Integrate reCAPTCHA Enterprise with iOS apps

This page explains how to integrate reCAPTCHA Enterprise in your iOS app.

Due to the variation in mobile devices in terms of screen size, performance, and UIs of the apps, the visual checkbox reCAPTCHA challenge (I'm not a robot) is not available for iOS mobile apps. You can instead implement your own tiered enforcement strategy, such as an MFA flow to provide an alternative redemption path for suspicious traffic.

Before you begin

  1. Set the minimum SDK of your app to iOS 11 or create a new mobile app.

  2. Prepare your environment for reCAPTCHA Enterprise.

  3. Create a reCAPTCHA key for the iOS app platform.

    Alternatively, you can copy the ID of an existing reCAPTCHA key for iOS by performing one of the following steps:

    • To copy the ID of an existing key from the Google Cloud console, do the following:

      1. Go to the reCAPTCHA Enterprise page.

        Go to reCAPTCHA Enterprise

      2. In the reCAPTCHA keys list, hold the pointer over the key you want to copy, and then click .
    • To copy the ID of an existing key using the REST API, use the projects.keys.list method.
    • To copy the ID of an existing key using the gcloud CLI, use the gcloud recaptcha keys list command.

  4. Have a GitHub account.

  5. Read the Apple privacy details.

Prepare your iOS environment

To prepare your development environment, do the following:

  1. Download and install the latest version of Xcode and create a new blank iOS single view application.

  2. Download the SDK by using one of the following:

    CocoaPods

    1. Download and install CocoaPods.
    2. Create a Podfile and add the following lines to your Podfile:

      source "https://github.com/CocoaPods/Specs.git"
      
      target 'AppTarget' do
      
        # Podfiles must include use_frameworks! or
        # use_frameworks! :linkage => :static
        use_frameworks!
      
        pod "RecaptchaEnterprise", "18.5.0-beta01"
        ...
      
      end
      
    3. Install the required dependencies by running pod update.

    Swift Package Manager

    1. In XCode, select File > Add Packages, and enter the following URL in the Search or Enter Package URL field: https://github.com/GoogleCloudPlatform/recaptcha-enterprise-mobile-sdk
    2. In the XCode dialog, enter the following details:

      • GitHub username.
      • A personal access token that you created using GitHub's instructions. The Personal Access Token must have the scopes listed in the XCode Sign In dialog.

      Xcode installs the SDK and its required dependencies.

    Flutter

    For detailed instructions about using reCAPTCHA Enterprise through Flutter, see the Flutter documentation.

    ReactNative

    For detailed instructions about using reCAPTCHA Enterprise through React Native, see the React Native documentation.

    Direct download

    1. If you want to download the SDK and its dependencies as xcframeworks, download the client.

Configure the app

You can write your apps in Swift or Objective-C.

To configure your app, add the following files in your app:

Swift

  1. If your app is written in Swift, create an Objective-C bridging header and include the following import:

    #import <RecaptchaEnterprise/RecaptchaEnterprise.h>
    

Objective-C

  1. If your app is written in Objective-C, create a dummy Swift file and include the following import to make sure Xcode can find and link the Swift libraries.

    import Foundation
    
  2. To ensure that the Swift code is linked correctly navigate to Target > Build Settings > Always Embed Swift Standard Libraries and verify that the option is set to Yes.

Integrate reCAPTCHA Enterprise with your iOS app

To integrate reCAPTCHA Enterprise with your iOS app, follow these steps in Xcode:

  1. To instantiate the SDK with the reCAPTCHA key (KEY_ID) that you created, update the app with the following code:

    Swift with Storyboard

    1. Update ViewController.swift.

      If you are using CocoaPods, then ignore the import RecaptchaEnterprise line, because the import statement #import <RecaptchaEnterprise/RecaptchaEnterprise.h> in the *-Bridging-Header.h file is sufficient.

      import RecaptchaEnterprise
      
      class ViewController: UIViewController {
        var recaptchaClient: RecaptchaClient?
      
        override func viewDidLoad() {
          super.viewDidLoad()
          Task {
            do {
              let client = try await Recaptcha.getClient(withSiteKey: "KEY_ID")
              self.recaptchaClient = client
            } catch let error as RecaptchaError {
               print("RecaptchaClient creation error: \(String(describing: error.errorMessage)).")
            }
          }
        }
      }
      

      If your application's minimum OS version is less than 13, use a trailing closure instead:

      import RecaptchaEnterprise
      
      class ViewController: UIViewController {
        var recaptchaClient: RecaptchaClient?
      
        override func viewDidLoad() {
          super.viewDidLoad()
          Recaptcha.getClient(withSiteKey: "KEY_ID") { client, error in
            guard let client = client else {
                print("RecaptchaClient creation error: \(error).")
              return
            }
            self.recaptchaClient = client
          }
        }
      }
      

    Swift with SwiftUI

    1. Create a ViewModel class.

      If you're using CocoaPods, then ignore theimport RecaptchaEnterprise line, because the import statement #import <RecaptchaEnterprise/RecaptchaEnterprise.h> in the *-Bridging-Header.h file is sufficient.

      import RecaptchaEnterprise
      
      @MainActor class ViewModel: ObservableObject {
        private var recaptchaClient: RecaptchaClient?
      
        init() {
           Task {
            do {
              let client = try await Recaptcha.getClient(withSiteKey: "KEY_ID")
              self.recaptchaClient = client
            } catch let error as RecaptchaError {
               print("RecaptchaClient creation error: \(String(describing: error.errorMessage)).")
            }
          }
        }
      }
      

      If your application's minimum OS version is less than 13, use a trailing closure instead:

      import RecaptchaEnterprise
      
      class ViewController: UIViewController {
        var recaptchaClient: RecaptchaClient?
      
        override func viewDidLoad() {
          super.viewDidLoad()
          Recaptcha.getClient(withSiteKey: "KEY_ID") { client, error in
            guard let client = client else {
                print("RecaptchaClient creation error: \(error).")
              return
            }
            self.recaptchaClient = client
          }
        }
      }
      
    2. Instantiate ViewModel in ContentView.swift.

      import SwiftUI
      import RecaptchaEnterprise
      
      struct ContentView: View {
        @StateObject private var viewModel = ViewModel()
      
        var body: some View {
        }
      }
      
      struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
          ContentView()
        }
      }
      

    Objective-C

    1. Update ViewController.h.

      #import <RecaptchaEnterprise/RecaptchaEnterprise.h>
      
      @interface ViewController : UIViewController
      @property (strong, atomic) RecaptchaClient *recaptchaClient;
      @end
      
    2. Update ViewController.m.

      @implementation ViewController
      [Recaptcha getClientWithSiteKey:@"KEY_ID"
            completion:^void(RecaptchaClient* recaptchaClient, NSError* error) {
              if (!recaptchaClient) {
                NSLog(@"%@", (RecaptchaError *)error.errorMessage);
                return;
              }
              self->_recaptchaClient = recaptchaClient;
            }
      ];
      @end
      
  2. Create a button to call reCAPTCHA Enterprise and trigger execute().

    Swift with Storyboard

    1. In the storyboard, create a button.
    2. Create an action in ViewController linked to the button that you created.
    3. Call the execute() method passing a Login action to return a reCAPTCHA token by using the following code snippet:

      guard let recaptchaClient = recaptchaClient else {
        print("RecaptchaClient creation failed.")
        return
      }
      Task {
        do {
          let token = try await recaptchaClient.execute(withAction: RecaptchaAction.login)
          print(token)
        } catch let error as RecaptchaError {
          print(error.errorMessage)
        }
      }
      

      If your application's minimum OS version is less than 13, use a trailing closure instead:

      guard let recaptchaClient = recaptchaClient else {
        print("RecaptchaClient creation failed.")
        return
      }
      recaptchaClient.execute(withAction: RecaptchaAction.login) { token, error in
        if let token = token {
          print(token)
        } else {
          print(error)
        }
      }
      

    Swift with SwiftUI

    1. Update ViewModel.swift with the execute code:

      import RecaptchaEnterprise
      
      @MainActor class ViewModel: ObservableObject {
      
        func execute() {
          guard let recaptchaClient = self.recaptchaClient else {
            print("Client not initialized correctly.")
            return
          }
      
          Task {
            do {
              let token = try await recaptchaClient.execute(withAction: RecaptchaAction.login)
              print(token)
            } catch let error as RecaptchaError {
              print(error.errorMessage)
            }
          }
        }
      }
      

      If your application's minimum OS version is less than 13, use a trailing closure instead:

      guard let recaptchaClient = recaptchaClient else {
        print("RecaptchaClient creation failed.")
        return
      }
      recaptchaClient.execute(withAction: RecaptchaAction.login) { token, error in
        if let token = token {
          print(token)
        } else {
          print(error)
        }
      }
      
    2. Update ContentView.swift.

      import SwiftUI
      import RecaptchaEnterprise
      
      struct ContentView: View {
        @StateObject private var viewModel = ViewModel()
      
        var body: some View {
      
          Button {
            viewModel.execute()
          } label: {
            Text("Execute")
          }.padding()
      
          Spacer()
        }
      }
      
      struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
          ContentView()
        }
      }
      

    Objective-C

    1. In the storyboard, create a button.
    2. Create an action in ViewController linked to the button that you created.
    3. Call the execute() method passing a Login action to return a reCAPTCHA token by using the following code snippet:

      if (!self->_recaptchaClient) {
        return;
      }
      
      [recaptchaClient execute:RecaptchaAction.login
          completion:^void(NSString* _Nullable  token, NSError* _Nullable error) {
        if (!token) {
          NSLog (@"%@", (RecaptchaError *)error.errorMessage);
          return;
        }
        NSLog (@"%@", token);
      }];
      
  3. Test your application:

    1. reCAPTCHA Enterprise uses Apple's AppAttest as part of its detection engine. If you don't plan to use a testing key with a fixed score for local development, do the following:

      1. In Xcode, add the App Attest capability to your app.

      2. In your project's .entitlements file, set the App Attest environment to production.

    2. To clean your Xcode build environment, in the Product menu, click Clean Build Folder.

    3. To run the application, in the Product menu, click Run.

    4. In your loaded application, click the button that you created earlier.

    5. Observe your debug output window for a reCAPTCHA token (alpha-numeric string), which is returned if the integration is successful.

