/
v3.0.11Get access
Swarm SDK

reCAPTCHA Integration

This guide explains how reCAPTCHA validation (v2 and v3) works with the Swarm SDK.
Download page as PDF

Overview

The Swarm SDK handles all human verification internally. Once the session is established, the SDK automatically intercepts protected requests, performs verification, and retries the original request on success.
reCAPTCHA v3
Silent background verification. The SDK calls window.grecaptcha.execute() automatically.
reCAPTCHA v2
Challenge widget verification. The SDK renders the widget into a #g-recaptcha container you provide in the DOM.

Setup - useInitSocket

Initialize the SDK at your application root. Required params are marked; all others are optional.
.ts
import {
  useInitSocket
} from '@softconstruct/betchain-core-client/hooks';

useInitSocket({
  /* -- required ----------------------------------------------------- */
  siteId: 100,
  language: 'en',
  socketUrl: 'wss://your-socket-url',
  onSessionSuccess: (data) => console.log('Session ready', data),
  onSessionError: ({
    message
  }) => console.error('Session error', message),

  /* -- optional ----------------------------------------------------- */
  source: 1,
  afec: userHash,
  releaseDate: new Date(),
  reCaptchaPlatform: 'android', // native apps only, see the native guide below
  onReconnectSuccess: () => console.log('Reconnected'),
  onReconnectError: ({
    message
  }) => console.error('Reconnect failed', message),
  xPoint: {
    clientKey: 'your-xpoint-client-key',
    enableXPoint: true,
    onResolve: ({
      value
    }) => {
      // value is '' when the user is allowed, or the X_POINT sentinel when blocked.
    },
  },
});

Session Initialization & reCAPTCHA Configuration

After connecting, the SDK receives verification configuration from the server via the session handshake. This data is also forwarded to your onSessionSuccess callback.
.ts
onSessionSuccess: (data) => {
  recaptcha_enabled: true,
  recaptcha_version: 3,
  recaptcha_actions: ['reset_password', 'register_user', ...],
  site_key: '6LcRh3EqAAAAADryiHcUU4h5-iKmCcI5wPqCe7Iu',
};
The SDK stores this data internally and uses it to decide whether verification is required before each protected request.
FieldExample valueDescription
recaptcha_enabledtrueWhether reCAPTCHA validation is active on the server.
recaptcha_version3Which reCAPTCHA version the server expects (2 or 3).
recaptcha_actions['reset_password', ...]List of command names that require reCAPTCHA validation.
site_key"6LcRh3EqAAAAADryiHcUU4h5-iKmCcI5wPqCe7Iu"The Google reCAPTCHA site key used internally by the SDK to generate tokens.

reCAPTCHA v3 Flow

Under the hood

The SDK initializes reCAPTCHA v3 by dynamically injecting the Google script into the page using the site_key received from the session:
.sh
https://www.recaptcha.net/recaptcha/api.js?render=${siteKey}
Once the script is loaded, the SDK calls window.grecaptcha.execute(siteKey, { action }); via an internal helper to obtain a token. If the script fails to load or window.grecaptcha is unavailable, the helper throws recaptcha_v3_initialization_failed.

How it works

  1. A protected request is made, for example forgot password.
  2. The SDK checks recaptcha_enabled and whether the command requires verification according to recaptcha_actions.
  3. The SDK silently calls window.grecaptcha.execute(siteKey, { action }) to obtain a token.
  4. The SDK sends a v3 validation request to the server with the token.
  5. Token valid: the original request is automatically retried.
  6. Token invalid: the listener receives an error payload.

Making a protected request

Consumer code does not need to provide a reCAPTCHA token manually. The SDK intercepts the request, performs v3 verification transparently, and then executes the original request if verification passes.
.ts
import {
  forgotPassword
} from '@softconstruct/betchain-core-client/swarm';
import {
  useSwarmGetOnce
} from '@softconstruct/betchain-core-client/hooks';

const {
  makeRequest
} = useSwarmGetOnce(forgotPassword, {
  shouldWait: true
});

await makeRequest({
  email: 'new_email',
});

reCAPTCHA v2 Flow

reCAPTCHA v2 can be triggered in two ways. In both cases the SDK renders the challenge widget and, after the user completes it, automatically retries the pending request. No form re-submission is needed.

Under the hood

