React Native Integration (Recommended)

You can integrate the SDK into a React Native project. This article explains how to integrate and implement the HUMAN React Native Wrapper into a React Native app.

Integrate the HUMAN React Native wrapper

  1. In the terminal from the command line, run:
npm install @humansecurity/react-native-sdk
  1. If your app uses iOS, navigate to the ios folder and install pods.
cd ios 
pod install

HUMAN React Native API

The HUMAN Security React Native Wrapper API offers the following functions:

export declare class HumanSecurity {
    static sdkVersion(): string;
    static startWithAppId(appId: string, policy?: HSPolicy): Promise<void>;
    static startWithAppIds(appIds: string[], policy?: HSPolicy): Promise<void>;
    static vid(appId: string): string | null;
    static BD: {
        headersForURLRequest(appId?: string): { [key: string]: string };
        canHandleResponse(response: string): boolean;
        handleResponse(response: string): Promise<HSBotDefenderChallengeResult>;
        challengeReferenceId(): string;
        setCustomParameters(parameters: { [key: string]: string }, appId?: string): Promise<void>;
        onBotDefenderEvent(fn: BotDefenderEventCallback): EventSubscription;
    };
    static AD: {
        setUserId(userId: string | null, appId?: string): Promise<void>;
        registerOutgoingUrlRequest(url: string, appId?: string): Promise<void>;
        setAdditionalData(parameters: { [key: string]: string }, appId?: string): Promise<void>;
    };
}

Start the SDK

The most important step is to start the SDK as early as possible in your app flow. If your app sends a URL request to your server before the SDK starts, the attached headers won’t include the latest updated tokens. As a result, HUMAN’s Enforcer could block the request, and the SDK won’t present a challenge to the user. Be sure to start the SDK only once.

To start the SDK, call startWithAppId in your main entry point (App.tsx) or at the starting point of your app where you register and initialize one-time services. It’s better to start the SDK outside of any UI component to avoid lifecycle issues.

🚧

Warning

Don't forget to change the <APP_ID> to your own application ID.

import HumanSecurity from '@humansecurity/react-native-sdk';

// Initialize the SDK once on app startup
(() => {
  HumanSecurity.startWithAppId("<APP_ID>") // update with your own app ID
    .then(() => {
      console.log("SDK started successfully");
    })
    .catch((error) => {
      console.error("Error starting the SDK:", error);
    });
})();

Policy options

Currently, the HSPolicy class includes two settings:

  1. hybridAppPolicy: Use this if your app operates in hybrid mode, meaning it has a WebView that loads a site also protected by HUMAN and running its sensor. In this case, configure all relevant website domains with the app ID.
  2. detectionPolicy: This setting lets you configure whether the SDK can send touch and motion events, either touch only or both touch and motion, to the server to improve detection. By default, it's off, and you can choose to enable it.

For example:

import HumanSecurity, { HSPolicy } from '@humansecurity/react-native-sdk';

(() => {
  const policy = {
    hybridAppPolicy: {
      webRootDomains: {
        "<APP_ID>": ["my-domain.com"], // update with your own app ID and domain
      },
    },
    detectionPolicy: {
      allowTouchDetection: true,
      allowDeviceMotionDetection: true,
    },
  };

  HumanSecurity.startWithAppId("<APP_ID>", policy) // update with your own app ID
    .then(() => {
      console.log("SDK started successfully with policy");
    })
    .catch((error) => {
      console.error("Error starting the SDK with policy:", error);
    });
})();

Here’s what the code includes:

  1. We start the SDK as soon as possible and only once. You can move this code to a different function or file and export it as long as it’s only called once.
  2. The startWithAppId function of the SDK is called with the following parameters:
    • Your application ID
    • The policy object, if needed
  3. In the second example, an HSPolicy instance configures the SDK’s behavior. This object defines settings such as hybridAppPolicy.webRootDomains, indicating that the app uses WebViews containing pages from a domain also protected by HUMAN Security, which is considered hybrid mode. Additionally, detectionPolicy is configured to send touch and motion data. If these parameters aren’t needed, you can just omit the policy.

📘

Note

If your app communicates with multiple servers that use different application IDs, you can call HumanSecurity/startWithAppIds(appIds: string[], policy?: HSPolicy): Promise<void>. This lets you to pass an array of IDs. If you do, you must specify the relevant ID for each API call to the SDK. If you only have one ID, then providing it in most functions is optional.

Bot Defender integration

