iOS Mobile SDK

Introduction

Arkose Labs' mobile SDK lets you wrap our solution with iOS native function calls. This guarantees seamless integration of your mobile apps with Arkose's full interactive challenges on detection and enforcement, and does so without the extended wait times for separate mobile solutions.

This page covers the Mobile SDK for iOS. If you are developing in Android, see the Mobile SDK for Android page.

The Arkose Mobile SDK for iOS v1:

  • Wraps Arkose's Advanced Enforcement Challenge in native iOS “web views”.

  • Has 1-to-1 feature availability between web and mobile solutions.

  • Integrates with your apps through native functions.

  • Handles errors through callback events.

  • Complies with Arkose Internal Security guidelines.

  • Complies with Apple App Store guidelines for ease of integration.

  • Is fully compatible with new API releases.

  • Supports minimum version iOS 12.0.

Mobile SDK High Level Design

Mobile SDK Builds Availability

The Arkose Labs Mobile SDKs are available via the Mobile SDK’s Support page. Please talk with your CSM (Customer Success Manager) about your intended usage and to request access.

Compatibility

DeviceMinimum OS VersionTarget OS Versions
iPhoneiOS 12+iOS 12, 13, 14, 15, 16, 17, 18
iPadiPadOS 12+iPadOS 12, 13, 14, 15, 16, 17, 18
MacmacOS 12+macOS 12, 13, 14, 15
Vision OSVision OS 1.3+Vision OS 1.3, 2.0

All existing detection and challenge features on our web solution are also available on the Mobile SDKs. All new ones are automatically added; you don't need to update your application every time we have a new release of our Web platform.

Security

The Arkose Labs Mobile SDKs are Arkose Labs Security reviewed and comply with Apple App Store guidelines.

Performance

We created the Arkose Labs Mobile SDKs with stability and performance in mind. Their use has no significant impact on the host application’s performance.

Installation

Follow these steps to set up Arkose Labs Mobile SDK for iOS in Xcode in your host application. This applies to both our detection and enforcement components.

Prerequisites

  • A host iOS application. You must be able to build and run this application.

  • For the full end-to-end Arkose setup, you must also complete the standard Arkose Server-Side setup instructions.

Integration Steps

Add ArkoseLabsKit to the Project

  1. In Xcode, open your Host application.

  2. From the Project Navigator area, select the folder with your project’s name.

  3. From the project’s xcodeproj details, select Target.

  4. To use the dynamic framework:

    1. Scroll to Frameworks, Libraries, and Embedded Content and drag and drop ALSDK.XCFramework into this section.
    2. In the Project Navigator, find the Frameworks folder and verify ArkoseLabsKit is inside it.
    3. Click on Build Phases to display that tab. Find the Link Binary with Libraries section and confirm it contains the ArkoseLabsKit.xcframework.
  5. To use the static library:

    1. Create a New Folder in your project called ArkoseLabsKitStatic.
    2. Drag and drop all files into the new folder from the SDK build dist folder.
    3. Scroll to Frameworks, Libraries, and Embedded Content and drag and drop:
      1. for iOS Device Support add ArkoseLabsKitStaticiOS.a file in the section
      2. for iOS Simulator Support add ArkoseLabsKitStaticiOSSim.a file in the section
      3. for Mac Support add ArkoseLabsKitStaticMac.a file in the section
    4. In the Copy Bundle Resources section, add ArkoseLabsKitResource.Bundle
  6. Perform a Clean task.

  7. Perform a Build.

Initialize the SDK

To integrate Arkose Bot Manager with the enforce challenge, follow the steps outlined below:

  1. Import the ArkoseLabsKit or ArkoseLabsKitStatic module before invoking any API from the SDK:
// For dynamic framework
import ArkoseLabsKit

// For static framework
//import ArkoseLabsKitStatic
  1. Initialize the SDK as soon as the application launches with the ArkoseConfig object that contains all configuration parameters. We recommend using the UIApplicationDelegate didFinishLaunchingWithOptions notification to do the initialization. A sample initialization code is shown below:

    ArkoseManager.initialize(
        with: ArkoseConfig.Builder(withAPIKey: <YOUR_PUBLIC_KEY>)
                .with(apiBaseUrl: "<Actual API Base URL>") // optional
                .build()
        )
    

    A complete example of didFinishLaunchingWithOptions implementation is below:

    // For dynamic framework
    import ArkoseLabsKit
    
    // For static framework
    //import ArkoseLabsKitStatic
    import SwiftUI
    
    class AppDelegate: NSObject, UIApplicationDelegate {
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
            ArkoseManager.initialize(
                with: ArkoseConfig.Builder(withAPIKey: <YOUR_PUBLIC_KEY>)
                        .with(apiBaseUrl: "<Actual API Base URL>") //optional
                        .with(language: "en") //optional
                        .with(clientAPIRetryCount: 0) //optional
                        .with(styleTheme: "") //optional
                        .build()
                )
            return true
        }
    }
    

