---
title: Integrating reCAPTCHA Enterprise into an iOS app
description: PingOne Advanced Identity Cloud PingAM iOS
component: orchsdks
page_id: orchsdks:journey:use-cases/recaptcha-enterprise/ios-recaptcha-enterprise
canonical_url: https://developer.pingidentity.com/orchsdks/journey/use-cases/recaptcha-enterprise/ios-recaptcha-enterprise.html
section_ids:
  importing_dependencies: Importing dependencies
  swift_package_manager: Swift Package Manager
  cocoapods: Cocoapods
  handling_the_callback_with_the_sdk: Handling the callback with the SDK
  config: Configuring the verification
  payload: Customizing the assessment payload
  custom-error: Returning custom error codes
---

# Integrating reCAPTCHA Enterprise into an iOS app

[icon: circle-check, set=far]PingOne Advanced Identity Cloud [icon: circle-check, set=far]PingAM [icon: apple, set=fab]iOS

To add support for reCAPTCHA Enterprise to your iOS apps, complete the following tasks.

## Importing dependencies

You can add the dependencies using Cocoapods or Swift Package Manager (SPM).

### Swift Package Manager

1. With your project open in **Xcode**, select **File** > **Add Package Dependencies**.

2. In the search bar, enter the ForgeRock SDK for iOS repository URL: `https://github.com/ForgeRock/ping-ios-sdk`.

3. Select the `ping-ios-sdk` package, and then click **Add Package**.

4. In the **Choose Package Products** dialog, set the **Add to Target** field for the `PingReCaptchaEnterprise` library to be the name of your project.

5. Click Add Package.

6. In your project, import the library:

   ```swift
   // Import the reCAPTCHA Enterprise library
   import PingReCaptchaEnterprise
   ```

### Cocoapods

