---
type: how-to
title: Intégration dans les apps mobiles
summary: Intègre le widget dans une WebView iOS, Android, React Native ou iframe de navigateur, et fais le pont du token vérifié vers ton code.
---

Caputchin tourne dans une app native via une page d'embed hébergée. Tu pointes une WebView vers cette page, le visiteur réussit l'épreuve à l'intérieur, et la page fait le pont du token résultant (et de toute erreur) vers ton code natif. La vérification elle-même est identique au web ; seul le shell hôte diffère.

## 1. Ouvre la page d'embed

Pointe une WebView vers `https://caputchin.com/embed` avec au moins une clé de site :

```
https://caputchin.com/embed?sitekey=cpt_pub_...&game=caputchin/games/leaf-memory
```

Omets les paramètres de jeu pour la simple case à cocher. Une liste `games=a,b` en choisit un au hasard par session.

<Callout type="warn">
Si la clé de site a le gate de jeu activé (son réglage **Exiger un jeu pour vérifier**), la simple case à cocher ne peut pas passer : l'embed doit exécuter un jeu sur une clé gatée. Passe un paramètre `game` (ou `games`) ; l'embed à case à cocher nue, sans paramètres de jeu, y lève une erreur `gate-unavailable`. C'est voulu, parce que le gate est appliqué du côté de Caputchin. Vois [le gate de jeu](/docs/site-keys/games).
</Callout>

### Paramètres de requête

| Paramètre | Requis | Effet |
|---|---|---|
| `sitekey` | oui | Ta clé publique (`cpt_pub_...`). Manquante, elle affiche un shell d'erreur sans widget. |
| `game` | non | Un id unique de jeu du marketplace (`owner/repo`, ou `owner/repo/leaf`). |
| `games` | non | Une liste séparée par des virgules ; un est choisi au hasard par session. |
| `game-src` | non | URL de ton propre bundle de jeu hébergé, pour un jeu auto-hébergé. |
| `layout` | non | `inline`, `modal`, `fullscreen` ou `auto`. Par défaut `inline` sur l'embed. |
| `overlay-width` / `overlay-height` | non | En `modal` / `fullscreen`, dimensionne la boîte de dialogue du jeu : `full`, un nombre de pixels, ou `auto` (la taille préférée du jeu lui-même). Voir [Taille et mise en page](/docs/references/widget-sizing). |
| `locale` / `skin` / `config` | non | Transmis au widget pour choisir une langue, un skin ou une configuration. |
| `no-verify` | non | Exécute le jeu sans gate de vérification (jeu seul, pas de token). |
| `postMessageTarget` | non | Intégrateurs en iframe de navigateur uniquement (voir ci-dessous). Ignoré dans une WebView native. |

Omets les trois `game` / `games` / `game-src` pour la simple case à cocher. Il n'y a pas de paramètre `mode` ; le widget pilote le déclencheur lui-même.

## 2. Fais le pont du token vers ton code

Quand le visiteur passe, la page d'embed pousse le token par le canal qui correspond à ton hôte. Enregistre le handler correspondant.

### iOS (WKWebView, Swift)

Le token arrive comme une chaîne brute sur un message handler nommé `caputchin` :

```swift
class TokenHandler: NSObject, WKScriptMessageHandler {
  func userContentController(_ controller: WKUserContentController,
                             didReceive message: WKScriptMessage) {
    guard let token = message.body as? String else { return }
    // send `token` to your backend
  }
}

let config = WKWebViewConfiguration()
config.userContentController.add(TokenHandler(), name: "caputchin")
let webView = WKWebView(frame: .zero, configuration: config)
webView.load(URLRequest(url: URL(string: "https://caputchin.com/embed?sitekey=cpt_pub_...&game=caputchin/games/leaf-memory")!))
```

### Android (WebView, Kotlin)

Le token arrive comme une chaîne brute sur un `@JavascriptInterface` nommé `caputchin` :

```kotlin
class TokenBridge {
  @JavascriptInterface
  fun onToken(token: String) {
    // send `token` to your backend
  }
}

webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(TokenBridge(), "caputchin")
webView.loadUrl("https://caputchin.com/embed?sitekey=cpt_pub_...&game=caputchin/games/leaf-memory")
```

### React Native (react-native-webview)

L'embed poste une chaîne JSON sur l'unique canal React Native. Parse-la et branche sur `type` :

```jsx
<WebView
  source={{ uri: "https://caputchin.com/embed?sitekey=cpt_pub_...&game=caputchin/games/leaf-memory" }}
  onMessage={(e) => {
    const msg = JSON.parse(e.nativeEvent.data);
    if (msg.type === "caputchin-token") {
      // send msg.token to your backend
    } else if (msg.type === "caputchin-error") {
      // msg.code, msg.message, msg.originalCode (optional)
    }
  }}
/>
```

### iframe de navigateur (postMessage)

Si tu intègres la page dans un `<iframe>` de navigateur plutôt que dans une WebView native, le relais vers le parent est **désactivé par défaut** et ne se déclenche que si tu actives explicitement une origine cible exacte via `?postMessageTarget=<origin>` (par exemple `postMessageTarget=https://app.example.com`). Un joker (`*`), un chemin, ou tout ce qui ne se parse pas en un simple schéma, hôte et port nu est rejeté, donc le token à usage unique et lié au site n'est jamais diffusé à un parent non vérifié. Écoute sur le parent et vérifie `event.origin` avant de faire confiance au message :

```js
window.addEventListener("message", (event) => {
  if (event.origin !== "https://embed-host.example.com") return;
  const msg = event.data;
  if (msg.type === "caputchin-token") {
    // msg.token
  } else if (msg.type === "caputchin-error") {
    // msg.code, msg.message
  }
});
```

## 3. Vérifie sur ton backend

C'est la même chose que le web : POSTe le token vers `/siteverify` avec ton secret. Vois [Intégration côté serveur](/docs/integration-guides/verify-on-your-backend).

## Recevoir les erreurs (optionnel)

Chaque fois que le widget rencontre une erreur, la page d'embed la reflète à travers un jeu de canaux parallèles : le message handler iOS `caputchinError`, l'interface Android `caputchinError` (`onError(json)`), le canal React Native comme `{ type: "caputchin-error", ... }`, et le même relais iframe gaté. La charge porte `{ code, message, originalCode? }`. iOS et Android la reçoivent comme une chaîne JSON ; React Native et le relais iframe reçoivent l'enveloppe typée.

C'est entièrement optionnel. Une app qui n'enregistre aucun handler d'erreur ne reçoit simplement pas les erreurs, et la page d'embed montre de toute façon une UI de réessai dans la WebView.

## Voir aussi

- [Intégration côté serveur](/docs/integration-guides/verify-on-your-backend) pour la vérification du token.
- [Intégration côté client](/docs/integration-guides/cdn) pour l'équivalent web.