Integrate into a SwiftUI Application

  1. To run Arkose Bot Manager and display the Enforcement Challenge in a SwiftUI View, integrate ArkoseChallengeView into the content of your custom view.
ArkoseChallengeView(isPresented: $isPresented, delegate: self, cancelButtonTitle: "Cancel")

See Appendix: SwiftUI Content View below for a complete example.

Integrate into a UIKit Application

  1. To run Arkose Bot Manager and display the Enforcement Challenge from a UIKit ViewController, invoke ArkoseManager.showEnforcementChallenge from an action method.
ArkoseManager.showEnforcementChallenge(
    parent: self,
    delegate: self,
    cancelButtonTitle: "Cancel")

See the Appendix: UIKit View Controller below for a complete example.

Receiving Notifications

To receive notifications about various events triggered by Enforcement Challenge, implement the ArkoseChallengeDelegate protocol on the SwiftUI View or the UIViewController class and pass the instance as the delegate parameter above. To simplify the implementation, ArkoseChallengeDelegate has a default implementation, so implement only the necessary methods for your desired functionality. The most commonly implemented protocol methods are onCompleted, onError, and onFailed to complete the necessary action from the application.

Build the revised project

  1. Perform a Clean.
  2. Perform a Build.

Run and test the application

  1. Run your modified iOS application.
  2. If running Arkose Bot Manager:
    1. On the integrated screen, confirm you now see an Arkose Labs Enforcement Challenge.b. Verify the challenge.
    2. On successful verification, the onCompleted event returns a token as part of the response JSON object.
  3. Send the token to your back-end server for verification.

Update Configuration in the SDK

To update configuration of the SDK any time before the enforcement challenge is called, follow the steps outlined below:

In SwiftUI Application

  1. To run Arkose Bot Manager and display the Enforcement Challenge in a SwiftUI View, integrate ArkoseChallengeView into the content of your custom view.
    ArkoseChallengeView(isPresented: $isPresented,
                                        delegate: self,
                                        cancelButtonTitle: "Cancel",
                                        resetButtonTitle: "Reset",
                                        config:
                                            ArkoseConfig.Builder(
                                                withAPIKey: <YOUR_PUBLIC_KEY>)
                                                .with(language: "en") //optional
                                                .with(clientAPIRetryCount: 0) //optional
                                                .with(styleTheme: "") //optional
                                                .build())
    
    See Appendix: SwiftUI Content View below for a complete example.

In a UIKit Application

  1. To run Arkose Bot Manager and display the Enforcement Challenge from a UIKit ViewController, invoke ArkoseManager.showEnforcementChallenge from an action method.
    ArkoseManager.update(with: 
      ArkoseConfig.Builder(
        withAPIKey: <YOUR_PUBLIC_KEY>)
        .with(language: "fr")
        .build()
        )
    

See the Appendix: UIKit View Controller below for a complete example.


For API Version 2.1.0 and Above

ArkoseConfig.Builder

Arkose Labs Enforcement Challenge configuration parameters can be updated using ArkoseConfig.Builder class. The public methods to specify these parameters are listed below:

  • public init(withAPIKey apiKey: String)
    Initialize the Builder instance with the public key of your account
  • public func with(apiBaseUrl: String) -> Builder
    Base URL of Arkose Labs EC platform as supplied by Arkose Labs.
  • public func with(blob: String) -> Builder
    Specify any encrypted data blobs to share with Arkose Bot Manager. It is optional.
  • public func with(language: String) -> Builder
    Specify any language setting for the Enforcement Challenge, the default value is en. It is optional.
  • public func with(userAgent: String) -> Builder
    Specify any userAgent setting for ease of testing forced Enforcement Challenge for a session, the default value is inbuilt webview’s userAgent. It is optional. Please talk with your CSM (Customer Success Manager) about your intended usage and request backend configuration.
  • public func with(clientAPIRetryCount: Int) -> Builder
    Specify the number of retries when network issues are triggered when the client app tries to connect to the apiBaseUrl.
    The retry only works for onError events with error codes below. When the configured number of retries is exhausted, the last error code is returned.
    • Challenge load error.
    • API_REQUEST_ERROR
    • API_REQUEST_TIMEOUT
      Default: 0. It is optional.
  • public func with(styleTheme: String) -> Builder
    Specify style theme name for Enforcement Challenge. It is optional.
  • public func build() -> ArkoseConfig
    Builds and returns an instance of ArkoseConfig