Set a timeout for API calls

You can specify a timeout value for getClient and execute APIs by using the withTimeout property of each API.

Swift

  1. Set timeout when calling getClient.

        Task {
          do {
            self.recaptchaClient = try await Recaptcha.getClient(
              withSiteKey: "KEY_ID",
              withTimeout: 15000
            )
          } catch let error as RecaptchaError {
              print("RecaptchaClient creation error: \(String(describing: error.errorMessage)).")
          }
        }
    

    If your application's minimum OS version is less than 13, use a trailing closure instead:

      Recaptcha.getClient(
        withSiteKey: "KEY_ID",
        withTimeout: 15000
      ) { client, error in
        guard let client = client else {
            print("RecaptchaClient creation error: \(error).")
          return
        }
        self.recaptchaClient = client
      }
    
  2. Set timeout when calling execute.

      Task {
        do {
          let token = try await recaptchaClient.execute(
            withAction: RecaptchaAction.login,
            withTimeout: 10000)
          print(token)
        } catch let error as RecaptchaError {
          print(error.errorMessage)
        }
      }
    

    If your application's minimum OS version is less than 13, use a trailing closure instead:

      recaptchaClient.execute(
        withAction: RecaptchaAction.login,
        withTimeout: 10000
      ) { token, error in
        if let token = token {
          print(token)
        } else {
          print(error)
        }
      }
    

Objective-C

  1. Set timeout when calling getClient.

      [Recaptcha getClientWithSiteKey:@"KEY_ID"
                  withTimeout:15000.0
                   completion:^void(RecaptchaClient *recaptchaClient, NSError *error) {
                     if (!recaptchaClient) {
                       NSLog(@"%@", (RecaptchaError *)error.errorMessage);
                       return;
                     }
                     self->_recaptchaClient = recaptchaClient;
                   }];
    
  2. Set timeout when calling execute.

      [recaptchaClient execute:RecaptchaAction.login
          witTimeout:10000.0
          completion:^void(NSString* _Nullable  token, NSError* _Nullable error) {
        if (!token) {
          NSLog (@"%@", (RecaptchaError *)error.errorMessage);
          return;
        }
        NSLog (@"%@", token);
      }];
    

API reference

For a complete reference of the reCAPTCHA API for iOS, see RecaptchaEnterprise.

What's next

  • To assess the reCAPTCHA response token, create an assessment.