Caputchin
Руководства по интеграции

Интеграция в мобильных приложениях

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

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

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

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

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

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

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

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

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

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

iOS (WKWebView, Swift)

Токен приходит сырой строкой на обработчик сообщений с именем caputchin:

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:

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:

<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, прежде чем доверять сообщению:

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 со своим секретом. Смотри Серверную интеграцию.

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

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

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

См. также

На этой странице