ArkoseConfig

An instance of ArkoseConfig contains all the configuration parameters, use ArkoseConfig.Builder to class to construct an instance of ArkoseConfig.

ArkoseManager

ArkoseManager class provides public methods to integrate the application with Arkose Bot Manager.

  • public static func initialize (with configuration: ArkoseConfig)
    Initialize Arkose Bot Manager SDK with the configuration parameters.

  • public static func update (with configuration: ArkoseConfig)
    Update Arkose Bot Manager SDK with the configuration parameters.

  • public static func showEnforcementChallenge(parent: UIViewController,
                                                      delegate: ArkoseChallengeDelegate,
                                                      cancelButtonTitle: String? = "Cancel",
                                                      resetButtonTitle: String? = nil,
                                                      withActivity: Bool? = nil)
    
  • Display the Enforcement Challenge View and invokes the ArkoseChallengeDelegate methods to notify the result.

    • parent: An instance of UIViewController where the Enforcement Challenge View is displayed
    • delegate: An instance of ArkoseChallengeDelegate to receive event notifications
    • cancelButtonTitle: A localized string for the title of the Cancel button, the default value is "Cancel".
      If this parameter is set to nil, the Cancel button is not shown in the view.
    • resetButtonTitle: A localize string for the title of the Reset button, the default value is nil.
      If this parameter is set to nil, the Reset button is not shown in the view.
    • withActivity: A bool to control enablement of loading Spinner animation, the default value is true.
      If this parameter is set to nil, the loading Spinner animation is shown in the view.
    • public static var logLevel: LogLevel
      Set the log level for the SDK. All messages logged by the ArkoseLabsKit framework will have the [ArkoseLabsKit] text for easy identification. Valid LogLevel values are: info, warn, error.

ArkoseChallengeView

ArkoseChallengeView is the SwiftUI View component to integrate into the contents of the application View.

public init(isPresented: Binding<Bool>,
                delegate: ArkoseChallengeDelegate,
                cancelButtonTitle: String? = nil,
                resetButtonTitle: String? = nil,
                withActivity: Bool? = nil,
                withActivityBackgroundAlpha: CGFloat = 0.2,
                config: ArkoseConfig? = nil)
  • isPresented: A Bool value that controls the visibility of the Enforcement Challenge View.
  • delegate: An instance of ArkoseChallengeDelegate to receive event notifications.
  • cancelButtonTitle: A localized String for the title of the Cancel button, with a default value of "Cancel". If set to nil, the Cancel button will not be displayed in the view.
  • resetButtonTitle: A localized String for the title of the Reset button, with a default value of nil. If set to nil, the Reset button will not be displayed in the view.
  • withActivity: A Bool that controls the enablement of the loading spinner animation, with a default value of true. If set to nil, the loading spinner animation will be displayed in the view.
  • withActivityBackgroundAlpha: A CGFloat value that sets the background alpha of the activity indicator or loader, ranging from 0.0 (fully transparent) to 1.0 (fully opaque), with a default value of 0.2.
  • config: An ArkoseConfig created using its builder, with a default value of nil. If set to nil, the configuration is not updated with the latest configuration.

LogLevel

LogLevel is an enumeration to control the logs generated by the framework. The valid values are:

  • info: Log messages with severity level of info and above
  • warn: Log messages with severity level of warn and above
  • error: Log messages with severity level of error only

ArkoseChallengeDelegate

