---
type: how-to
title: Интеграция в мобильных приложениях
summary: Встрой виджет в WebView под iOS, Android, React Native или браузерный iframe и пробрось проверенный токен обратно в свой код.
---

Caputchin работает внутри нативного приложения через размещённую страницу встраивания. Ты наводишь WebView на эту страницу, посетитель проходит испытание внутри неё, и страница пробрасывает получившийся токен (и любую ошибку) обратно в твой нативный код. Сама проверка идентична веб-версии; различается только хост-оболочка.

## 1. Открой страницу встраивания

Наведи WebView на `https://caputchin.com/embed` хотя бы с ключом сайта:

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

Опусти параметры игры для простой галочки. Список `games=a,b` выбирает одну случайно на сессию.

<Callout type="warn">
Если у ключа сайта включены игровые ворота (его настройка **Требовать игру для проверки**), простая галочка не проходит: на ключе с воротами встраивание обязано запустить игру. Передай параметр `game` (или `games`); голое встраивание с галочкой, без параметров игры, поднимает там ошибку `gate-unavailable`. Это сделано намеренно, потому что ворота соблюдаются на стороне Caputchin. Смотри [игровые ворота](/docs/site-keys/games).
</Callout>

### Параметры запроса

| Параметр | Обязателен | Эффект |
|---|---|---|
| `sitekey` | да | Твой публичный ключ (`cpt_pub_...`). Без него рендерится оболочка с ошибкой без виджета. |
| `game` | нет | Один id игры из маркетплейса (`owner/repo` или `owner/repo/leaf`). |
| `games` | нет | Список через запятую; одна выбирается случайно на сессию. |
| `game-src` | нет | URL твоей собственной размещённой сборки игры, для самостоятельно размещённой игры. |
| `layout` | нет | `inline`, `modal`, `fullscreen` или `auto`. По умолчанию `inline` на встраивании. |
| `overlay-width` / `overlay-height` | нет | В `modal` / `fullscreen` задаёт размер диалога игры: `full`, число пикселей или `auto` (собственный предпочитаемый размер игры). См. [Размер и макет](/docs/references/widget-sizing). |
| `locale` / `skin` / `config` | нет | Пробрасываются в виджет для выбора языка, скина или конфигурации. |
| `no-verify` | нет | Запускает игру без проверочных ворот (только игра, без токена). |
| `postMessageTarget` | нет | Только для встраивающих в браузерный iframe (см. ниже). Игнорируется в нативном WebView. |

Опусти все три из `game` / `games` / `game-src` для простой галочки. Параметра `mode` нет; виджет сам управляет триггером.

## 2. Пробрось токен в свой код

Когда посетитель проходит, страница встраивания проталкивает токен через канал, подходящий твоему хосту. Зарегистрируй соответствующий обработчик.

### iOS (WKWebView, Swift)

Токен приходит сырой строкой на обработчик сообщений с именем `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)

Токен приходит сырой строкой на `@JavascriptInterface` с именем `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)

Встраивание постит JSON-строку в единый канал React Native. Распарси её и ветвись по `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 (postMessage)

Если ты встраиваешь страницу в браузерный `<iframe>`, а не в нативный WebView, ретрансляция к родителю **по умолчанию выключена** и срабатывает только когда ты явно включаешь её с точным целевым источником через `?postMessageTarget=<origin>` (например `postMessageTarget=https://app.example.com`). Подстановочный знак (`*`), путь или что угодно, что не парсится в голую схему, хост и порт, отклоняется, так что одноразовый, привязанный к сайту токен никогда не вещается непроверенному родителю. Слушай на родителе и проверяй `event.origin`, прежде чем доверять сообщению:

```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. Проверь на своём бэкенде

Это то же, что и в вебе: отправь POST с токеном на `/siteverify` со своим секретом. Смотри [Серверную интеграцию](/docs/integration-guides/verify-on-your-backend).

## Приём ошибок (опционально)

Всякий раз, когда виджет наталкивается на ошибку, страница встраивания зеркалит её через параллельный набор каналов: обработчик сообщений `caputchinError` под iOS, интерфейс `caputchinError` под Android (`onError(json)`), канал React Native как `{ type: "caputchin-error", ... }` и та же огороженная ретрансляция iframe. Нагрузка несёт `{ code, message, originalCode? }`. iOS и Android получают её как JSON-строку; React Native и ретрансляция iframe получают типизированный конверт.

Это полностью опционально. Приложение, не регистрирующее обработчик ошибок, просто не получает ошибки, а страница встраивания всё равно показывает UI повтора внутри WebView в любом случае.

## См. также

- [Серверная интеграция](/docs/integration-guides/verify-on-your-backend) для проверки токена.
- [Клиентская интеграция](/docs/integration-guides/cdn) для веб-эквивалента.
