### Install reCAPTCHA Transaction Defense Skill with Context7 CLI Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/skills/README.md Use the Context7 skills CLI to install skills. This command installs the specific recaptcha-transaction-defense-integrator skill. ```sh # Interactively browse and install skills. npx ctx7 skills install /GoogleCloudPlatform/recaptcha-enterprise-mobile-sdk # Install a specific skill (e.g., vertex-ai-api-dev). npx ctx7 skills install /GoogleCloudPlatform/recaptcha-enterprise-mobile-sdk recaptcha-transaction-defense-integrator ``` -------------------------------- ### Run the Demo Server Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/server/README.md After configuring your project credentials, execute this command to start the local demo server. ```bash python3 main.py ``` -------------------------------- ### Install Server Dependencies Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/server/README.md Run this command to install all necessary dependencies for the local demo server. ```bash pip3 install -r requirements.txt ``` -------------------------------- ### Install reCAPTCHA Transaction Defense Skill with Vercel CLI Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/skills/README.md Use the Vercel skills CLI to interactively browse and install skills. This command installs the specific recaptcha-transaction-defense-integrator skill globally. ```sh # Interactively browse and install skills. npx skills add GoogleCloudPlatform/recaptcha-enterprise-mobile-sdk --list # Install a specific skill (e.g., gemini-api-dev). npx skills add GoogleCloudPlatform/recaptcha-enterprise-mobile-sdk --skill recaptcha-transaction-defense-integrator --global ``` -------------------------------- ### Android: Execute reCAPTCHA for Login Action Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Use `recaptchaClient.execute` on the IO dispatcher immediately before sending the token to your backend. Tokens are single-use and expire quickly. This example shows ViewModel integration for a login action. ```kotlin import com.google.android.recaptcha.RecaptchaAction import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class LoginViewModel : ViewModel() { fun onLoginClicked(username: String, password: String) { viewModelScope.launch(Dispatchers.IO) { RecaptchaRepository.retrieveToken(RecaptchaAction.LOGIN) .onSuccess { token -> // Send token + credentials to your backend for assessment val response = backendRepository.login(username, password, token) if (response["shouldBlock"] as Boolean) { _errorMessage.postValue("Attestation failed!") } else { _loginState.postValue(true) } } .onFailure { error -> _errorMessage.postValue("reCAPTCHA failed: ${error.localizedMessage}") } } } } // Custom action (any alphanumeric string, slashes, underscores) val checkoutToken = RecaptchaRepository.retrieveToken(RecaptchaAction(customAction = "checkout")) ``` -------------------------------- ### iOS: Initialize reCAPTCHA Client (Callback) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Use `Recaptcha.fetchClient(withSiteKey:completion:)` for iOS < 13 or when not using async/await. Store the returned client for later `execute` calls. Ensure the site key is present in your `Info.plist`. ```swift import RecaptchaEnterprise class RecaptchaRepository { static private var recaptchaClient: RecaptchaClient? static func initRecaptcha() { let siteKey = Bundle.main.object(forInfoDictionaryKey: "SITE_KEY") as? String ?? "" Recaptcha.fetchClient(withSiteKey: siteKey) { client, error in guard let client = client else { print("RecaptchaClient init error: \(String(describing: error))") return } self.recaptchaClient = client } } static func getToken(action: RecaptchaAction) async -> Result { do { guard let client = recaptchaClient else { throw NSError(domain: "RecaptchaNotInitialized", code: -1) } let token = try await client.execute(withAction: action) return .success(token) } catch { return .failure(error) } } } ``` -------------------------------- ### iOS - Initialize Client (async/await) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt For iOS 13 and later, the `async` variant of `Recaptcha.fetchClient` is recommended for seamless integration with Swift Concurrency. Errors are handled as `RecaptchaError` objects, which contain an `errorMessage` property. ```APIDOC ## iOS — `Recaptcha.fetchClient` (Initialize the Client — async/await) For iOS 13+ the `async` variant of `Recaptcha.fetchClient` is preferred. It integrates cleanly with Swift Concurrency. Errors are typed as `RecaptchaError` with an `errorMessage` property. ```swift import RecaptchaEnterprise @available(iOS 13.0, *) func initRecaptchaAsync(siteKey: String) async { do { let client = try await Recaptcha.fetchClient(withSiteKey: siteKey) // Store client for later execute calls self.recaptchaClient = client print("reCAPTCHA client ready") } catch let error as RecaptchaError { print("Init failed: \(error.errorMessage)") } catch { print("Init failed: \(error.localizedDescription)") } } // Called from a Task in viewDidLoad: override func viewDidLoad() { super.viewDidLoad() Task { await initRecaptchaAsync( siteKey: Bundle.main.object(forInfoDictionaryKey: "SITE_KEY") as? String ?? "" ) } } ``` ``` -------------------------------- ### iOS - Initialize Client (Callback) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt The `Recaptcha.fetchClient(withSiteKey:completion:)` method initializes the reCAPTCHA client for iOS versions below 13 or when not using async/await. The completion handler receives an optional `RecaptchaClient` and an optional `Error`. The client should be stored for subsequent `execute` calls. ```APIDOC ## iOS — `Recaptcha.fetchClient` (Initialize the Client — Callback) `Recaptcha.fetchClient(withSiteKey:completion:)` is the callback-based initializer for iOS < 13 or when `async/await` is not used. The completion block receives an optional `RecaptchaClient` and an optional `Error`. Store the client for later `execute` calls. ```swift import RecaptchaEnterprise class RecaptchaRepository { static private var recaptchaClient: RecaptchaClient? static func initRecaptcha() { let siteKey = Bundle.main.object(forInfoDictionaryKey: "SITE_KEY") as? String ?? "" Recaptcha.fetchClient(withSiteKey: siteKey) { client, error in guard let client = client else { print("RecaptchaClient init error: \(String(describing: error))") return } self.recaptchaClient = client } } static func getToken(action: RecaptchaAction) async -> Result { do { guard let client = recaptchaClient else { throw NSError(domain: "RecaptchaNotInitialized", code: -1) } let token = try await client.execute(withAction: action) return .success(token) } catch { return .failure(error) } } } ``` ``` -------------------------------- ### Configure Development Site Keys for iOS Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/ios/basic/README.md Add your development site key and base URL to the `DebugSettings.xcconfig` file. This configuration is specifically for the `dev` flavor and should not be exposed publicly. ```text # This site key is used for development only and should never be exposed to # customers, copybara is configured to ignore this file and build.gradle # to only create the dev flavor if this file exist. WEB_SITE_KEY = "YOUR_DEV_SITE_KEY" WEB_BASE_URL = "http://YOURDOMAIN" ``` -------------------------------- ### Initialize Android RecaptchaClient Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Initialize the RecaptchaClient using Recaptcha.fetchClient(application, siteKey). Call once at app startup on an IO coroutine. Handles initialization failures. ```kotlin // RecaptchaRepository.kt import android.app.Application import com.google.android.recaptcha.Recaptcha import com.google.android.recaptcha.RecaptchaAction import com.google.android.recaptcha.RecaptchaClient import com.google.android.recaptcha.RecaptchaException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch object RecaptchaRepository { private lateinit var recaptchaClient: RecaptchaClient private const val SITE_KEY = "YOUR_SITE_KEY" // Call once in Application.onCreate() fun initializeClient(context: Application) { CoroutineScope(Dispatchers.IO).launch { try { recaptchaClient = Recaptcha.fetchClient(context, SITE_KEY) } catch (e: RecaptchaException) { // Log and handle: e.errorMessage contains the reason println("Init failed: ${e.errorMessage}") } } } suspend fun retrieveToken(action: RecaptchaAction): Result { return recaptchaClient.execute(action) } } // Application.kt class MyApplication : Application() { override fun onCreate() { super.onCreate() RecaptchaRepository.initializeClient(this) } } ``` -------------------------------- ### Configure Development Site Key Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/android/basic/README.md Create this file to configure development-only site keys. It should be placed in the `config` folder. This file is ignored by copybara and used to create a dev flavor. ```properties # This site key is used for development only and should never be exposed to # customers, copybara is configured to ignore this file and build.gradle # to only create the dev flavor if this file exist. SITE_KEY = "YOUR_DEV_SITE_KEY" ``` -------------------------------- ### iOS Visual Challenge via WebView (`RecaptchaVisual`) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Presents a visual reCAPTCHA challenge (like a checkbox) using a modal WebView. Instantiate `RecaptchaVisual` with necessary parameters and call `runCaptcha` to display the challenge. The completion block returns the token or an error. ```APIDOC ## iOS — Visual Challenge via WebView (`RecaptchaVisual`) For visual/checkbox-style challenges, instantiate `RecaptchaVisual` with a `UIViewController`, site key, and base URL. Call `runCaptcha` to present a modal WebView containing the reCAPTCHA challenge. The completion block receives the token or an error. ```swift import RecaptchaEnterprise class CheckoutViewController: UIViewController { func presentVisualChallenge() { guard let baseUrl = URL(string: "https://your-domain.com") else { return } let recaptchaVisual = RecaptchaVisual( viewController: self, siteKey: "YOUR_SITE_KEY", baseUrl: baseUrl, lang: "en" ) recaptchaVisual.runCaptcha { token, error in if let token = token { print("Visual challenge token: \(token)") // Send token to backend for assessment } else if let error = error { print("Visual challenge error: \(error.localizedDescription)") } } } } ``` ``` -------------------------------- ### JavaScript for reCAPTCHA Initialization and Callbacks Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/android/visual/app/src/main/assets/rce.html Handles the initialization of the reCAPTCHA widget, including site key configuration and callback functions for verification, errors, and expiration. ```javascript let isReadyTimer; const onVerify = (token) => { __JS_OBJECT_NAME__.onVerify(token); }; const onError = (error) => { __JS_OBJECT_NAME__.onError(error); }; const onExpire = () => { __JS_OBJECT_NAME__.onExpire(); }; var onLoad = () => { document.getElementById("spinner").style.display='none'; const recaptchaParams = { sitekey: "__SITE_KEY__", callback: onVerify, "error-callback": onError, "expired-callback": onExpire, }; window.grecaptcha.render("recaptcha-container", recaptchaParams); __JS_OBJECT_NAME__.onLoad(); }; ``` -------------------------------- ### iOS: Initialize reCAPTCHA Client (async/await) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt For iOS 13+, the `async` variant `Recaptcha.fetchClient` is preferred for clean integration with Swift Concurrency. Errors are typed as `RecaptchaError`. This function should be called within a `Task`. ```swift import RecaptchaEnterprise @available(iOS 13.0, *) func initRecaptchaAsync(siteKey: String) async { do { let client = try await Recaptcha.fetchClient(withSiteKey: siteKey) // Store client for later execute calls self.recaptchaClient = client print("reCAPTCHA client ready") } catch let error as RecaptchaError { print("Init failed: \(error.errorMessage)") } catch { print("Init failed: \(error.localizedDescription)") } } // Called from a Task in viewDidLoad: override func viewDidLoad() { super.viewDidLoad() Task { await initRecaptchaAsync( siteKey: Bundle.main.object(forInfoDictionaryKey: "SITE_KEY") as? String ?? "" ) } } ``` -------------------------------- ### iOS `RecaptchaClient.execute` (Generate a Token — async/await) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Generates a reCAPTCHA token for a given action using async/await. Supports built-in actions like login and signup, as well as custom actions. Tokens are single-use and should be generated per user action. ```APIDOC ## iOS `RecaptchaClient.execute` (Generate a Token — async/await) `client.execute(withAction:)` returns a `String` token on success or throws a `RecaptchaError`. Use `RecaptchaAction.login`, `RecaptchaAction.signup`, or `RecaptchaAction(customAction:)` for custom action names. Tokens are single-use; generate a fresh token per user action. ```swift import RecaptchaEnterprise @available(iOS 13.0, *) func performLogin() async { guard let client = recaptchaClient else { print("Client not initialized") return } do { // Built-in actions: .login, .signup let token = try await client.execute(withAction: RecaptchaAction.login) print("Token received: \(token)") // Forward token to backend let result = await LoginViewModel().sendToBackend(token: token) } catch let error as RecaptchaError { print("Execute failed: \(error.errorMessage)") } catch { print("Execute failed: \(error.localizedDescription)") } } // Custom action: let checkoutToken = try await client.execute(withAction: RecaptchaAction(customAction: "checkout")) ``` ``` -------------------------------- ### Create Transaction Defense Assessment (Back-Office) Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/skills/recaptcha-transaction-defense-integrator/references/recaptcha-api.md Use this JSON payload to create an assessment for a transaction, including enriched data for back-office analysis. Ensure 'YOUR_SITE_KEY' and 'TRANSACTION_ID' are replaced with actual values. ```json { "event": { "siteKey": "YOUR_SITE_KEY", "expectedAction": "checkout", "transactionData": { "transactionId": "TRANSACTION_ID", "paymentMethod": "credit_card", "currencyCode": "USD", "value": 5.00, "cardLastFour": "4242", "billingAddress": { "postalCode": "94043", "regionCode": "US" }, "user": { "email": "user@example.com" } } } } ``` -------------------------------- ### Add iOS SDK via Swift Package Manager Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Declare the RecaptchaEnterprise package in your Package.swift or add the GitHub URL in Xcode's package manager. Requires iOS 15+. ```swift // Package.swift let package = Package( name: "MyApp", platforms: [.iOS(.v15)], dependencies: [ .package( url: "https://github.com/GoogleCloudPlatform/recaptcha-enterprise-mobile-sdk.git", from: "18.9.0" ) ], targets: [ .target(name: "MyApp", dependencies: ["RecaptchaEnterprise"]) ] ) ``` -------------------------------- ### reCAPTCHA Enterprise JavaScript Initialization Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/ios/visual/exampleApp/rce.html Configure and render the reCAPTCHA widget within a web view. Ensure the site key is correctly replaced and callbacks are defined for verification, errors, and expiration. ```javascript const onVerify = (token) => { window.webkit.messageHandlers.onVerify.postMessage({ "token": token }); }; const onError = (error) => { window.webkit.messageHandlers.onError.postMessage({ "error": error }); }; const onExpire = () => { window.webkit.messageHandlers.onExpire.postMessage({ }); }; var onLoad = () => { document.getElementById("spinner").style.display='none'; const recaptchaParams = { 'sitekey': "__SITE_KEY__", 'callback': onVerify, 'error-callback': onError, 'expired-callback': onExpire, }; window.grecaptcha.render("recaptcha-container", recaptchaParams); window.webkit.messageHandlers.onLoad.postMessage({ }); }; ``` -------------------------------- ### iOS `RecaptchaClient.execute` (Generate a Token — Callback) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Generates a reCAPTCHA token using a callback-based approach, suitable for iOS versions prior to 13. The completion block provides an optional token and an optional error. ```APIDOC ## iOS `RecaptchaClient.execute` (Generate a Token — Callback) The callback variant supports iOS < 13. The completion block receives an optional token string and an optional error. ```swift import RecaptchaEnterprise func callExecute(client: RecaptchaClient) { client.execute(withAction: RecaptchaAction.login) { token, error in if let token = token { print("Token: \(token)") // Send token to backend } else { print("Execute failed: \(String(describing: error))") } } } // With timeout (seconds): client.execute(withAction: RecaptchaAction.login, withTimeout: 10.0) { token, error in guard let token = token else { print("Timed out or failed: \(String(describing: error))") return } print("Token: \(token)") } ``` ``` -------------------------------- ### Handle reCAPTCHA Execution Click (JavaScript) Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/ios/webview/exampleApp/rce.html This function is triggered by a user interaction (e.g., a button click) to initiate the reCAPTCHA execution. It calls the `onExecute` function and updates the UI with the resulting token or error. ```javascript const executeClick = async () => { try { const result =await onExecute("login") document.querySelector("#result").textContent = "TOKEN: " + result } catch(err) { document.querySelector("#result").textContent = "ERROR: " + err } } ``` -------------------------------- ### Add iOS SDK via CocoaPods Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Add the RecaptchaEnterprise pod to your Podfile. The final supported release is 18.9.x. ```ruby # Podfile (CocoaPods — final supported release is 18.9.x) pod 'RecaptchaEnterprise', '18.9.0' ``` -------------------------------- ### Present Visual reCAPTCHA Challenge (iOS) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Use `RecaptchaVisual` to present a modal WebView for visual or checkbox-style challenges. Requires a `UIViewController`, site key, and base URL. The completion block returns the token or an error. ```swift import RecaptchaEnterprise class CheckoutViewController: UIViewController { func presentVisualChallenge() { guard let baseUrl = URL(string: "https://your-domain.com") else { return } let recaptchaVisual = RecaptchaVisual( viewController: self, siteKey: "YOUR_SITE_KEY", baseUrl: baseUrl, lang: "en" ) recaptchaVisual.runCaptcha { token, error in if let token = token { print("Visual challenge token: \(token)") // Send token to backend for assessment } else if let error = error { print("Visual challenge error: \(error.localizedDescription)") } } } } ``` -------------------------------- ### Generate reCAPTCHA Token with Callback (iOS) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt For iOS versions below 13, use the callback variant of `client.execute(withAction:)`. The completion block provides an optional token and error. A timeout can also be specified. ```swift import RecaptchaEnterprise func callExecute(client: RecaptchaClient) { client.execute(withAction: RecaptchaAction.login) { token, error in if let token = token { print("Token: \(token)") // Send token to backend } else { print("Execute failed: \(String(describing: error))") } } } // With timeout (seconds): client.execute(withAction: RecaptchaAction.login, withTimeout: 10.0) { token, error in guard let token = token else { print("Timed out or failed: \(String(describing: error))") return } print("Token: \(token)") } ``` -------------------------------- ### Generate reCAPTCHA Token with async/await (iOS) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Use `client.execute(withAction:)` for iOS 13.0+ to generate a token asynchronously. Supports built-in actions like `.login` and `.signup`, or custom actions. Tokens are single-use. ```swift import RecaptchaEnterprise @available(iOS 13.0, *) func performLogin() async { guard let client = recaptchaClient else { print("Client not initialized") return } do { // Built-in actions: .login, .signup let token = try await client.execute(withAction: RecaptchaAction.login) print("Token received: \(token)") // Forward token to backend let result = await LoginViewModel().sendToBackend(token: token) } catch let error as RecaptchaError { print("Execute failed: \(error.errorMessage)") } catch { print("Execute failed: \(error.localizedDescription)") } } // Custom action: let checkoutToken = try await client.execute(withAction: RecaptchaAction(customAction: "checkout")) ``` -------------------------------- ### Add Android SDK Dependency Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Add the reCAPTCHA dependency to your Android module's build.gradle.kts. Requires a SITE_KEY value. ```kotlin // app/build.gradle.kts dependencies { implementation("com.google.android.recaptcha:recaptcha:18.8.0") } ``` ```toml # gradle/libs.versions.toml (version catalog approach) [versions] recaptcha = "18.8.0" [libraries] recaptcha = { group = "com.google.android.recaptcha", name = "recaptcha", version.ref = "recaptcha" } ``` -------------------------------- ### Load reCAPTCHA Enterprise JavaScript Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Include this script in your HTML's to enable reCAPTCHA Enterprise functionality. Ensure you use enterprise.js and replace YOUR_SITE_KEY with your actual site key. ```html ``` -------------------------------- ### Generate reCAPTCHA Token on Frontend Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Generates a fresh reCAPTCHA token for a given action. Call this immediately before each API request; do NOT cache the token. Handles potential token generation failures by logging a warning and returning null. ```javascript /** * Generates a fresh reCAPTCHA token for the given action. * Call this immediately before each API request — do NOT cache the token. */ async function getRecaptchaToken(siteKey, action) { try { return await grecaptcha.enterprise.execute(siteKey, { action }); } catch (error) { console.warn('reCAPTCHA token generation failed (Fail Open):', error); return null; } } ``` ```javascript // Example — protect a checkout button click: document.getElementById('checkout-btn').addEventListener('click', async () => { const token = await getRecaptchaToken('YOUR_SITE_KEY', 'checkout'); const response = await fetch('/api/pay', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token, ...paymentData }), }); const result = await response.json(); if (result.shouldBlock) { alert('Transaction blocked.'); } }); ``` -------------------------------- ### Execute reCAPTCHA Action in JavaScript Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/android/webview/app/src/main/assets/rce.html Use this function to execute a reCAPTCHA challenge for a given action. It returns a promise that resolves with the reCAPTCHA token or rejects with an error. Ensure the __JS_OBJECT_NAME__ is properly configured. ```javascript const onExecute = async (action) => { const executeId = 'rce\_' + Math.floor(Math.random() * 100000) window[executeId] = {} window[executeId].bridgeResolve = (token) => { window[executeId].resolve(token) delete window[executeId] } window[executeId].bridgeReject = (err) => { window[executeId].reject(err) delete window[executeId] } const promise = new Promise((resolve, reject) => { window[executeId].resolve = (token) => resolve(token) window[executeId].reject = (err) => reject(err) }) __JS_OBJECT_NAME__.onExecute(action, `window.${executeId}.bridgeResolve`, `window.${executeId}.bridgeReject`); return promise }; ``` -------------------------------- ### createAssessment (Node.js) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt The server-side `createAssessment` function calls the reCAPTCHA Enterprise API to validate a token and retrieve a risk score. It requires the `@google-cloud/recaptcha-enterprise` package and the `GOOGLE_APPLICATION_CREDENTIALS` environment variable. ```APIDOC ## createAssessment (Node.js) ### Description Calls the reCAPTCHA Enterprise API to validate a token and retrieve a risk score. ### Method Signature `createAssessment({ projectID, siteKey, token, transactionData, expectedAction })` ### Parameters - **projectID** (string) - Optional - The Google Cloud project ID. Defaults to `process.env.CLOUD_PROJECT_ID`. - **siteKey** (string) - Optional - The reCAPTCHA site key. Defaults to `process.env.RECAPTCHA_SITE_KEY`. - **token** (string) - Required - The token generated by the reCAPTCHA client-side. - **transactionData** (object) - Optional - Data associated with the transaction. - **expectedAction** (string) - Optional - The expected action for the token. ### Request Example ```javascript const assessment = await createAssessment({ token, expectedAction: 'login', }); ``` ### Response - **response** (object) - The assessment result from the reCAPTCHA Enterprise API, or null if the token is invalid or an error occurs. - **name** (string) - The name of the assessment. - **riskAnalysis.score** (number) - The risk score (0.0 to 1.0). - **tokenProperties.valid** (boolean) - Whether the token is valid. - **tokenProperties.invalidReason** (string) - The reason if the token is invalid. - **tokenProperties.action** (string) - The action associated with the token. ``` -------------------------------- ### Android - Execute Action and Generate Token Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt The `recaptchaClient.execute(action)` function generates a reCAPTCHA token for a given action. It should be called on the IO dispatcher just before sending the token to your backend, as tokens are single-use and expire quickly. The function returns a `Result` which is either a success containing the token or a failure with an exception. ```APIDOC ## Android - `RecaptchaClient.execute` (Generate a Token) `recaptchaClient.execute(action)` is a suspending function that returns `Result`. The `Result` is a success containing the token string, or a failure with an exception. Always call `execute` on the IO dispatcher immediately before sending the token to your backend — tokens are single-use and expire quickly. ```kotlin // ViewModel usage — execute a LOGIN action and send token to backend import com.google.android.recaptcha.RecaptchaAction import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class LoginViewModel : ViewModel() { fun onLoginClicked(username: String, password: String) { viewModelScope.launch(Dispatchers.IO) { RecaptchaRepository.retrieveToken(RecaptchaAction.LOGIN) .onSuccess { token -> // Send token + credentials to your backend for assessment val response = backendRepository.login(username, password, token) if (response["shouldBlock"] as Boolean) { _errorMessage.postValue("Attestation failed!") } else { _loginState.postValue(true) } } .onFailure { error -> _errorMessage.postValue("reCAPTCHA failed: ${error.localizedMessage}") } } } } // Custom action (any alphanumeric string, slashes, underscores) val checkoutToken = RecaptchaRepository.retrieveToken(RecaptchaAction(customAction = "checkout")) ``` ``` -------------------------------- ### CSS for reCAPTCHA Loading Spinner Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/android/visual/app/src/main/assets/rce.html Defines the CSS animations and styles for a loading spinner used while reCAPTCHA is initializing. ```css @keyframes lf-loading-spinner { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .lf-loading-spinner { animation: lf-loading-spinner 1250ms infinite linear; border: 4px solid #4285f4; border-radius: 32px; border-right-color: transparent; border-top-color: transparent; box-sizing: border-box; height: 64px; width: 64px; } html, body, .container { height: 100%; width: 100%; margin: 0; padding: 0; background-color: transparent; } .container { display: flex; justify-content: center; align-items: center; } ``` -------------------------------- ### Check reCAPTCHA Enterprise Integration Status Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Fetches reCAPTCHA Enterprise metrics to confirm tokens are reaching the API. Requires CLOUD_PROJECT_ID and RECAPTCHA_SITE_KEY environment variables. It may take up to 24 hours for data to appear after the first token is generated. ```javascript const { RecaptchaEnterpriseServiceClient } = require('@google-cloud/recaptcha-enterprise'); async function checkStatus() { const client = new RecaptchaEnterpriseServiceClient(); const metricsName = `projects/${process.env.CLOUD_PROJECT_ID}/keys/${process.env.RECAPTCHA_SITE_KEY}/metrics`; const [metrics] = await client.getMetrics({ name: metricsName }); console.log(`Score metrics: ${metrics.scoreMetrics?.length ?? 0} days of data`); if (metrics.scoreMetrics?.length > 0) { const latest = metrics.scoreMetrics[0]; console.log('Latest score distribution:'); console.log(JSON.stringify(latest.overallMetrics.scoreBuckets, null, 2)); // Example output: // { // "0.1": 12, // 12 requests with score 0.1 (bot-like) // "0.7": 845, // 845 requests with score 0.7 (human-like) // "0.9": 203 // } } else { console.log('No data yet — can take up to 24h to appear after first token.'); } } checkStatus(); // Run: CLOUD_PROJECT_ID=my-project RECAPTCHA_SITE_KEY=my-key node check-status.js ``` -------------------------------- ### Create reCAPTCHA Enterprise Assessment (Node.js) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Use this function to call the reCAPTCHA Enterprise API to validate a token and retrieve a risk score. Requires `@google-cloud/recaptcha-enterprise` and `GOOGLE_APPLICATION_CREDENTIALS` environment variable. ```javascript // recaptcha-integration.js const { RecaptchaEnterpriseServiceClient } = require('@google-cloud/recaptcha-enterprise'); async function createAssessment({ projectID = process.env.CLOUD_PROJECT_ID, siteKey = process.env.RECAPTCHA_SITE_KEY, token, transactionData = {}, expectedAction = null }) { const client = new RecaptchaEnterpriseServiceClient(); const projectPath = client.projectPath(projectID); const request = { assessment: { event: { token, siteKey, transactionData, expectedAction, }, }, parent: projectPath, }; try { const [response] = await client.createAssessment(request); if (!response.tokenProperties.valid) { console.log('Token invalid:', response.tokenProperties.invalidReason); return null; // Fail open or closed depending on policy } if (expectedAction && response.tokenProperties.action !== expectedAction) { console.log('Action mismatch — possible token hijack attempt'); return null; } console.log('Assessment name:', response.name); console.log('Risk score:', response.riskAnalysis.score); // 0.0 (bot) to 1.0 (human) return response; } catch (e) { console.error('createAssessment failed:', e); return null; // Fail Open: allow transaction on API error } } // Usage in an Express login route: app.post('/login', async (req, res) => { const token = req.body['g-recaptcha-response']; const assessment = await createAssessment({ token, expectedAction: 'login', }); if (!assessment || assessment.riskAnalysis.score < 0.5) { return res.status(403).json({ shouldBlock: true }); } res.json({ shouldBlock: false }); }); module.exports = { createAssessment }; ``` -------------------------------- ### Handle reCAPTCHA Execution Click Event in JavaScript Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/examples/android/webview/app/src/main/assets/rce.html This function is triggered by a click event to execute a reCAPTCHA challenge for the 'login' action and display the resulting token or error message on the page. It utilizes the onExecute function to obtain the reCAPTCHA token. ```javascript const executeClick = async () => { try { const result = await onExecute("login") document.querySelector("#result").textContent = "TOKEN: " + result } catch(err) { document.querySelector("#result").textContent = "ERROR: " + err } } ``` -------------------------------- ### Two-Stage Transaction Assessment with reCAPTCHA Enterprise Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Perform a front-office assessment at checkout and a back-office assessment after payment authorization, enriching with card details for fraud detection. Store the assessment name for later feedback. ```javascript // Stage 1 — At checkout, evaluate token + user email const frontOfficeAssessment = await createAssessment({ token: req.body.recaptchaToken, expectedAction: 'checkout', transactionData: { transactionId: generatedTxId, paymentMethod: 'credit_card', currencyCode: 'USD', value: 99.00, user: { email: 'user@example.com', hashedAccountId: sha256(userId) }, }, }); if (frontOfficeAssessment?.fraudPreventionAssessment?.transactionVerdict === 'FRAUDULENT') { return res.status(403).json({ error: 'Transaction blocked' }); } // Store assessmentName for feedback later await db.saveAssessmentName(generatedTxId, frontOfficeAssessment.name); ``` ```javascript // Stage 2 — In Stripe webhook after authorization, enrich with card data app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), async (req, res) => { const sig = req.headers['stripe-signature']; const event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET); if (event.type === 'checkout.session.completed') { const session = event.data.object; const pi = await stripe.paymentIntents.retrieve(session.payment_intent, { expand: ['payment_method'], }); const backOfficeAssessment = await createAssessment({ token: undefined, // No new token needed for back-office transactionData: { transactionId: pi.metadata.transactionId, cardLastFour: pi.payment_method.card.last4, billingAddress: { postalCode: pi.payment_method.billing_details.address.postal_code, regionCode: 'US', }, }, }); const verdict = backOfficeAssessment?.fraudPreventionAssessment?.transactionVerdict; if (verdict !== 'FRAUDULENT') { await stripe.paymentIntents.capture(pi.id); } else { await stripe.paymentIntents.cancel(pi.id); } } res.json({ received: true }); }); ``` -------------------------------- ### Create Assessment Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/skills/recaptcha-transaction-defense-integrator/references/recaptcha-api.md Create an assessment to protect a transaction by providing transaction data. This is used for both front-office and back-office assessments. ```APIDOC ## Create Assessment ### Description Creates an assessment to protect a transaction. This endpoint is used for both front-office and back-office assessments. ### Method POST ### Endpoint `https://recaptchaenterprise.googleapis.com/v1/projects/PROJECT_ID/assessments` ### Request Body - **event** (object) - Required - The event to be assessed. - **siteKey** (string) - Required - Your Enterprise Site Key. - **expectedAction** (string) - Optional - The expected action for the event (e.g., `checkout`). - **transactionData** (object) - Optional - Object containing transaction details. - **transactionId** (string) - Required - Unique identifier for the transaction. - **paymentMethod** (string) - Optional - The payment method used (e.g., `credit_card`). - **currencyCode** (string) - Optional - The currency code for the transaction value (e.g., `USD`). - **value** (number) - Optional - The monetary value of the transaction. - **cardLastFour** (string) - Optional - The last four digits of the card used. - **billingAddress** (object) - Optional - Billing address details. - **postalCode** (string) - Optional - The postal code of the billing address. - **regionCode** (string) - Optional - The region code of the billing address (e.g., `US`). - **user** (object) - Optional - User details. - **email** (string) - Optional - The email address of the user. - **hashedAccountId** (string) - Optional - A stable, hashed ID for the user. ### Request Example ```json { "event": { "siteKey": "YOUR_SITE_KEY", "expectedAction": "checkout", "transactionData": { "transactionId": "TRANSACTION_ID", "paymentMethod": "credit_card", "currencyCode": "USD", "value": 5.00, "cardLastFour": "4242", "billingAddress": { "postalCode": "94043", "regionCode": "US" }, "user": { "email": "user@example.com" } } } } ``` ### Response #### Success Response (200) - **riskAnalysis.score** (number) - The bot score (0.0 to 1.0). - **fraudPreventionAssessment.transactionVerdict** (string) - The fraud verdict (`LEGITIMATE`, `FRAUDULENT`, `SUSPICIOUS`). #### Response Example ```json { "event": { "token": "TOKEN", "siteKey": "YOUR_SITE_KEY", "expectedAction": "checkout", "transactionData": { "transactionId": "TRANSACTION_ID", "paymentMethod": "credit_card", "currencyCode": "USD", "value": 5.00, "cardLastFour": "4242", "billingAddress": { "postalCode": "94043", "regionCode": "US" }, "user": { "email": "user@example.com" } } }, "riskAnalysis": { "score": 0.9 }, "fraudPreventionAssessment": { "transactionVerdict": "FRAUDULENT" } } ``` ``` -------------------------------- ### Annotate Assessment with Ground Truth Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/skills/recaptcha-transaction-defense-integrator/references/recaptcha-api.md Send this JSON payload to the annotate endpoint to provide ground truth for an assessment, such as marking it as fraudulent due to a chargeback. Replace 'PROJECT_ID' and 'ASSESSMENT_ID' with your specific values. ```json { "annotation": "FRAUDULENT", "reasons": ["CHARGEBACK_FRAUD"] } ``` -------------------------------- ### iOS WebView Bridge (`RecaptchaBridge` + `WKScriptMessageHandler`) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Connects a `WKWebView` to the native `RecaptchaClient`, enabling web content to request reCAPTCHA tokens via JavaScript `postMessage`. The bridge must be registered with `addToWebView(_:)` before loading HTML content. ```APIDOC ## iOS — WebView Bridge (`RecaptchaBridge` + `WKScriptMessageHandler`) `RecaptchaBridge` connects a `WKWebView` to the native `RecaptchaClient`, allowing web content inside the app to request tokens via JavaScript `postMessage`. Register the bridge with `addToWebView(_:)` before loading HTML content. ```swift import WebKit import RecaptchaEnterprise class WebViewController: UIViewController { private var bridge: RecaptchaBridge? private lazy var webView: WKWebView = { let config = WKWebViewConfiguration() config.preferences.javaScriptEnabled = true return WKWebView(frame: .zero, configuration: config) }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(webView) // Layout constraints omitted for brevity } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 1. Attach the bridge (registers JS message handlers) bridge = RecaptchaBridge() bridge?.addToWebView(webView) // 2. Load HTML that posts to window.webkit.messageHandlers.onExecute if let url = Bundle.main.url(forResource: "rce", withExtension: "html") { let html = try? String(contentsOf: url) webView.loadHTMLString(html ?? "", baseURL: nil) } } } // JavaScript side (inside the loaded HTML): // window.webkit.messageHandlers.onExecute.postMessage({ // action: "checkout", // bridgeResolve: "onTokenSuccess", // bridgeReject: "onTokenError" // }); ``` ``` -------------------------------- ### Stripe Manual Capture Workflow Webhook Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/skills/recaptcha-transaction-defense-integrator/references/psp-webhooks.md Handles Stripe's checkout.session.completed event to perform a second reCAPTCHA assessment with card details before capturing payment. Ensure the Stripe secret is configured. ```javascript app.post('/webhooks/stripe', express.raw({type: 'application/json'}), async (req, res) => { const sig = req.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret); } catch (err) { return res.status(400).send(`Webhook Error: ${err.message}`); } if (event.type === 'checkout.session.completed') { const session = event.data.object; const piId = session.payment_intent; // 1. Retrieve PI with expanded payment_method to get Card Last 4 and Zip const pi = await stripe.paymentIntents.retrieve(piId, { expand: ['payment_method'] }); const card = pi.payment_method.card; const billing = pi.payment_method.billing_details; // 2. Perform SECOND reCAPTCHA Assessment with card data const assessment = await recaptcha.createAssessment({ transactionData: { cardLastFour: card.last4, billingAddress: { postalCode: billing.address.postal_code } // ... other fields } }); // 3. Capture only if not FRAUDULENT if (assessment.fraudPreventionAssessment.transactionVerdict !== 'FRAUDULENT') { await stripe.paymentIntents.capture(piId); } else { // Handle fraud (e.g., cancel/refund) } } res.json({received: true}); }); ``` -------------------------------- ### Integrate WebView with reCAPTCHA Bridge (iOS) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Connect a `WKWebView` to the native `RecaptchaClient` using `RecaptchaBridge`. This allows JavaScript within the web view to request tokens via `postMessage`. Register the bridge with `addToWebView(_:)` before loading HTML. ```swift import WebKit import RecaptchaEnterprise class WebViewController: UIViewController { private var bridge: RecaptchaBridge? private lazy var webView: WKWebView = { let config = WKWebViewConfiguration() config.preferences.javaScriptEnabled = true return WKWebView(frame: .zero, configuration: config) }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(webView) // Layout constraints omitted for brevity } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 1. Attach the bridge (registers JS message handlers) bridge = RecaptchaBridge() bridge?.addToWebView(webView) // 2. Load HTML that posts to window.webkit.messageHandlers.onExecute if let url = Bundle.main.url(forResource: "rce", withExtension: "html") { let html = try? String(contentsOf: url) webView.loadHTMLString(html ?? "", baseURL: nil) } } } // JavaScript side (inside the loaded HTML): // window.webkit.messageHandlers.onExecute.postMessage({ // action: "checkout", // bridgeResolve: "onTokenSuccess", // bridgeReject: "onTokenError" // }); ``` -------------------------------- ### Correct reCAPTCHA Enterprise Script Tag Source: https://github.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/blob/main/skills/recaptcha-transaction-defense-integrator/references/v3.md Always import `enterprise.js` for reCAPTCHA Enterprise keys. Using `api.js` will result in a `MALFORMED` error. ```html ``` -------------------------------- ### Annotate reCAPTCHA Enterprise Assessment (Node.js) Source: https://context7.com/googlecloudplatform/recaptcha-enterprise-mobile-sdk/llms.txt Use this function to provide feedback to the reCAPTCHA Enterprise model, improving its accuracy over time. Requires the assessment name obtained from a previous `createAssessment` call. ```javascript const { RecaptchaEnterpriseServiceClient } = require('@google-cloud/recaptcha-enterprise'); async function annotateAssessment({ assessmentName, annotation, reasons = [] }) { const client = new RecaptchaEnterpriseServiceClient(); try { const [response] = await client.annotateAssessment({ name: assessmentName, annotation, // 'LEGITIMATE' | 'FRAUDULENT' | 'PASSWORD_CORRECT' | 'PASSWORD_INCORRECT' reasons, // ['CHARGEBACK_FRAUD', 'PASSED_TWO_FACTOR', etc.] }); console.log(`Annotated ${assessmentName} as ${annotation}`); return response; } catch (err) { console.error('annotateAssessment error:', err); return null; } } // Mark a confirmed fraudulent transaction: await annotateAssessment({ assessmentName: 'projects/my-project/assessments/abc123', annotation: 'FRAUDULENT', reasons: ['CHARGEBACK_FRAUD'], }); // Mark a confirmed legitimate login: await annotateAssessment({ assessmentName: 'projects/my-project/assessments/xyz789', annotation: 'LEGITIMATE', reasons: ['PASSED_TWO_FACTOR'], }); ```