ArkoseChallengeDelegate is a protocol to be implemented by the application and passed in showEnforcementChallenge function call to receive notification about different events during Enforcement Challenge View lifecycle.

  • func onReady(): onReady callback is invoked when the Enforcement Challenge or detection is ready.
  • func onShow(): onShow callback is invoked when the Enforcement Challenge is running and our detection component is analyzing the user intent. The function is also invoked when an Enforcement Challenge or detection is re-displayed (e.g. if the user closes the EC or detection view and tries to continue). Applicable to enforcement only.
  • func onShown(): onShown callback is invoked when the Enforcement Challenge is displayed for the first time. Applicable to enforcement only.
  • func onSuppress(): onSuppress callback is invoked when either an Enforcement Challenge is suppressed (i.e. A session was classified as not requiring a challenge) or detection is running and is analyzing the user intent.
  • func onHide():onHide callback is invoked when the EC or detection view is hidden. For example, this happens after an EC or detection is completed or if the user clicks the close button.
  • func onReset():onReset callback is invoked after the Enforcement Challenge is reset. Typically occurs after a challenge has been successfully answered. Applicable to enforcement only.
  • func onCompleted(response: [String: Any?]): onCompleted callback is invoked when a session is classified as not needing a challenge or a detection has been successfully completed.
    A Response Object is passed to this function.
  • func onError(response: [String: Any?]): onError callback is invoked when an error occurs when loading the challenge or detection.
    A Response Object is passed to this function.
  • func onWarning(response: [String: Any?]): onWarning callback is invoked when an issue occurs which needs to be shared with the app as a warning, based on which App can take custom actions, when loading the challenge or detection.
    A Response Object is passed to this function.
  • func onFailed(response: [String: Any?]): onFailed callback is invoked when a challenge has failed (the user has failed the challenge multiple times and is not allowed to continue the session).
    A Response Object is passed to this function. Applicable to enforcement only.

For API Version 2.0.1

Arkose Labs Enforcement Challenge configuration parameters can be updated using ArkoseConfig.Builder class. The public methods to specify these parameters are listed below:

  • public init(withAPIKey apiKey: String)
    Initialize the Builder instance with the public key of your account.
  • public func with(apiBaseUrl: String) -> Builder
    Base URL of Arkose Labs EC platform as supplied by Arkose Labs.
  • public func with(blob: String) -> Builder
    Specify any encrypted data blobs to share with Arkose Bot Manager. It is optional.
  • public func with(language: String) -> Builder 
    Specify any language setting for the Enforcement Challenge, the default value is en. It is optional.
  • public func build() -> ArkoseConfig
    Builds and returns an instance of ArkoseConfig.

ArkoseConfig

An instance of ArkoseConfig contains all the configuration parameters, use ArkoseConfig.Builder class to construct an instance of ArkoseConfig.

ArkoseManager

ArkoseManager class provides public methods to integrate the application with the Arkose Bot Manager.

  • public static func initialize(with configuration: ArkoseConfig)
    Initialize Arkose Bot Manager SDK with the configuration parameters.

  • public static func update(with configuration: ArkoseConfig)
    Update Arkose Bot Manager SDK with the configuration parameters.

  • public static func showEnforcementChallenge(parent: UIViewController,
                                                delegate: ArkoseChallengeDelegate,
                                                cancelButtonTitle: String? = "Cancel",
                                                resetButtonTitle: String? = nil)
    
  • Display the Enforcement Challenge View and invokes the ArkoseChallengeDelegate methods to notify the result.

    • parent: An instance of UIViewController where the Enforcement Challenge View is displayed.
    • delegate: An instance of ArkoseChallengeDelegate to receive event notifications.
    • cancelButtonTitle: A localized string for the title of the Cancel button, the default value is "Cancel". If this parameter is set to nil, the Cancel button is not shown in the view.
    • resetButtonTitle: A localize string for the title of the Reset button, the default value is nil. If this parameter is set to nil, the Resetbutton is not shown in the view.
  • public static var logLevel: LogLevel:
    Set the log level for the SDK. All messages logged by the ArkoseLabsKit framework will have the [ArkoseLabsKit] text for easy identification. Valid LogLevel values are: info, warn, error

ArkoseChallengeView

ArkoseChallengeView is the SwiftUI View component to integrate into the contents of the application view.

public init(isPresented: Binding<Bool>,
            delegate: ArkoseChallengeDelegate,
            cancelButtonTitle: String? = "Cancel",
            resetButtonTitle: String? = nil)
						config: ArkoseCongig? = nil)

isPresented: A boolean value to control the visibility of the Enforcement Challenge View
delegate: An instance of ArkoseChallengeDelegate to receive event notifications
cancelButtonTitle: A localized string for the title of the Cancel button, the default value is "Cancel".
If this parameter is set to nil, the Cancel button is not shown in the view.
resetButtonTitle: A localize string for the title of the Reset button, the default value is nil.
If this parameter is set to nil, the Reset button is not shown in the view.
config: An ArkoseConfig created using it’s builder, the default is nil.
If this parameter is set to nil, the configuration is not updated with latest configuration.