Add the SDK’s HTTP headers to your URL requests and handle blocked requests

  • The SDK provides HTTP headers that your app must add to URL requests. It’s essential to include these headers in every request.
  • You shouldn’t cache these HTTP headers. They contain a token with an expiration date, and the SDK keeps it up to date. Ensure the code isn’t cached so that each request triggers a call to the HumanSecurity module.
  • The SDK can handle the blocked request and present a challenge to the user.
  • Ensure that arguments are passed correctly to the wrapper. For example, when using axios, you might need to call JSON.stringify(error.response?.data) before passing the response body to the SDK. Additionally, in Axios, the catch block handles blocked responses because it indicates a failed request.

The following are examples using either a fetch API or using axios.

import HumanSecurity, { HSBotDefenderChallengeResult } from '@humansecurity/react-native-sdk';

public static async fetchData(url: string): Promise<any> {
    try {
        const headers = HumanSecurityManager.getHeaders();

        const response = await fetch(url, { method: 'GET', headers });
        const statusCode = response.status;
        const responseText = await response.text();

        if (statusCode === 200) {
            return { status: statusCode, data: responseText };
        }

        if (HumanSecurityManager.canHandleResponse(responseText)) {
            const result = await HumanSecurityManager.handleResponse(responseText);
            // If challenge was solved, retry the request.
            return { challengeResult: HSBotDefenderChallengeResult[result] };
        }

        throw new Error(`Unhandled response - Status: ${statusCode}`);
    } catch (error) {
        throw error instanceof Error ? error : new Error('Unknown error occurred');
    }
}
import axios, { AxiosInstance, AxiosResponse } from 'axios';
import { HSBotDefenderChallengeResult } from '@humansecurity/react-native-sdk';

public static async fetchDataWithAxios(url: string): Promise<any> {
    try {
        const headers = HumanSecurityManager.getHeaders();
        const response: AxiosResponse = await ApiManager.getInstance().get(url, { headers });
        return { status: response.status, data: response.data };
    } catch (error: any) {
        const statusCode = error.response?.status || 0;
        const responseText = JSON.stringify(error.response?.data) || 'No response data';

        console.log(`Axios call failed - Status: ${statusCode}`);

        if (HumanSecurityManager.canHandleResponse(responseText)) {
            const result = await HumanSecurityManager.handleResponse(responseText);
            // If challenge was solved, retry the request.
            return { challengeResult: HSBotDefenderChallengeResult[result] };
        } else {
            throw error;
        }
    }
}

Here’s what the code includes:

  1. The SDK provides HTTP headers.
  2. The HTTP headers are added to the URL requests.
  3. The URL request is sent.
  4. In case of an error, the response is sent to the SDK, which checks if it’s a blocked request by calling canHandleResponse. If canHandleResponse returns true, handleResponse is called to present the challenge to the user.
  5. The challenge result HSBotDefenderChallengeResult can be one of the following:
    • SOLVED: The user successfully completed the challenge.
    • CANCELED: The user dismissed or failed to complete the challenge.
    • FAILED: The SDK was unable to handle the response, usually indicating that something wasn't passed correctly to the handleResponse function.

Note that you can await handleResponse, but if you do, you would be waiting until the user solves the challenge. You can also continue your flow and handle the result in the .then block.

What to do when a request is blocked

  • Handle it as a failure. Your app should treat the blocked request as a failure. However, keep in mind that your app’s UI will be shown again after the user has solved or canceled the challenge. If the request was triggered by a user action, you should make it clear that the user may try again.
  • Use the promise result to write analytics, logs, etc.
  • You may use the returned promise to retry the original request when appropriate. Consider the following:
    • The promise returns out of the original request’s scope. Make sure you handle that case correctly.
    • The user might cancel the challenge. In this case, you shouldn’t retry the request because it would be blocked again.
    • The retry attempt might fail. Don’t assume it will be successful.

Understanding the block response

When HUMAN's Enforcer blocks a request, it returns a JSON string in the response body with status code 403. This body contains metadata for the SDK. For example:

{
  "vid": "928d7ab3-9cf1-11ee-a624-b802520f369f",
  "uuid": "fd01e6d6-9cf2-11ee-808c-acde48001122",
  "page": "...",
  "appId": "PXj9y4Q8Em",
  "action": "captcha",
  "collectorUrl": "https://collector-pxj9y4q8em.perimeterx.net"
}

Your app should pass the entire JSON as response in a string format to the SDK. Otherwise, the SDK won’t present a challenge to the user.

HumanSecurity.BD.handleResponse(response: string): Promise<HSBotDefenderChallengeResult>

