Configuring Advanced Features

In this segment we will explore more advanced topics that will help you get the most out of the SDK.


The AppID is the key to start the PerimeterX SDK, by calling the start function with it. If you are using only one AppID in your app, all other functions in the SDK will work properly without specifying the AppID again (you may pass null).


The PerimeterXDelegate provides callbacks, such as request blocked or challenge solved. However, The delegate can be set only once when calling the start function. You can set that more objects in your project to receive those callbacks too. Use the registerCallbackForRequestBlockedEvent, the registerCallbackForChallengeCancelledEvent and the registerCallbackForChallengeSolvedEvent functions. Here is an example:

val requestBlockedEventRegistrationId = PerimeterX.INSTANCE.registerCallbackForRequestBlockedEvent(null) {  
  println("request was blocked")  
val challengeSolvedEventRegistrationId = PerimeterX.INSTANCE.registerCallbackForChallengeSolvedEvent(null) {  
  println("challenge was solved")  
val challengeCancelledEventRegistrationId = PerimeterX.INSTANCE.registerCallbackForChallengeCancelledEvent(null) {  
  println("challenge was cancelled")  
String requestBlockedEventRegistrationId = PerimeterX.INSTANCE.registerCallbackForRequestBlockedEvent(null, () -> {  
    Log.i("tag", "request was blocked");  
    return null;  
String challengeSolvedEventRegistrationId = PerimeterX.INSTANCE.registerCallbackForChallengeSolvedEvent(null, () -> {  
    Log.i("tag", "challenge was solved");  
    return null;  
String challengeCancelledEventRegistrationId = PerimeterX.INSTANCE.registerCallbackForChallengeCancelledEvent(null, () -> {  
    Log.i("tag", "challenge was cancelled");  
    return null;  

The registerCallbackForRequestBlockedEvent, registerCallbackForChallengeSolvedEvent and the registerCallbackForChallengeCancelledEvent functions return a Registration ID. Use it to unregister from getting those callbacks with unregisterCallbackForRequestBlockedEvent, unregisterCallbackForChallengeSolvedEvent and unregisterCallbackForChallengeCancelledEvent functions. Here is an example:

PerimeterX.INSTANCE.unregisterCallbackForRequestBlockedEvent(null, requestBlockedEventRegistrationId)
PerimeterX.INSTANCE.unregisterCallbackForChallengeSolvedEvent(null, challengeSolvedEventRegistrationId)
PerimeterX.INSTANCE.unregisterCallbackForChallengeCancelledEvent(null, challengeCancelledEventRegistrationId)
PerimeterX.INSTANCE.unregisterCallbackForRequestBlockedEvent(null, requestBlockedEventRegistrationId);
PerimeterX.INSTANCE.unregisterCallbackForRequestBlockedEvent(null, challengeSolvedEventRegistrationId);
PerimeterX.INSTANCE.unregisterCallbackForRequestBlockedEvent(null, challengeCancelledEventRegistrationId);

Another important callback is when the Perimeter SDK is ready. Calling the start function will start an async operation that will start the PerimeterX SDK. This function has a completion handler, but you can register to this event from other places in your project, using the addInitializationFinishedCallback function. Here is an example:

PerimeterX.INSTANCE.addInitializationFinishedCallback(null) {  
  println("PerimeterX is ready")  
PerimeterX.INSTANCE.addInitializationFinishedCallback(null, () -> {  
  Log.i("tag", "PerimeterX is ready");  
    return null;  

You can call the addInitializationFinishedCallback when the PerimeterX SDK is ready. In this case, the callback will be called immediately.

Block Error

When the PXPolicy's requestsInterceptedAutomaticallyEnabled is set to true, the PerimeterX SDK will automatically block requests and present a challenge to the end user. When there is a block, the original request will fail with the following Error: domain: PerimeterXErrorDomain, code: PerimeterXErrorCode's requestWasBlocked. You can check the received error with the isRequestBlockedError function. Here is an example:

val isRequestBlockedError = PerimeterX.INSTANCE.isRequestBlockedError(responseString)  
if (isRequestBlockedError) {  
    println("request was blocked by PX")  
boolean isRequestBlockedError = PerimeterX.INSTANCE.isRequestBlockedError(responseString);  
if (isRequestBlockedError) {  
    Log.i("tag", "request was blocked by PX");  

Block response with the challenge result

The SDK automatically intercepts HTTP requests. Once a request is blocked, a "request blocked" error is returned to your handler code, while the user is solving the challenge. However, you can configure the SDK to delay the response until the user solved the challenge (or cancelled it). In this way, you can retry the original request a soon as you get the error (assuming the user solved the challenge) without waiting for this event to be occurred elsewhere in your code.

You can check the error with isChallengeSolvedError and isChallengeCancelledError functions:

val isChallengeSolvedError = PerimeterX.INSTANCE.isChallengeSolvedError(responseString)  
if (isChallengeSolvedError) {  
    println("request was blocked by PX and user solved the challenge")  

val isChallengeCancelledError = PerimeterX.INSTANCE.isChallengeCancelledError(responseString)  
if (isChallengeCancelledError) {  
    println("request was blocked by PX and challenge was cancelled")  
boolean isChallengeSolvedError = PerimeterX.INSTANCE.isChallengeSolvedError(responseString);  
if (isChallengeSolvedError) {  
    Log.i("tag", "request was blocked by PX and user solved the challenge");  

boolean isChallengeCancelledError = PerimeterX.INSTANCE.isChallengeCancelledError(responseString);  
if (isChallengeCancelledError) {  
    Log.i("tag", "request was blocked by PX and challenge was cancelled");  

To enable this feature (disabled by default) you should configure it in the policy:

val policy = PXPolicy()  
policy.delayResponseUntilChallengeSolvedOrCancelled = true  
PerimeterX.INSTANCE.setPolicy(policy, null)
PXPolicy nativePolicy = new PXPolicy();  
PerimeterX.INSTANCE.setPolicy(policy, null);

Notice that enabling this could mean that your request handler code will not be called at all (for example, when the user does not solve the challenge).

Hybrid App

The hybrid App uses both native URL requests and web views to communicate with the server. In the context of PerimeterX, it's important to make sure both native requests and web views are synced together to make sure end users will get the expected behavior from your app. To help PerimeterX SDK achieve that, you should set your domain in the policy for the relevant AppID. Here is an example:

val policy = PXPolicy()"")  
PerimeterX.INSTANCE.setPolicy(policy, null)
PXPolicy policy = new PXPolicy();  
PerimeterX.INSTANCE.setPolicy(policy, null);

In addition, you need to setup your web view with the setupWebView function. The first parameter is the web view instance. The second parameter (optional) is your web view client instance. You should not set your web view client directly to the web view, but using the setupWebView function instead. Here is an example:

PerimeterX.INSTANCE.setupWebView(webView, webViewClient)
PerimeterX.INSTANCE.setupWebView(webView, webViewClient)

Multiple AppIDs

You can configure multiple AppIDs for the PerimeterX SDK, by calling the start function for each AppID you have.

When using multiple AppIDs, you should:

  1. Specify the relevant AppID anytime you call functions in the PerimeterX SDK.

  2. Set the domain list in the policy for each AppID. Here is an example:

val policyForAppId1 = PXPolicy()"")
PerimeterX.INSTANCE.setPolicy(policyForAppId1, "<APP_ID_1>")

val policyForAppId2 = PXPolicy()"")
PerimeterX.INSTANCE.setPolicy(policyForAppId2, "<APP_ID_2>")
PXPolicy policyForAppId1 = new PXPolicy();  
PerimeterX.INSTANCE.setPolicy(policyForAppId1, "<APP_ID_1>");

PXPolicy policyForAppId2 = new PXPolicy();  
PerimeterX.INSTANCE.setPolicy(policyForAppId2, "<APP_ID_2>");

Doctor App

The "Doctor App" is a tool that helps verify the SDK integration in your project by simulating a typical user flow in the application. When the "Doctor app" is enabled, it will pop up as part of the app flow and will guide the developer on simulating a user flow to gather the required information for testing the integration.

The "Doctor App" includes assets that are used for the UI. Those assets are required only for the "Doctor App" usage and are not needed in your app production build. In order minimize the SDK footprint, those assets are loaded dynamically in run time (from v2.1.0).

If you run the "Doctor App", those assets will be loaded automatically (internet connection is required).

In order to enable this feature, call the start function with the enableDoctorCheck as true. Here is an example:

PerimeterX.INSTANCE.start(this, "<APP_ID>", this, true) { success ->  
PerimeterX.INSTANCE.start(this, "<APP_ID>", this, true, success -> { 
    return null;  


Important Notice

This feature is for development only and should not be shipped as enabled with the application to the store.


  1. Welcome screen

In this screen you select whether to start a new test or load the summary of a previous test, if one exists.

  1. Instruction screen

In this screen you get a detailed explanation on how to start a new test, what is expected to happen and what you can do in case you are not able to generate a challenge/captcha.

  1. Test selection screen

In this screen you can select between two different types of tests:

  1. Native app framework - to test your native URL requests.
  2. Web view framework - to test your web view URL requests.

When you are done executing a test, you will return to this screen to enable you to start the other test.

  1. Summary screen

In this screen you review the test results. You can go into details regarding each test and get troubleshooting tips in case a test failed, to help you analyze what is causing this issue.


Please Note

When you exit the "Doctor App", your app will also terminated. Just remember to switch the enableDoctorCheck param to false in case you finished validating your SDK integration.

Enable support for Account Defender

In order to enable support for PerimeterX Account Defender, a user ID should be set. You can set it by calling the setUserId function.

PerimeterX.INSTANCE.setUserId("<the current user ID>", null)
PerimeterX.INSTANCE.setUserId("<the current user ID>", null);

When the current user logs out, you should call this function again with null. This will turn off the Account Defender supported features.

To properly send Account Defender the complete user flow, call this function for each URL request that has been sent to your server. Notice that when the interceptor is enabled, this is done automatically by the SDK and there is no need to manually call the function.

PerimeterX.INSTANCE.registerOutgoingUrlRequest("<URL>", null)
PerimeterX.INSTANCE.registerOutgoingUrlRequest("<URL>", null);

Did this page help you?