Log Level

LogLevel is an enumeration to control the logs generated by the framework. The valid values are:

  • info: Log messages with severity level of info and above
  • warn: Log messages with severity level of warn and above
  • error: Log messages with severity level of error only

ArkoseChallengeDelegate

ArkoseChallengeDelegate is a protocol to be implemented by the application and passed in showEnforcementChallenge function call to receive notification about different events during Enforcement Challenge View lifecycle.

  • func onReady(): onReady callback is invoked when the Enforcement Challenge or detection is ready.
  • func onShow(): onShow callback is invoked when the Enforcement Challenge is running and our detection component is analyzing the user intent. The function is also invoked when an Enforcement Challenge or detection is re-displayed (e.g. if the user closes the EC or detection view and tries to continue). Applicable to enforcement only.
  • func onShown(): onShown callback is invoked when the Enforcement Challenge is displayed for the first time. Applicable to enforcement only.
  • func onSuppress(): onSuppress callback is invoked when either an Enforcement Challenge is suppressed (i.e. A session was classified as not requiring a challenge) or detection is running and our detection component is analyzing the user intent.
  • func onHide():onHide callback is invoked when the EC or detection view is hidden. For example, this happens after an EC or detection is completed or if the user clicks the close button.
  • func onReset():onReset callback is invoked after the Enforcement Challenge is reset. Typically occurs after a challenge has been successfully answered. Applicable to enforcement only.
  • func onCompleted(response: [String: Any?]): onCompleted callback is invoked when a session is classified as not needing a challenge or a detection has been successfully completed.
  • func onError(response: [String: Any?]): onError callback is invoked when an error occurs when loading the challenge or detection.
    A Response Object is passed to this function.
  • func onWarning(response: [String: Any?]): onWarning callback is invoked when an issue occurs which needs to be shared with the app as a warning, based on which App can take custom actions, when loading the challenge or detection.
    A Response Object is passed to this function.
  • func onFailed(response: [String: Any?]): onFailed callback is invoked when a challenge has failed (the user has failed the challenge multiple times and is not allowed to continue the session).
    A Response Object is passed to this function. Applicable to enforcement only.

For API Version 1.0

Note: Version 1.0 APIs are deprecated starting with ArkoseLabsKit framework 2.0.0, but fully backward compatible with old APIs. But we recommend upgrading to the simplified implementation in 2.0.0 and above.

ALWebView

Configuration ObjectTypeDescription
ALWebViewPublic methodMethod used to start Arkose Bot Manager.

Before this method is called, the model object must be initialized with these three additional configuration parameters detailed in this table.

- webEventDelegate (should be assigned to “receiving component”)

- apiLang

- apiBlob
WebEventDelegatePublic delegate componentLets clients receive callbacks from Arkose Bot Manager.
apiLangStringApplies only to our enforcement component.

Language setting for the Enforcement Challenge.

Default: "en"
apiBlobStringOptional. Mainly used to share any client encrypted data blobs with Arkose Bot Manager.

Default: ""
apiKeyStringOptional. The API_KEY added in Config.plist can be overridden with this value if needed.

Default: ""
resetSessionPublic methodOptional method to reset the current session for Arkose Bot Manager. This creates a new session.

WebEventDelete Protocol

Events CallbackTypeDescription EventApplicable Component
onReadyEventReceives the onReady event callback from the API server.

Invoked when the Enforcement or detection component is ready. The Enforcement or detection cannot be triggered before this event. You may want to disable the UI you are protecting until this event has been triggered.
Detection
Enforcement
onShowEventListener function invoked when the Enforcement is running and our detection component is analyzing the user intent. The function is also invoked when an Enforcement Challenge or detection is re-displayed (e.g. if the user closes the EC or detection view and tries to continue). Note that the close button only appears when in Lightbox mode.Detection
Enforcement
onShownEventFunction only invoked the when the Enforcement Challenge is displayed for the first time.Enforcement
onSuppressEventListener function invoked when either an Enforcement Challenge is suppressed (i.e. A session was classified as not requiring a challenge) or detection is running and our detection component is analyzing the user intent.Detection
Enforcement
onHideEventListener function invoked when the EC or detection view is hidden. For example, this happens after an EC or detection is completed or if the user clicks the close button. Note that the close button only appears when in Lightbox mode.Detection
Enforcement
onResetEventFunction invoked after the Enforcement resets. Typically occurs after a challenge has been successfully answered.Enforcement
onCompletedEventListener function invoked when a session is classified as not needing a challenge or a detection has been successfully completed.

