---
type: how-to
title: Integration in Mobile-Apps
summary: Bette das Widget in eine iOS-, Android-, React-Native- oder Browser-Iframe-WebView ein und brücke das verifizierte Token zurück in deinen Code.
---

Caputchin läuft in einer nativen App über eine gehostete Embed-Seite. Du richtest eine WebView auf diese Seite, der Besucher löst die Aufgabe darin, und die Seite brückt das resultierende Token (und jeden Fehler) zurück in deinen nativen Code. Die Verifizierung selbst ist identisch mit dem Web; nur die Host-Hülle unterscheidet sich.

## 1. Die Embed-Seite öffnen

Richte eine WebView auf `https://caputchin.com/embed` mit mindestens einem Site-Key:

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

Lass die Spiel-Parameter weg für die schlichte Checkbox. Eine `games=a,b`-Liste wählt eines pro Session zufällig aus.

<Callout type="warn">
Hat der Site-Key das Spiel-Gate eingeschaltet (seine Einstellung **Ein Spiel zur Verifizierung verlangen**), kann die schlichte Checkbox nicht durchkommen: Das Embed muss auf einem gegateten Key ein Spiel ausführen. Übergib einen `game`- (oder `games`-)Parameter; das nackte Checkbox-Embed, ganz ohne Spiel-Parameter, wirft dort einen `gate-unavailable`-Fehler. Das ist Absicht, weil das Gate auf Caputchins Seite durchgesetzt wird. Sieh dir [das Spiel-Gate](/docs/site-keys/games) an.
</Callout>

### Query-Parameter

| Parameter | Pflicht | Wirkung |
|---|---|---|
| `sitekey` | ja | Dein Public Key (`cpt_pub_...`). Fehlt er, rendert eine Fehlerhülle ohne Widget. |
| `game` | nein | Eine einzelne Marketplace-Spiel-id (`owner/repo`, oder `owner/repo/leaf`). |
| `games` | nein | Eine kommagetrennte Liste; eines wird pro Session zufällig gewählt. |
| `game-src` | nein | URL deines eigenen gehosteten Spiel-Bundles, für ein selbst gehostetes Spiel. |
| `layout` | nein | `inline`, `modal`, `fullscreen` oder `auto`. Standard ist `inline` auf dem Embed. |
| `overlay-width` / `overlay-height` | nein | In `modal` / `fullscreen` den Spiel-Dialog dimensionieren: `full`, eine Pixelzahl oder `auto` (die bevorzugte Größe des Spiels selbst). Siehe [Größe und Layout](/docs/references/widget-sizing). |
| `locale` / `skin` / `config` | nein | An das Widget weitergereicht, um Sprache, Skin oder Konfiguration zu wählen. |
| `no-verify` | nein | Führt das Spiel ohne Verifizierungs-Gate aus (nur Spiel, kein Token). |
| `postMessageTarget` | nein | Nur für Browser-Iframe-Einbetter (siehe unten). In einer nativen WebView ignoriert. |

Lass alle drei von `game` / `games` / `game-src` weg für die schlichte Checkbox. Es gibt keinen `mode`-Parameter; das Widget steuert den Auslöser selbst.

## 2. Das Token in deinen Code brücken

Wenn der Besucher besteht, schiebt die Embed-Seite das Token durch den Kanal, der zu deinem Host passt. Registrier den passenden Handler.

### iOS (WKWebView, Swift)

Das Token kommt als roher String auf einem Message-Handler namens `caputchin` an:

```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)

Das Token kommt als roher String auf einem `@JavascriptInterface` namens `caputchin` an:

```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)

Das Embed postet einen JSON-String auf dem einen React-Native-Kanal. Parse ihn und verzweig auf `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)
    }
  }}
/>
```

### Browser-Iframe (postMessage)

Bettest du die Seite in ein Browser-`<iframe>` statt in eine native WebView ein, ist das Eltern-Relay **standardmäßig aus** und feuert nur, wenn du dich über einen exakten Ziel-Origin mit `?postMessageTarget=<origin>` einklinkst (zum Beispiel `postMessageTarget=https://app.example.com`). Ein Wildcard (`*`), ein Pfad oder alles, was nicht zu einem nackten Schema, Host und Port parst, wird abgelehnt, sodass das einmalige, site-gebundene Token nie an ein unverifiziertes Eltern-Fenster gesendet wird. Lausch im Eltern-Fenster und prüf `event.origin`, bevor du der Nachricht traust:

```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. Auf deinem Backend verifizieren

Das ist dasselbe wie im Web: POSTe das Token an `/siteverify` mit deinem Secret. Sieh dir [Serverseitige Integration](/docs/integration-guides/verify-on-your-backend) an.

## Fehler empfangen (optional)

Wann immer das Widget auf einen Fehler trifft, spiegelt die Embed-Seite ihn über einen parallelen Satz Kanäle: iOS-`caputchinError`-Message-Handler, Android-`caputchinError`-Interface (`onError(json)`), den React-Native-Kanal als `{ type: "caputchin-error", ... }` und dasselbe gegatete Iframe-Relay. Die Payload trägt `{ code, message, originalCode? }`. iOS und Android empfangen sie als JSON-String; React Native und das Iframe-Relay empfangen den typisierten Umschlag.

Das ist vollkommen optional. Eine App, die keinen Fehler-Handler registriert, empfängt einfach keine Fehler, und die Embed-Seite zeigt ohnehin eine Retry-UI in der WebView, egal was.

## Siehe auch

- [Serverseitige Integration](/docs/integration-guides/verify-on-your-backend) für die Token-Prüfung.
- [Clientseitige Integration](/docs/integration-guides/cdn) für das Web-Äquivalent.