The reCAPTCHA v2 script must be loaded on the page so that window.grecaptcha is available.
A container element with id="g-recaptcha" must exist in the DOM. The SDK looks up this element by ID and renders the widget inside it. If the element is not found, the SDK returns g_recaptcha_element_not_found.
.html
<div id="g-recaptcha" data-testid="g-recaptcha" data-verifycallbackname="verifyCallback"></div>

1. Pre-request v2 check

  1. If the session recaptcha_version is 2 and the command is in recaptcha_actions, the SDK triggers v2 verification before the request is sent.
  2. The SDK calls window.grecaptcha.render() into the #g-recaptcha container.
  3. The user completes the widget challenge.
  4. The SDK automatically calls the v2 validation endpoint with the widget token.
  5. On success, the SDK retries the original request automatically.

2. Server-initiated v2 (code 27)

  1. The server may return response code 27 after a v3 validation attempt, indicating v2 verification is required instead.
  2. The SDK renders the v2 widget into the #g-recaptcha container.
  3. The listener receives { hasError: true, error: 'reCaptcha v2 validation required' } to signal the error state to your UI.
  4. The user completes the widget challenge.
  5. The SDK automatically calls the v2 validation endpoint.
  6. On success, the SDK retries the pending request automatically.

Error States

ScenarioListener payload
v3 token invalid (server rejected){ hasError: true, error: 'recaptcha_v3_verification_failed' }
v3 script not loaded / window.grecaptcha unavailable{ hasError: true, error: 'recaptcha_v3_initialization_failed' }
Server requires v2 (code 27){ hasError: true, error: 'recaptcha_v2_validation required' }
site_key missing from session (reCAPTCHA){ hasError: true, error: 'missing_recaptcha_v2_siteKey' } or 'missing_recaptcha_v3_siteKey'
#g-recaptcha element not found in the DOM (v2){ hasError: true, error: 'g_recaptcha_element_not_found' }
Native apps

Native app captcha (reCAPTCHA Enterprise)

The reCAPTCHA widget described above is a browser component, and a native Android or iOS app has no page to render it into. Google's only supported path for native apps is the reCAPTCHA Enterprise mobile SDK, whose tokens are verified through the Enterprise assessments API. Swarm now supports that flow end to end.
Invisible
There is no checkbox and no image challenge on mobile. The Enterprise SDK runs silently and returns a risk score.
Your app drives it
Once reCaptchaPlatform is set, the BetChain Core SDK steps out of the way. Your app obtains the token and submits it for validation.

The flow, end to end

  1. Your app opens a session and declares which platform it is, using reCaptchaPlatform.
  2. Swarm answers with the reCAPTCHA Enterprise site_key for that platform. The app never hardcodes a key.
  3. Your app initializes the Enterprise SDK with that key, once.
  4. Immediately before each protected action, your app calls the Enterprise SDK's execute(action) and receives a short-lived token.
  5. Your app validates the token with Swarm, then sends the actual protected command.

Before you start: what to send us

We create the Enterprise keys for your app, so we need the identifiers below. In return you get confirmation that native captcha is enabled for your partner ID and platform.
What we needPlatformWhere to find it
Package nameAndroidThe applicationId in your Gradle config, for example com.partner.app
SHA-256 signing fingerprintAndroidkeytool -list -v -keystore <release-key>.jks — the SHA-256 line of your production release key
Bundle IDiOSThe bundle identifier in Xcode, for example com.partner.app
Distributed outside Google Play?AndroidYes or no. APK-direct and third-party stores need a separate key
Apple team ID, key ID and .p8iOS (optional)Improves score accuracy. Can be added later
You never receive a key to hardcode. The site key is delivered to your app at runtime, in the session response.

Step 1 — Declare your platform when opening the session

Pass reCaptchaPlatform to useInitSocket with the value "android" or "ios". The SDK carries it into the session handshake as the captcha_platform parameter of request_session.
.ts
import { useInitSocket } from '@softconstruct/betchain-core-client/hooks';

useInitSocket({
  siteId: 123,
  language: 'en',
  socketUrl: 'wss://your-socket-url',

  // 'android' or 'ios'. Send the OS the app runs on, not the framework.
  reCaptchaPlatform: 'android',

  onSessionSuccess: (data) => console.log('Session ready', data),
  onSessionError: ({ message }) => console.error('Session error', message),
});
  • Any value other than android or ios is rejected. The SDK fails fast, calling onSessionError with incorrect_recaptcha_platform and never opening the session; the same value sent directly is rejected by Swarm with code 2.
  • Omitting the parameter keeps today's behaviour.
  • Setting it also switches off the SDK's own reCAPTCHA, Turnstile and XPoint handling, so your app owns verification from here on.
  • React Native and Flutter: send the operating system the app is actually running on, not the framework. Use Platform.OS in React Native, and Platform.isAndroid / Platform.isIOS in Flutter.