A Response Object is passed to this function.
Detection
Enforcement
onErrorEventFunction invoked when an error occurs when loading the challenge or detection.

A Response Object is passed to this function.
Detection
Enforcement
onWarningEventFunction invoked when an issue occurs which needs to be shared with the app as a warning, based on which App can take custom actions, when loading the challenge or detection.Detection
Enforcement
onFailedEventFunction invoked when a challenge has failed (the user has failed the challenge multiple times and is not allowed to continue the session).

A Response Object is passed to this function.
Enforcement
onResizeEventFunction invoked on a resizing event which provides the new width and height values of the EC due to an SDK call.

A Response Object is passed to this function.
Enforcement

Configuration Parameters

You can change the following configuration parameters by specifying their values in the config.plist file.

Configuration ParametersTypeDescription
API_URL_BASEStringBase URL of Arkose Bot Manager as supplied by Arkose Labs.
API_KEYStringPublic key for your account.
API_FILEStringName of JavaScript file of Arkose Bot Manager as supplied by Arkose Labs.

Config.plist Example

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>VERIFICATION_URL</key>
    <string></string>
    <key>API_KEY</key>
    <!-- Replace <YOUR_PUBLIC_KEY> with the public key that has been setup for your account -->
    <string>YOUR_PUBLIC_KEY</string>
    <key>API_URL_BASE</key>
    <string>https://client-api.arkoselabs.com/v2</string>
    <key>API_FILE</key>
    <string>api.js</string>
</dict>
</plist>


Appendix

Appendix: SwiftUI Content View

import SwiftUI
import ArkoseLabsKit

struct ContentView: View, ArkoseChallengeDelegate {
    
    func onCompleted(response: [String: Any?]) {
        print("onComplete received: \(response)")
        isPresented = false
    }
    
    func onError(response: [String: Any?]) {
        print("onError received: \(response)")
        isPresented = false
    }
    
    func onFailed(response: [String: Any?]) {
        print("onFailed received: \(response)")
        isPresented = false
    }
    
    @State var isPresented = false
    @State var username : String = ""
    @State var password : String = ""
    
    var body: some View {
        ZStack {
            
            VStack {
                Text("SwiftUI App")
                    .padding()
                    .font(.largeTitle)
                    .foregroundColor(Color.black)
                TextField("Username", text: $username)
                    .font(.title3)
                    .disableAutocorrection(true)
                    .autocapitalization(.none)
                    .padding()
                
                SecureField("Password", text: $password)
                    .font(.title3)
                    .disableAutocorrection(true)
                    .autocapitalization(.none)
                    .padding()
                
                Button("Login") {
                    self.isPresented = true
                }
                ArkoseChallengeView(isPresented: $isPresented, 
                                      delegate: self, 
                                      cancelButtonTitle: "Cancel",
                                      resetButtonTitle: "Reset",
                                      config:
                                        ArkoseConfig.Builder(
                                            withAPIKey: "<YOUR_PUBLIC_KEY>") // Replace <YOUR_PUBLIC_KEY> with the actual API key assigned to your account
                                            .with(language: "fr")
                                            .build())
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Appendix: UIKit View Controller

import UIKit
import ArkoseLabsKit

class ViewController: UIViewController, ArkoseChallengeDelegate {
    
    func onCompleted(response: [String: Any?]) {
        print("onComplete received: \(response)")
    }
    
    func onError(response: [String: Any?]) {
        print("onError received: \(response)")
    }
    
    func onFailed(response: [String: Any?]) {
        print("onFailed received: \(response)")
    }
    
    @IBAction func Login(_ sender: Any) {
    // Replace <YOUR_PUBLIC_KEY> with the actual API key assigned to your account
    ArkoseManager.update(with: ArkoseConfig.Builder(withAPIKey: "<YOUR_PUBLIC_KEY>")
            .with(language: "fr")
            .build()
        )
        ArkoseManager.showEnforcementChallenge(
            parent: self,
            delegate: self,
            cancelButtonTitle: "Cancel")
    }
}