Set custom parameters for Bot Defender (optional)

You can set custom parameters to configure HUMAN's backend with additional values. To do so:

  • Set those parameters as an object in JavaScript using keys in the format custom_param_[x], where [x] is a number between 1 and 10.
  • Call setCustomParameters after calling startWithAppId.

For example:

import HumanSecurity from '@humansecurity/react-native-sdk';

const setCustomParams = () => {
  const parameters = { custom_param_1: 'value1', custom_param_2: 'value2' };

  HumanSecurity.BD.setCustomParameters(parameters, appId)
    .then(() => {
      setCustomParamsResult('Custom Parameters Set Successfully');
    })
    .catch((error) => {
      setCustomParamsResult('Failed to Set Custom Parameters: ' + error);
    });
};

Bot Defender delegates

Bot Defender provides several delegates, or callbacks, to notify about events related to headers and challenges. These callbacks are mainly intended for analytics and statistics rather than for taking specific actions. In the Expo library, these callbacks work as events.

To listen for Bot Defender events, subscribe to the onBotDefenderEvent listener. The received event will be of type BotDefenderEvent and can be handled as needed.

useEffect(() => {
  const subscription = HumanSecurity.BD.onBotDefenderEvent((event) => {
    console.log(
      `[HumanSdk] Event received: ${event.event} | AppID: ${event.appId} | Headers: ${JSON.stringify(event.headers)}`
    );
  });
  return () => {
    subscription.remove();
  };
}, []);

BotDefenderEvent structure and event options

Only the botDefenderDidUpdateHeaders event provides headers. The rest have the app ID.

export interface BotDefenderEvent {
  event:
    | 'botDefenderRequestBlocked'
    | 'botDefenderChallengeSolved'
    | 'botDefenderChallengeCancelled'
    | 'botDefenderChallengeRendered'
    | 'botDefenderChallengeRenderFailed'
    | 'botDefenderDidUpdateHeaders';
  appId: string;
  headers?: { [key: string]: string };
}

Account Defender integration

Enable Account Defender in your app

To enable Account Defender, you should set the UserID of your current logged-in user in the SDK. When the user logs out, make sure to call the function with null to clear the user ID. For example:

import HumanSecurity from '@humansecurity/react-native-sdk';

const setUserId = (userId: string) => {
  HumanSecurity.AD.setUserId(userID, "<APP_ID>") // update with your app ID
    .then(() => {
      setUserIdResult('User ID Set Successfully');
    })
    .catch((error) => {
      setUserIdResult('Failed to Set User ID: ' + error);
    });
};

function onUserLoggedOut() {
  try {
    HumanSecurity.AD.setUserId(null, "<APP_ID>"); // update with your app ID
  } catch (error) {
    console.log(`Exception: ${error.message}`);
  }
}

Notify HUMAN's backend on outgoing URL requests from the app

To let Account Defender protect the user's account, your app must provide the SDK with outgoing URL requests. This should be done after you set the user ID.

import HumanSecurity from "@humansecurity/react-native-sdk";

...
   // In your sendAPIRequest function

    const headers = HumanSecurity.BD.headersForURLRequest(appId);

    // Add this for account defender
      HumanSecurity.AD.registerOutgoingUrlRequest(url, appId).catch((error) => {
      console.log('Error registering outgoing url request: ', error);
    });

    const response = await fetch(url, {
      method: "GET",
      headers,
    });

...

You should call the HumanSecurity.AD.registerOutgoingUrlRequest(url: string, appId?: string): Promise<void> function before sending the URL request. If you're using a custom HttpClient service, add this function to the request interceptor.

Set additional data (optional)

You can set additional data to configure HUMAN's backend with extra parameters. To do so, call HumanSecurity.AD.setAdditionalData(parameters: { [key: string]: string }, appId?: string): Promise<void> after calling HumanSecurity.startWithAppId(appId: string, policy?: HSPolicy): Promise<void>.

For example:

import HumanSecurity from "@humansecurity/react-native-sdk";

const setAdditionalData = async () => {
  const parameters = { key1: 'value1', key2: 'value2' };
  HumanSecurity.AD.setAdditionalData(parameters, appId).then(
    () => {
      setAdditionalDataResult('Additional Data Set Successfully');
    },
    (error) => {
      setAdditionalDataResult('Failed to Set Additional Data' + error);
    }
  );
};

Simulate a challenge

You can simulate a challenge to test the integration. To do so, follow the steps in our help article.