Step 2 — Read the captcha config from the response

The SDK hands the session config to your onSessionSuccess callback in camelCase. The raw request_session response carries the same values in snake_case.
.ts
onSessionSuccess: (data) => {
  sid: '...',
  recaptchaEnabled: true,
  recaptchaEnterprise: true,
  recaptchaActions: ['login', 'register_user', 'do_bet', 'deposit'],
};
onSessionSuccessSession responseMeaning
recaptchaEnterpriserecaptcha_enterprisetrue means native captcha is on for you. false, or absent, means it is not enabled for this partner and platform — do not initialize the Enterprise SDK.
recaptchaActionsrecaptcha_actionsThe actions your partner actually protects. Only these need a token.
recaptchaEnabledrecaptcha_enabledfalse means captcha is switched off entirely for this partner.
—site_keyThe key to initialize the reCAPTCHA Enterprise SDK with. Read it at runtime on every session; never hardcode or persist it.

Step 3 — Initialize the Enterprise SDK once

PlatformDependencyMinimum
Androidcom.google.android.recaptcha:recaptcha:18.9.x (Google Maven)API level 24
iOSRecaptchaEnterprise via Swift Package ManageriOS 15
Flutterrecaptcha_enterprise_flutterAs per the platform above
React NativeNo official Google SDK for React Native. Wrap the native Android and iOS SDKs above in a thin native module.As per the platform above

Fetching the client

.kt
// Once, at app start. Keep the client for the whole app lifetime.
val client = Recaptcha
  .fetchClient(application, siteKeyFromSwarm)
  .getOrThrow()
Signatures vary between SDK versions. Check the exact ones for your version in Google's mobile reference pages: instrument-android-apps, instrument-ios-apps, create-key-mobile and create-assessment-mobile under https://docs.cloud.google.com/recaptcha/docs/.
  • Fetch the client once and reuse it. Do not create a new client per action.
  • Android requires the android.permission.INTERNET permission.
  • CocoaPods support for the iOS SDK ends after the 18.9.x line. Use Swift Package Manager for new integrations.

Step 4 — Get a token immediately before each action

.kt
val token = client
  .execute(RecaptchaAction.custom("do_bet"))
  .getOrThrow()

Token rules

  • A token expires after two minutes and is single use. Never cache or reuse one.
  • The action string you pass to execute must be exactly the action you then send to Swarm. A mismatch is treated as an attack and rejected.
  • Action names are case-insensitive and may contain only letters, digits, / and _.
  • One token per protected action. Do not fetch a token at screen load and use it later.

Step 5 — Validate the token, then send the command

Pass the token and its action to the validateRecaptchaV3 method — its page carries the full parameters, the response shape and a Try it now console. On success, send the protected command immediately.
.json
{
  command: 'validate_recaptcha',
  params: {
    action: 'do_bet',
    g_recaptcha_response: '<token from the mobile SDK>'
  }
}
  • Both the token and the action are required.
  • Do not send m_hash together with the token. Exactly one of the two is allowed, otherwise the call fails with code 2.
  • No session id is needed. The session is managed internally.
  • Some commands also accept the token inline, for example register_user inside user_info and login as g_recaptcha_response. Validate-then-command works for every protected command, so that is the pattern we recommend everywhere.

Do and do not

Do
  • Read site_key from the session response on every session.
  • Call execute immediately before the protected command.
  • Use the same action string when you execute and when you validate.
  • Handle SDK failures gracefully — no network, Play Services missing. Offer a retry rather than silently skipping the action.
Do not
  • Reuse tokens, cache them, or fetch them in advance.
  • Hardcode or persist the site key.
  • Use a WebView or the web reCAPTCHA widget in a native app.
  • Ship a key registered against a debug signing fingerprint to production.

Existing apps using m_hash

m_hash continues to work unchanged, so no app breaks on release day. It is a static shared-secret bypass that carries no device signals, and it is planned for retirement per partner once the Enterprise SDK integration is live.