1. If you do not already have CocoaPods, install the [latest version](https://guides.cocoapods.org/using/getting-started.html).

2. If you do not already have a Podfile, in a terminal window, run the following command to create a new [Podfile](https://guides.cocoapods.org/syntax/podfile.html):

   ```
   pod init
   ```

3. Add the following lines to your Podfile:

   ```swift
   pod 'PingReCaptchaEnterprise', '2.0.0'
   ```

4. Run the following command to install pods:

   ```
   pod install
   ```

## Handling the callback with the SDK

Use code similar to the following to handle the `ReCaptchaEnterpriseCallback` in your client-side code using the Orchestration SDKs:

```swift
import PingJourney
import PingReCaptchaEnterprise

// Process Journey callbacks
node.callbacks.forEach { callback in
    switch callback {
    case let recaptchaCallback as ReCaptchaEnterpriseCallback:
        Task {
            // Execute reCAPTCHA assessment
            let result = await recaptchaCallback.verify()
            switch result {
            case .success:
                // reCAPTCHA assessment successful
                // The token has been automatically set in the callback
                // Continue to the next step in the Journey
                let nextNode = await node.next()
            case .failure(let error):
                // Handle reCAPTCHA-specific errors
                print("reCAPTCHA error: \(error.errorCode) - \(error.errorMessage)")
                // Optionally set a custom error code
                recaptchaCallback.setClientError("recaptcha_failed")
            }
        }

    // Handle other callback types
    default:
        break
    }
}
```

## Configuring the verification

You can pass a number of options into the call to `verify()` to customize its operation:

Configuring the call to `verify()` on iOS

```swift
import PingJourney
import PingReCaptchaEnterprise

// Process Journey callbacks
node.callbacks.forEach { callback in
    switch callback {
    case let recaptchaCallback as ReCaptchaEnterpriseCallback:
        Task {

            // Execute reCAPTCHA assessment
            let result = await recaptchaCallback.verify { config in
                // Optionally customize the configuration
                config.action = "purchase"
                config.timeout = 20000
                config.logger = LogManager.error
            }

            switch result {
            case .success:
                // reCAPTCHA assessment successful
                // The token has been automatically set in the callback
                // Continue to the next step in the Journey
                let nextNode = await node.next()
            case .failure(let error):
                // Handle reCAPTCHA-specific errors
                print("reCAPTCHA error: \(error.errorCode) - \(error.errorMessage)")
                // Optionally set a custom error code
                recaptchaCallback.setClientError("recaptcha_failed")
            }
        }

    // Handle other callback types
    default:
        break
    }
}
```

The available properties for configuring the `verify()` call are as follows:

| Property                     | Default                                      | Description                                                                                                                                                                                                                                                                                              |
| ---------------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `siteKey` (`String`)         | From server                                  | The reCAPTCHA Enterprise site key is set by the server, and is read-only.                                                                                                                                                                                                                                |
| `action` (`String`)          | `ReCaptchaEnterpriseConstants.defaultAction` | The type of action you want to verify.The default `ReCaptchaEnterpriseConstants.defaultAction` signifies a login action.You can also specify your own action:```
config.action = "password_reset"
config.action = "payment"
config.action = "add_to_cart"
```                                            |
| `timeout` (`Double`)         | `15000`                                      | How long to wait, in milliseconds, for a verification to complete.Use longer timeouts for slow networks or critical operations.                                                                                                                                                                          |
| `payload` (`[String: Any]?`) | `nil`                                        | Add relevant metadata to help with risk assessment and debugging.Learn more in [Customizing the assessment payload](#payload).                                                                                                                                                                           |
| `logger` (`Logger`)          | `LogManager.warning`                         | What level of logging the module should output.Choose from the following options:- `LogManager.debug`

  Detailed debugging messages, for use during development.

- `LogManager.error`

  Only logs errors.

- `LogManager.info`

  Logs info-level messages.

- `LogManager.none`

  Disables logging. |

## Customizing the assessment payload

You can add additional data to customize the payload that the server sends to the Google reCAPTCHA Enterprise for assessment.

Add data to the payload to leverage additional functionality provided by reCAPTCHA Enterprise.

The JSON format the payload expects is as follows:

```json
{
  "token": string,
  "siteKey": string,
  "userAgent": string,
  "userIpAddress": string,
  "expectedAction": string,
  "hashedAccountId": string,
  "express": boolean,
  "requestedUri": string,
  "wafTokenAssessment": boolean,
  "ja3": string,
  "headers": [
    string
  ],
  "firewallPolicyEvaluation": boolean,
  "transactionData": {
    object (TransactionData)
  },
  "userInfo": {
    object (UserInfo)
  },
  "fraudPrevention": enum (FraudPrevention)
}
```

By default, the SDK or the node itself populates the following fields:

* `token`

* `siteKey`

* `userAgent`

* `userIpAddress`

* `expectedAction`

You can however also override these values if it suits your use case.

|   |                                                                                                                                                                                                                                                                             |
| - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | You can add custom payload data as part of an authentication journey that includes the [reCAPTCHA Enterprise node](https://docs.pingidentity.com/auth-node-ref/latest/recaptcha-enterprise.html). Custom data in the journey overrides any custom data added by the client. |

To learn more about the payload, refer to [Project Assessments - Event](https://cloud.google.com/recaptcha/docs/reference/rest/v1/projects.assessments#event) in the Google Developer documentation.

To add custom data for an assessment, pass the `payload` object in the `verify` configuration:

```swift
// Execute reCAPTCHA assessment
let result = await recaptchaCallback.verify { config in
    // Optionally customize the payload
    config.payload = ["firewallPolicyEvaluation": true,
        "transactionData": [
            "transactionId": "TXN-12345",
            "paymentMethod": "CREDIT_CARD",
            "cardBin": "123456",
            "cardLastFour": "1234",
            "currencyCode": "USD",
            "value": 99.99
        ],
        "userInfo": [
            "accountId": "user-abc123",
            "creationMs": "1609459200000"
        ]
    ]
}
```

## Returning custom error codes

You can return a custom error to the node if required for your business logic:

```swift
// Optional custom error code
callback.setClientError("custom_client_error")
```
