Android SDK

How to install, configure and use the Castle Android SDK to perform device fingerprinting and monitor user activity.

πŸ“˜

πŸ‘©β€πŸ’» Looking for the source code?

The Castle Android SDK is available on GitHub.

Introduction

The Android SDK is a central component of the Castle integration, and provides device fingerprinting, behavioral analysis, and client-side event monitoring.

All the client-side SDKs, have two main purposes:

Configuration

Once installed, the SDK needs to be configured using your Publishable Key, which can be found in the Dashboard for users with administrator access.

import io.castle.android.Castle

// Place the below in your Application class onCreate method
Castle.configure(application, "{Publishable-API-Key}")
import io.castle.android.Castle;

// Place the below in your Application class onCreate method
Castle.configure(application, "{Publishable-API-Key}");

The Castle Android SDK collects fingerprint information from the device and sends this information directly to Castle. These requests are batched to optimize device performance. See the last section, Configuration Notes, to make changes to the way Castle collects and batch-processes this fingerprint information.

Creating request tokens

The SDK generates a request_token, which is a required field in the Risk and Filter APIs.

It's recommended that you forward the request token as a request header to every request to your API, since then you won't need to update the app whenever you're adding new server-side calls to Castle. The default value of the header is X-Castle-Request-Token, but you can specify the header name in the SDK configuration.

🚧

Request tokens don't live forever

A new request token value should to be generated for each request to your backend. A request token will expire after 120 seconds and should only be used during a single request to your backend. It's recommended that you implement the token generation as a client-side middleware which generates a new request token with each request to your backend.

Examples on how to pass the request token to your server

// OkHttp
requestBuilder.header(
    Castle.requestTokenHeaderName,
    Castle.createRequestToken()
);

// HttpURLConnection
httpUrlConnection.setRequestProperty(
    Castle.requestTokenHeaderName,
    Castle.createRequestToken()
);

// Volley
headers.put(
    Castle.requestTokenHeaderName,
    Castle.createRequestToken()
);
// OkHttp
requestBuilder.header(
    Castle.requestTokenHeaderName,
    Castle.createRequestToken()
)

// HttpURLConnection
httpUrlConnection.setRequestProperty(
    Castle.requestTokenHeaderName,
    Castle.createRequestToken()
)

// Volley
headers.put(
    Castle.requestTokenHeaderName,
    Castle.createRequestToken()
)

The createRequestToken method doesn't accept any options, and it generates tokens immediately in a non-blocking way.

Tracking client-side events

Step 1. Exposing the user object from your backend

The SDK offer two methods of sending data: screen and custom (described below) depending on which type of action the user performs. Common for these calls is that a user object needs to be provided. The contents of the user object are the same as for the the Risk and Filter APIs.

def castle_user
  return {
    id: 'ca1242f498', # required
    email: '[email protected]', # required
    phone: '+1415232183', # required if email is not present
    name: 'Michael Brown',
    registered_at: '2012-12-02T00:30:08.276Z',
    traits: {
      plan: 'premium'
    }
  }
end

In order to prevent user information from being spoofed by a bad actor, it is required that you encode the user information as a signed JWT on your backend.

From your backend code, you encode the user as a JWT and sign it using your Castle API Secret. Later, when Castle receives the JWT, the integrity of the user data will be verified to ensure that the data isn't being tampered with.

Below is an example of how to generate a JWT using the Ruby language, and exposing it as an endpoint called from your mobile app:

# Put behind authorization to have access to the logged in user
post '/castle_user_jwt' do
  JWT.encode(castle_user, ENV.fetch('CASTLE_API_SECRET'), 'HS256')
end

Step 2. Setting the user in your app

Now that your server API exposes the /castle_user_jwt endpoint, you'll request it from your mobile app and put it into the userJwt method. This method caches the user object for subsequent requests to screen and custom.

// IMPLEMENT: fetch the user_jwt from your /castle_user_jwt endpoint

Castle.userJwt("{user_jwt}");
// IMPLEMENT: fetch the user_jwt from your /castle_user_jwt endpoint

Castle.userJwt("{user_jwt}")

Step 3. Sending screen views from your app

Passing the title of each screen view to Castle offers your analysts detailed insights into user patterns that will help uncover complex fraud patterns. It's recommended that you centralize this logic so that you won't have to explicitly call screen for each new screen view. At the very least, it's recommended that you call screen for each step in the user onboarding flow, as well as any critical views such as transactions or user settings.

Castle.screen("Onboarding – Verify documents");
Castle.screen("Onboarding – Verify documents")

Step 4. Sending custom events from your app

Any user action that isn't covered by screen views can be tracked by calling the custom function. This also allows you to send custom properties related to the user action.

Castle.custom("Added to Cart", Map.of(
   "product", "iPhone 13 Pro",
   "price", 1099.99
));
Castle.custom("Added to Cart", mapOf(
   "product" to "iPhone 13 Pro",
   "price" to 1099.99
))

Additional configuration

The SDK allows for additional configuration options. Please refer to the documentation packaged with the SDK code for full details.

ArrayList<String> baseURLAllowList = new ArrayList<>();
baseURLAllowList.add("https://m.castle.io/");

CastleConfiguration configuration = new CastleConfiguration.Builder()
  .publishableKey("{Publishable-API-Key}")
  .debugLoggingEnabled(true) // Default false
  .flushLimit(10) // Default 20
  .baseURLAllowList(baseURLAllowList)
  .maxQueueLimit(100) // Default 1000
  .build();

// Setup Castle SDK with provided configuration
Castle.configure(application, configuration);
val configuration = CastleConfiguration.Builder()
  .publishableKey("{Publishable-API-Key}")
  .debugLoggingEnabled(true) // Default false
  .flushLimit(10) // Default 20
  .baseURLAllowList(listOf("https://m.castle.io/"))
  .maxQueueLimit(100) // Default 1000
  .build()

// Setup Castle SDK with provided configuration
Castle.configure(application, configuration)

Queue flushing

The SDK queues API calls to save battery life, and it only flushes queued events to the Castle API whenever the app is installed, updated, opened or closed, or when the queue reaches 20 events.