> This page is for Applications Protection.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.humansecurity.com/llms.txt.

# Native - Advanced Functionality

# Integrating the SDK into Your Native iOS/Android App

## Introduction

In this article, we will learn how to integrate the SDK into your native iOS or Android app.

### Highlights

* **Handle Blocked Requests with Challenge Results:**
  * **Benefits:**
    * Great for analytics, logs, etc.
    * Enables sending the URL request again.
* **Automatic Retry Option:**
  * Option to retry the blocked request automatically after the challenge is solved.
* **URL Request Interception:**
  * The SDK intercepts your URL requests.

**Notes:**

* **Android:** Requires your app to use [OkHttp](https://square.github.io/okhttp/) which supports [Interceptors](https://square.github.io/okhttp/features/interceptors/).
* **iOS:** Requires your app to use [`URLSession`](https://developer.apple.com/documentation/foundation/urlsession) or any third-party library based on it.

### Topics Covered

* [How to Start the SDK](#how-to-start-the-sdk)
* [Bot Defender Integration](#bot-defender-integration)
  * Adding SDK's HTTP headers to your URL requests
  * Presenting a challenge to the user
  * Handling the challenge's result
  * Setting custom parameters (optional)
* [Account Defender Integration](#account-defender-integration)
  * Enabling Account Defender
  * Notifying HUMAN's backend on outgoing URL requests
  * Setting additional data (optional)

## How to Start the SDK

* **Initialize Early:** Start the SDK as soon as possible in your app's lifecycle to ensure all URL requests include the SDK's HTTP headers. Delaying SDK initialization may result in requests being blocked by HUMAN's Enforcer.
  * **Android:** Initialize in the `Application`'s `onCreate` method.
  * **iOS:** Initialize in the `AppDelegate`'s `didFinishLaunchingWithOptions` method.
* **Main Thread:** Start the SDK on the **main thread**.
* **Domain Specification:** Specify which domains the SDK should intercept. If no domains are specified, **all domains** will be intercepted. The SDK checks if the URL's domain ends with one of the specified domains (e.g., setting `example.com` will also intercept `www.example.com` and `api.example.com`).

### Example Implementation

#### Android

**Kotlin:**

```kotlin
import android.app.Application
import com.humansecurity.mobile_sdk.HumanSecurity
import com.humansecurity.mobile_sdk.main.policy.HSPolicy
import com.humansecurity.mobile_sdk.main.policy.HSAutomaticInterceptorType

class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        startHumanSDK()
    }

    private fun startHumanSDK() {
        try {
            val policy = HSPolicy().apply {
                automaticInterceptorPolicy.interceptorType = HSAutomaticInterceptorType.INTERCEPT_WITH_DELAYED_RESPONSE // or INTERCEPT_AND_RETRY_REQUEST
                automaticInterceptorPolicy.setInterceptedDomains(setOf("example.com"), "<APP_ID>")
            }

            HumanSecurity.start(this, "<APP_ID>", policy)
        } catch (exception: Exception) {
            println("Exception: ${exception.message}")
        }
    }
}
```

**Java:**

```java
import android.app.Application;
import android.util.Log;
import java.util.HashSet;
import com.humansecurity.mobile_sdk.HumanSecurity;
import com.humansecurity.mobile_sdk.main.policy.HSPolicy;
import com.humansecurity.mobile_sdk.main.policy.HSAutomaticInterceptorType;

public class MainApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        startHumanSDK();
    }

    void startHumanSDK() {
        try {
            HSPolicy policy = new HSPolicy();
            policy.getAutomaticInterceptorPolicy().setInterceptorType(HSAutomaticInterceptorType.INTERCEPT_WITH_DELAYED_RESPONSE); // or INTERCEPT_AND_RETRY_REQUEST

            HashSet<String> domains = new HashSet<>();
            domains.add("example.com");
            policy.getAutomaticInterceptorPolicy().setInterceptedDomains(domains, "<APP_ID>");

            HumanSecurity.INSTANCE.start(this, "<APP_ID>", policy);
        } catch (Exception exception) {
            Log.e("MainApplication", "Exception: " + exception.getMessage());
        }
    }
}
```

#### iOS

**Swift:**

```swift
import UIKit
import HUMAN

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        startHumanSDK()
        return true
    }

    func startHumanSDK() {
        do {
            let policy = HSPolicy()
            policy.automaticInterceptorPolicy.interceptorType = .interceptWithDelayedResponse // or .interceptAndRetryRequest
            policy.automaticInterceptorPolicy.set(interceptedDomains: ["example.com"], forAppId: "<APP_ID>")
            HSAutomaticInterceptorPolicy.urlSessionRequestTimeout = 10 // Set the timeout you would like for your requests.

            try HumanSecurity.start(appId: "<APP_ID>", policy: policy)
        } catch {
            print("Error: \(error)")
        }
    }
}
```

**Objective-C:**

```objc
@import HUMAN;

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self startHumanSDK];
    return YES;
}

- (void)startHumanSDK {
    HSPolicy *policy = [[HSPolicy alloc] init];
    policy.automaticInterceptorPolicy.interceptorType = HSAutomaticInterceptorTypeInterceptWithDelayedResponse; // or HSAutomaticInterceptorTypeInterceptAndRetryRequest
    [policy.automaticInterceptorPolicy setWithInterceptedDomains:[NSSet setWithObject:@"example.com"] forAppId:@"<APP_ID>"];
    HSAutomaticInterceptorPolicy.urlSessionRequestTimeout = 10; // Set the timeout you would like for your requests.

    NSError *error = nil;
    [HumanSecurity startWithAppId:@"<APP_ID>" policy:policy error:&error];
    if (error != nil) {
        NSLog(@"Error: %@", error);
    }
}

@end
```

**Important:** Don't forget to replace `<APP_ID>` with your actual AppID.

### Explanation of the Code

1. **Initialization:** Start the SDK as early as possible on the main thread to ensure all URL requests include the necessary HTTP headers.
2. **Policy Configuration:** Create an `HSPolicy` instance to configure the SDK's behavior. Set the `automaticInterceptorPolicy.interceptorType` to `INTERCEPT_WITH_DELAYED_RESPONSE` or `INTERCEPT_AND_RETRY_REQUEST` to enable the *Automatic Interception* feature of the SDK. Also, specify the domains your app will interact with.
3. **Starting the SDK:** Call the `HumanSecurity.start(appId:policy:)` function with the application instance (Android only), your AppID, and the configured policy.

**Notes:**

* **iOS:** The Automatic Interception uses `URLSessionConfiguration.default`. If your app uses a custom configuration, set it in the policy using `HSAutomaticInterceptorPolicy.urlSessionConfiguration`.
* **Multiple AppIDs:** If your app communicates with multiple servers having different AppIDs, use the `HumanSecurity.start(appIds:policy:)` function to pass an array of AppIDs and specify the relevant AppID for each API call.

## Bot Defender Integration

### How to Add SDK’s HTTP Headers to Your URL Requests and Handle Blocked Requests

* **Automatic Header Addition:** The SDK adds its HTTP headers to your URL requests automatically. **It is essential that these HTTP headers are included in every URL request.**
* **No Caching of Headers:** Do **not** cache these HTTP headers as they contain a token with an expiration date. The SDK manages this token to ensure it is always up-to-date.
* **Automatic Handling of Blocked Requests:** The SDK handles blocked requests and presents a challenge to the user automatically.
* **Custom Error Responses:** The SDK provides a custom error response directly to your request handler **after** the challenge is solved or canceled.
* **Disable Request Timeout:**
  * **iOS:** Set the request timeout to `0` or configure `HSAutomaticInterceptorPolicy.urlSessionRequestTimeout` to your desired timeout.
  * **Android:** Set the call/request timeout to `0` (which is also the default value) and configure connectTimeout and read/write timeout as needed.

### Example Implementation

#### Android

In this example, we assume your app uses [OkHttp](https://square.github.io/okhttp/) or [Ktor](https://ktor.io/). We recommend creating a custom [Interceptor](https://square.github.io/okhttp/features/interceptors/) for this task. However, you may use any HTTP client of your choice and implement the same logic.

**Kotlin (OkHttp):**

```kotlin
import com.humansecurity.mobile_sdk.HumanSecurity
import com.humansecurity.mobile_sdk.main.HSBotDefenderErrorType
import okhttp3.OkHttpClient
import okhttp3.Request
import java.util.concurrent.TimeUnit

class MyHttpClient {

    private val okHttpClient: OkHttpClient = OkHttpClient.Builder()
        .callTimeout(0, TimeUnit.SECONDS)
        .addInterceptor(HSInterceptor()) // SHOULD BE THE LAST INTERCEPTOR
        .build()

    fun sendRequest(url: String) {
        try {
            val request: Request = Request.Builder().url(url).build()
            okHttpClient.newCall(request).execute().use { response ->
                if (!response.isSuccessful) {
                    response.body?.string()?.let { responseBody ->
                        when (HumanSecurity.BD.errorType(responseBody)) {
                            HSBotDefenderErrorType.CHALLENGE_WAS_SOLVED -> {
                                println("Challenge was solved")
                            }
                            HSBotDefenderErrorType.CHALLENGE_WAS_CANCELLED -> {
                                println("Challenge was cancelled")
                            }
                            else -> {
                                println("Unknown error")
                            }
                        }
                    }
                }
            }
        } catch (exception: Exception) {
            println("Request failed. Exception: $exception")
        }
    }
}
```

**Kotlin (Ktor):**

```kotlin
import com.humansecurity.mobile_sdk.HumanSecurity
import com.humansecurity.mobile_sdk.main.HSBotDefenderErrorType
import com.humansecurity.mobile_sdk.main.HSInterceptor
import io.ktor.client.*
import io.ktor.client.call.body
import io.ktor.client.engine.okhttp.*
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.request.*
import io.ktor.client.statement.*

class MyHttpClient {

    private val httpClient: HttpClient = HttpClient(OkHttp) {
        install(HttpTimeout) {
            requestTimeoutMillis = HttpTimeout.INFINITE_TIMEOUT_MS
        }
        engine {
            addInterceptor(HSInterceptor()) // SHOULD BE THE LAST INTERCEPTOR
        }
    }

    suspend fun sendRequest(url: String) {
        try {
            val response: HttpResponse = httpClient.request(url) {}
            val responseBody = response.body<String>()
            when (HumanSecurity.BD.errorType(responseBody)) {
                HSBotDefenderErrorType.CHALLENGE_WAS_SOLVED -> {
                    println("Challenge was solved")
                }
                HSBotDefenderErrorType.CHALLENGE_WAS_CANCELLED -> {
                    println("Challenge was cancelled")
                }
                else -> {
                    println("Unknown error")
                }
            }
        } catch (exception: Exception) {
            println("Request failed. Exception: $exception")
        }
    }
}
```

**Java:**

```java
import com.humansecurity.mobile_sdk.HumanSecurity;
import com.humansecurity.mobile_sdk.main.HSInterceptor;
import android.util.Log;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import java.util.concurrent.TimeUnit;

public class MyHttpClient {

    private final OkHttpClient httpClient = new OkHttpClient.Builder()
            .callTimeout(0, TimeUnit.SECONDS)
            .addInterceptor(new HSInterceptor()) // SHOULD BE THE LAST INTERCEPTOR
            .build();

    void sendRequest(String url) {
        Runnable r = () -> {
            try {
                Request request = new Request.Builder().url(url).build();
                Response response = httpClient.newCall(request).execute();
                ResponseBody responseBody = response.body();
                String responseString = null;
                if (responseBody != null) {
                    responseString = responseBody.string();
                    response.close();
                }
                if (!response.isSuccessful() && responseString != null) {
                    switch (HumanSecurity.INSTANCE.getBD().errorType(responseString)) {
                        case CHALLENGE_WAS_SOLVED:
                            Log.i("MyHttpClient", "Challenge was solved");
                            break;
                        case CHALLENGE_WAS_CANCELLED:
                            Log.i("MyHttpClient", "Challenge was cancelled");
                            break;
                        default:
                            Log.i("MyHttpClient", "Unknown error");
                            break;
                    }
                }
            } catch (Exception exception) {
                Log.i("MyHttpClient", "Request failed. Exception: " + exception);
            }
        };
        new Thread(r).start();
    }
}
```

#### iOS

**Using `URLSession`:**

**Swift:**

```swift
import HUMAN

class MyHttpClient {

    func sendUrlRequest(url: URL) {
        var request = URLRequest(url: url)
        request.timeoutInterval = 0 // Disable timeout

        // Configure your request...

        let dataTask = URLSession.shared.dataTask(with: request) { data, response, error in
            if let error {
                let errorType = HumanSecurity.BD.errorType(error: error)
                switch errorType {
                case .challengeWasSolved:
                    print("Challenge was solved")
                case .challengeWasCancelled:
                    print("Challenge was cancelled")
                default:
                    print("Unknown error")
                }
            }
        }
        dataTask.resume()
    }
}
```

**Objective-C:**

```objc
@import HUMAN;

@implementation MyHttpClient

- (void)sendUrlRequest:(NSURL *)url {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.timeoutInterval = 0; // Disable timeout

    // Configure your request...

    NSURLSessionDataTask *dataTask = [NSURLSession.sharedSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error != nil) {
            HSBotDefenderErrorType errorType  = [HumanSecurity.BD errorTypeWithError:error];
            switch (errorType) {
                case HSBotDefenderErrorTypeChallengeWasSolved:
                    NSLog(@"Challenge was solved");
                    break;
                case HSBotDefenderErrorTypeChallengeWasCancelled:
                    NSLog(@"Challenge was cancelled");
                    break;
                default:
                    NSLog(@"Unknown error");
                    break;
            }
        }
    }];
    [dataTask resume];
}

@end
```

**Using Alamofire:**

**Swift:**

```swift
import Alamofire
import HUMAN

class MyHttpClient {

    func sendUrlRequest(url: URL) {
        AF.request(url) { $0.timeoutInterval = 0 } // Disable timeout
            .response { response in
                if let error = response.error?.underlyingError {
                    let errorType = HumanSecurity.BD.errorType(error: error)
                    switch errorType {
                    case .challengeWasSolved:
                        print("Challenge was solved")
                    case .challengeWasCancelled:
                        print("Challenge was cancelled")
                    default:
                        print("Unknown error")
                        break
                    }
                }
            }
    }
}
```

### Explanation of the Code

1. **Disable Request Timeout:**
   * **iOS:** Set `request.timeoutInterval` to `0` or configure `HSAutomaticInterceptorPolicy.urlSessionRequestTimeout` to your desired timeout.
   * **Android:** Set the call/request timeout to `0` (default value) and configure `connectTimeout` and `read/write timeout` as needed.
2. **Adding HTTP Headers:**
   * The SDK automatically adds its HTTP headers to your URL requests via the `HSInterceptor`. Ensure that this interceptor is the **last** in the interceptor chain.
3. **Sending the Request:**
   * Execute the URL request using your configured HTTP client.
4. **Handling the Response:**
   * The SDK provides a custom error response after the challenge is solved or canceled. Check the error type to determine the challenge result (`CHALLENGE_WAS_SOLVED` or `CHALLENGE_WAS_CANCELLED`).
   * **Note:** When `HSAutomaticInterceptorType` is set to `INTERCEPT_AND_RETRY_REQUEST`, the SDK will resend the blocked request after the challenge is solved. However, the second request could still be blocked, and the SDK won't resend it again.

**Important:** Handle the challenge result appropriately, considering scenarios where the challenge is canceled or the retry attempt fails.

### What to Do When a Request Is Blocked

* **Handle as a Failure:**
  * Treat blocked requests as failures. After the challenge is solved, you may resend the request.
  * If the request was triggered by a user's action, inform the user that they can retry the same action.
* **Use Handler Callback for Analytics:**
  * Utilize the handler callback to log analytics, create logs, etc.
* **Optional Request Retry:**
  * You may use the handler callback to retry the original request when appropriate. Consider the following:
    1. **Callback Scope:** The callback is called outside the original request's scope. Ensure your app handles this correctly.
    2. **Challenge Cancellation:** If the challenge is canceled by the user, do not retry the request to avoid it being blocked again.
    3. **Retry Block Possibility:** The retry attempt may also be blocked. Do not assume it will succeed.

### Understanding the Block Response

1. **Enforcer Decision:**

   * When HUMAN's Enforcer decides to block a request, it returns a JSON string in the response body with an HTTP status code of `403`. Example response:

   ```json
   {
     "vid": "928d7ab3-9cf1-11ee-a624-b802520f369f",
     "appId": "PXj9y4Q8Em",
     "action": "captcha",
     "collectorUrl": "https://collector-pxj9y4q8em.perimeterx.net"
   }
   ```

   **Note:** This JSON contains metadata for the SDK.

2. **Passing Response to SDK:**
   * Your app should pass the entire JSON response to the SDK via the `HSBotDefender.handleResponse(response:data:callback:)` function. If not, the SDK won't present a challenge to the user.

### Setting Custom Parameters for Bot Defender (Optional)

You can configure HUMAN's backend with additional parameters by setting custom parameters.

* **Android:** Use a `HashMap<String, String>`.
* **iOS:** Use a `Dictionary<String, String>`.

**Key Format:** Use keys in the format `custom_param[x]`, where `[x]` is a number between `1-10`.

**Important:** Call the `HSBotDefender.setCustomParameters(parameters:forAppId:)` function **only after** the `HumanSecurity.start(appId:policy:)` function has been called.

#### Example Implementation

##### Android

**Kotlin:**

```kotlin
import com.humansecurity.mobile_sdk.HumanSecurity

fun setCustomParametersForBotDefender() {
    try {
        val customParameters = HashMap<String, String>().apply {
            put("custom_param1", "hello")
            put("custom_param2", "world")
        }
        HumanSecurity.BD.setCustomParameters(customParameters, "<APP_ID>")
    } catch (exception: Exception) {
        println("Exception: ${exception.message}")
    }
}
```

**Java:**

```java
import com.humansecurity.mobile_sdk.HumanSecurity;
import java.util.HashMap;
import android.util.Log;

void setCustomParametersForBotDefender() {
    try {
        HashMap<String, String> customParameters = new HashMap<>();
        customParameters.put("custom_param1", "hello");
        customParameters.put("custom_param2", "world");
        HumanSecurity.INSTANCE.getBD().setCustomParameters(customParameters, "<APP_ID>");
    } catch(Exception exception) {
        Log.e("MainApplication", "Exception: " + exception.getMessage());
    }
}
```

##### iOS

**Swift:**

```swift
import HUMAN

func setCustomParametersForBotDefender() {
    do {
        let customParameters: [String: String] = [
            "custom_param1": "hello",
            "custom_param2": "world"
        ]
        try HumanSecurity.BD.setCustomParameters(parameters: customParameters, forAppId: "<APP_ID>")
    } catch {
        print("Error: \(error)")
    }
}
```

**Objective-C:**

```objc
@import HUMAN;

- (void)setCustomParametersForBotDefender {
    NSMutableDictionary<NSString *, NSString *> *customParameters = [[NSMutableDictionary alloc] init];
    customParameters[@"custom_param1"] = @"hello";
    customParameters[@"custom_param2"] = @"world";

    NSError *error = nil;
    [HumanSecurity.BD setCustomParametersWithParameters:customParameters forAppId:@"<APP_ID>" error:&error];
    if (error != nil) {
        NSLog(@"Error: %@", error);
    }
}
```

## Account Defender Integration

### How to Enable Account Defender in Your App

To enable Account Defender, set the `UserID` of the currently logged-in user in the SDK.

#### Example Implementation

##### Android

**Kotlin:**

```kotlin
import com.humansecurity.mobile_sdk.HumanSecurity

fun onUserLoggedIn(userID: String) {
    try {
        HumanSecurity.AD.setUserId(userID, "<APP_ID>")
    } catch (exception: Exception) {
        println("Exception: ${exception.message}")
    }
}
```

**Java:**

```java
import com.humansecurity.mobile_sdk.HumanSecurity;
import android.util.Log;

void onUserLoggedIn(String userID) {
    try {
        HumanSecurity.INSTANCE.getAD().setUserId(userID, "<APP_ID>");
    } catch(Exception exception) {
        Log.e("MainApplication", "Exception: " + exception.getMessage());
    }
}
```

##### iOS

**Swift:**

```swift
import HUMAN

func onUserLoggedIn(userID: String) {
    do {
        try HumanSecurity.AD.setUserId(userId: userID, forAppId: "<APP_ID>")
    } catch {
        print("Error: \(error)")
    }
}
```

**Objective-C:**

```objc
@import HUMAN;

- (void)onUserLoggedIn:(NSString *)userID {
    NSError *error = nil;
    [HumanSecurity.AD setUserIdWithUserId:userID forAppId:@"<APP_ID>" error:&error];
    if (error != nil) {
        NSLog(@"Error: %@", error);
    }
}
```

### How to Notify HUMAN's Backend on Outgoing URL Requests from the App

To enable Account Defender to protect the user's account, your app must provide the SDK with outgoing URL requests.

**Note:** While the SDK's interceptor is enabled, the SDK automatically collects your outgoing URL requests. **No manual API calls are required.**

#### Android

In this example, we assume your app uses [OkHttp](https://square.github.io/okhttp/) or [Ktor](https://ktor.io/). We recommend creating a custom [Interceptor](https://square.github.io/okhttp/features/interceptors/) for this task. However, you may use any HTTP client of your choice and implement the same logic.

**Kotlin:**

```kotlin
import com.humansecurity.mobile_sdk.HumanSecurity
import okhttp3.Interceptor
import okhttp3.Response

class AccountDefenderInterceptor : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        try {
            HumanSecurity.AD.registerOutgoingUrlRequest(request.url.toString(), "<APP_ID>")
        } catch (exception: Exception) {
            println("Exception: ${exception.message}")
        }
        return chain.proceed(request)
    }
}
```

**Kotlin (OkHttp):**

```kotlin
import okhttp3.OkHttpClient
import okhttp3.Request

class MyHttpClient {

    private val okHttpClient: OkHttpClient = OkHttpClient.Builder()
        .addInterceptor(AccountDefenderInterceptor())
        .build()

    fun sendRequest(url: String) {
        try {
            val request: Request = Request.Builder().url(url).build()
            okHttpClient.newCall(request).execute().use { response ->
                // Handle the response...
            }
        } catch (exception: Exception) {
            println("Request failed. Exception: $exception")
        }
    }
}
```

**Kotlin (Ktor):**

```kotlin
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
import io.ktor.client.request.*
import io.ktor.client.statement.*

class MyHttpClient {

    private val httpClient: HttpClient = HttpClient(OkHttp) {
        engine {
            addInterceptor(AccountDefenderInterceptor())
        }
    }

    suspend fun sendRequest(url: String) {
        try {
            val response: HttpResponse = httpClient.request(url) {}
            // Handle the response...
        } catch (exception: Exception) {
            println("Request failed. Exception: $exception")
        }
    }
}
```

**Java:**

```java
import com.humansecurity.mobile_sdk.HumanSecurity;
import android.util.Log;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class AccountDefenderInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        try {
            HumanSecurity.INSTANCE.getAD().registerOutgoingUrlRequest(request.url().toString(), "<APP_ID>");
        } catch (Exception exception) {
            Log.i("AccountDefenderInterceptor", "Exception: " + exception.getMessage());
        }
        return chain.proceed(request);
    }
}
```

```java
import android.util.Log;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class MyHttpClient {

    private final OkHttpClient httpClient = new OkHttpClient.Builder()
            .addInterceptor(new AccountDefenderInterceptor())
            .build();

    void sendRequest(String url) {
        Runnable r = () -> {
            try {
                Request request = new Request.Builder().url(url).build();
                Response response = httpClient.newCall(request).execute();
                // Handle the response...
            } catch (Exception exception) {
                Log.i("MyHttpClient", "Request failed. Exception: " + exception);
            }
        };
        new Thread(r).start();
    }
}
```

#### iOS

**Swift:**

```swift
import HUMAN

class MyHttpClient {

    func sendUrlRequest(url: URL) {
        do {
            try HumanSecurity.AD.registerOutgoingUrlRequest(url: url.absoluteString, forAppId: "<APP_ID>")
        } catch {
            print("Error: \(error)")
        }

        // Send the request...
    }
}
```

**Objective-C:**

```objc
@import HUMAN;

@implementation MyHttpClient

- (void)sendUrlRequest:(NSURL *)url {
    NSError *error = nil;
    [HumanSecurity.AD registerOutgoingUrlRequestWithUrl:url.absoluteString forAppId:@"<APP_ID>" error:&error];
    if (error != nil) {
        NSLog(@"Error: %@", error);
    }

    // Send the request...
}

@end
```

### Setting Additional Data for Account Defender (Optional)

You can configure HUMAN's backend with additional parameters by setting additional data.

* **Android:** Use a `HashMap<String, String>`.
* **iOS:** Use a `Dictionary<String, String>`.

**Important:** Call the `HSAccountDefender.setAdditionalData(parameters:forAppId:)` function **only after** the `HumanSecurity.start(appId:policy:)` function has been called.

#### Example Implementation

##### Android

**Kotlin:**

```kotlin
import com.humansecurity.mobile_sdk.HumanSecurity

fun setAdditionalDataForAccountDefender() {
    try {
        val additionalData = HashMap<String, String>().apply {
            put("my_key1", "hello")
            put("my_key2", "world")
        }
        HumanSecurity.AD.setAdditionalData(additionalData, "<APP_ID>")
    } catch (exception: Exception) {
        println("Exception: ${exception.message}")
    }
}
```

**Java:**

```java
import com.humansecurity.mobile_sdk.HumanSecurity;
import java.util.HashMap;
import android.util.Log;

void setAdditionalDataForAccountDefender() {
    try {
        HashMap<String, String> additionalData = new HashMap<>();
        additionalData.put("my_key1", "hello");
        additionalData.put("my_key2", "world");
        HumanSecurity.INSTANCE.getAD().setAdditionalData(additionalData, "<APP_ID>");
    } catch(Exception exception) {
        Log.e("MainApplication", "Exception: " + exception.getMessage());
    }
}
```

##### iOS

**Swift:**

```swift
import HUMAN

func setAdditionalDataForAccountDefender() {
    do {
        let additionalData: [String: String] = [
            "my_key1": "hello",
            "my_key2": "world"
        ]
        try HumanSecurity.AD.setAdditionalData(parameters: additionalData, forAppId: "<APP_ID>")
    } catch {
        print("Error: \(error)")
    }
}
```

**Objective-C:**

```objc
@import HUMAN;

- (void)setAdditionalDataForAccountDefender {
    NSMutableDictionary<NSString *, NSString *> *additionalData = [[NSMutableDictionary alloc] init];
    additionalData[@"my_key1"] = @"hello";
    additionalData[@"my_key2"] = @"world";

    NSError *error = nil;
    [HumanSecurity.AD setAdditionalDataWithParameters:additionalData forAppId:@"<APP_ID>" error:&error];
    if (error != nil) {
        NSLog(@"Error: %@", error);
    }
}
```