Android SDK

A simple guide to integrate Fingerprint's device intelligence platform in your native Android apps.

In this guide, you will learn to

  • Include Android SDK in your mobile apps.
  • Get a visitorId.
  • Read the SDK response.
  • Configure the SDK as per your needs.
  • Specify additional metadata in your identification request.
  • Handle errors.

For a complete example of how to use this SDK in your app, please visit the Github repo of our demo app.

Prerequisites

Sign up for an account with Fingerprint to get your API key.

Including the SDK in your app

  1. Add the repositories to your app-level build.gradle:
    // Use this block ONLY for Gradle versions 7 or higher
    repositories {
      ...
      maven { url 'https://maven.fpregistry.io/releases' }
    }
    
    // Use this block ONLY if Gradle version is lower than 7.
    allprojects {	
      repositories {
      ...
      maven { url 'https://maven.fpregistry.io/releases' }
    }}
    
  2. Add the dependencies to your module-level build.gradle:
    dependencies {
      implementation "com.fingerprint.android:pro:2.7.0"
    }
    
  3. Perform a Gradle sync to update all the dependencies.

Getting a visitorId

To get a visitorId, you need the public API key that you obtained when signing up for an account with Fingerprint. You can find this API key in the Dashboard > API Keys.

Here is an example that shows you how to get a visitorId:

import com.fingerprintjs.android.fpjs_pro.Configuration
import com.fingerprintjs.android.fpjs_pro.FingerprintJSFactory
...

// Initialize and configure the SDK
val factory = FingerprintJSFactory(applicationContext)
val configuration = Configuration(
  apiKey = "<<browserToken>>",
  // The 'region' must match the region associated with your API key
  region = Configuration.Region.US,
  // For custom subdomain or proxy integration, use this option to specify a custom endpoint.
  // If you do not have a custom endpoint, this parameter can be skipped.
  endpointUrl = "custom-endpoint-URL",
  // Additionally, you may also specify alternate, fallback endpoints to redirect failed
  // requests.
  fallbackEndpointUrls = listOf(
      "fallback-endpoint-URL-1",
      "fallback-endpoint-URL-2",
  ),
  extendedResponseFormat = false
)
 
val fpjsClient = factory.createInstance(
  configuration
)

// Get a 'visitorId'
fpjsClient.getVisitorId { visitorIdResponse ->
  val visitorId = visitorIdResponse.visitorId
  // Use the visitorId
}
import com.fingerprintjs.android.fpjs_pro.Configuration;
import com.fingerprintjs.android.fpjs_pro.FingerprintJS;
import com.fingerprintjs.android.fpjs_pro.FingerprintJSFactory;
import java.util.Arrays;
...

// Initialize and configure the SDK
FingerprintJSFactory factory = new FingerprintJSFactory(this.getApplicationContext());
Configuration configuration = new Configuration(
  "<<browserToken>>",
  // The 'region' must match the region associated with your API key
  Configuration.Region.US,
  // For custom subdomain or proxy integration, use this option to specify a custom endpoint.
  // If you do not have a custom endpoint, this parameter can be skipped.
  "custom-endpoint-URL",
  // Additionally, you may also specify alternate, fallback endpoints to redirect failed
  // requests.
  Arrays.asList(
    "fallback-endpoint-URL-1",
    "fallback-endpoint-URL-2"
  ),
  false
);

FingerprintJS fpjsClient = factory.createInstance(configuration);

// Get a 'visitorId'
fpjsClient.getVisitorId(visitorIdResponse -> {
  // Use the ID
  String visitorId = visitorIdResponse.getVisitorId();
  return null;
});

Specifying a custom timeout

Default timeout value: null

The identification requests made from an Android SDK do not have a default timeout.

You can use timeoutMillis to provide a custom timeout value of your choice. If the getVisitorId() call does not complete within the specified timeout, you will receive a ClientTimeout error.

Here is an example that shows you how to specify a custom timeout:

fpjsClient.getVisitorId (
  // Set a timeout value of 10 seconds
  timeoutMillis = 10_000,
  
  // Get a 'visitorId', will timeout after 10s
  listener = { visitorIdResponse ->
    visitorId = visitorIdResponse.visitorId;
  }
)
fpjsClient.getVisitorId(
  // Pass a timeout value of 10 seconds
  10000,
  visitorIdResponse -> {
    // Get a 'visitorId', will timeout after 10s
    visitorId = visitorIdResponse.getVisitorId();
    return null;
  }
);

Reading the response

The function FingerprintJS.getVisitorId() returns the response in a FingerprintJSProResponse object. This object has the following fields, some of which can be empty/invalid when Sealed Client Results is enabled for your account.

FieldSealed Client Results is disabledSealed Client Results is enabled
requestIdString. An identifier that uniquely identifies this particular request to FingerprintJS.getVisitorID().String. An identifier that uniquely identifies this particular request to FingerprintJS.getVisitorID().
visitorIdString. An identifier that uniquely identifies the device.N/A
confidenceScoreConfidenceScore. A score that indicates the probability of this device being accurately identified. The value ranges from 0 to 1.N/A
sealedResultnullString?. An encrypted, binary, Base64-encoded String that contains the same response as you would receive with an /events API request

Configuring the SDK

Using the Configuration object, It is possible to configure the SDK as per your requirements. As of now, the following options are supported:

region

Type: Region.

Default value: Region.US

This option allows you to specify a region where you want your data to be stored and processed. This region must be the same as the one you specified when registering your app with Fingerprint. See region for more information.

endpointUrl

Type: String

Default value: Region.US.getEndpointUrl()

This option allows you to specify a custom endpoint, particularly when you have set up either a custom sub-domain or a proxy integration.

fallbackEndpointUrls

Type: List

Default value: emptyList()

This option allows you to specify alternate, fallback endpoints to redirect failed requests.

extendedResponseFormat

Type: Boolean

Default value: false

When set to true, in addition to those fields returned by default, the FingerprintJSProResponse object will also contain the following fields:

  • visitorFound - Boolean. Indicates if this device has already been encountered by your app.
  • ipAddress - String. The IPv4 address of the device.
  • ipLocation - IPLocation. [This field is deprecated and will not return a result for applications created after January 23rd, 2024. See IP Geolocation for a replacement available in our Smart Signals product.] Indicates the location as deduced from the IP address.
  • osName - String. Indicates the name of the underlying operating system.
  • osVersion - String. Indicates the version of the underlying operating system of the device.
  • firstSeenAt, lastSeenAt - Timestamp. See Visitor Footprint Timestamps.

When Sealed Client Results is enabled for your account, several of these fields may not have valid values.

Specifying linkedID and tag

Similar to the JS Agent for the browser, the Android SDK also supports providing custom metadata along with an identification request. To learn more about this capability, please see Linking and tagging information.

Here is an example that shows you how to associate your identification request with an account ID and additional metadata:

fpjsClient.getVisitorId (
  // Associate additional metadata to this request
  tags = mapOf("orderID" to orderId, "zip" to zipCode),
  // Associate an account number to this request 
  linkedId = accountID,
  
  // Get a 'visitorId'
  listener = { visitorIdResponse ->
    visitorId = visitorIdResponse.visitorId;
  }
)   
Map<String, String> tags = new HashMap<>();
tags.put("orderID", orderId);
tags.put("zip", zipCode);

fpjsClient.getVisitorId(
  // Associate additional metadata to this request
  tags,
  // Associate an account number to this request
  accountId,
  // Get a 'visitorId'
  visitorIdResponse -> {
    // handle visitorId and other data
  },
);

Handling errors

The SDK provides an Error class that helps you identify the reasons behind an unsuccessful identification request. Here is an example that shows you how to handle errors in your app:

fpjsClient.getVisitorId (
  // Get a 'visitorId'
  listener = { visitorIdResponse ->
    visitorId = visitorIdResponse.visitorId;
  },
  errorListener = { error ->
    when(error) {
      is ApiKeyRequired -> {
        val requestId = error.requestId
        // Handle error
      }
    }
  }
)
Map<String, String> tags = new HashMap<>();
tags.put("orderID", orderId);
tags.put("zip", zipCode);

fpjsClient.getVisitorId(
  // Associate additional metadata to this request
  tags,
  // Associate an account number to this request
  accountID,
  // Get a 'visitorId'
  visitorIdResponse -> {
    // Handle visitorId and other data
    String visitorId = visitorIdResponse.getVisitorId();
  	return null;
  },
  // Handle errors
  error -> {
    // Handle errors as per their type 
    if (error.getClass() == ApiKeyRequired.class) {
      Log.e(TAG, error.getRequestId() + error.getDescription());
  	}
  	return null;
  }
);

Data Classes

ConfidenceScore

data class ConfidenceScore(
  val score: Double
)

Configuration

class Configuration @JvmOverloads constructor(
  val apiToken: String,
  val region: Region = Region.US,
  val endpointUrl: String = region.endpointUrl,
  val fallbackEndpointUrls: List<String> = emptyList(),
  val extendedResponseFormat: Boolean = false
)

Error

It's a sealed class, which can be one of:

  • ApiKeyRequired
  • ApiKeyNotFound
  • ApiKeyExpired
  • RequestCannotBeParsed
  • Failed
  • RequestTimeout
  • TooManyRequest
  • OriginNotAvailable
  • HeaderRestricted
  • PackageNotAuthorized
  • WrongRegion
  • SubscriptionNotActive
  • UnsupportedVersion
  • ResponseCannotBeParsed
  • NetworkError
  • ClientTimeout
sealed class Error(
  // The request ID of the identification request
  val requestId: String = UNKNOWN,
  // A self-explanatory description of the error
  val description: String? = UNKNOWN
)

IPLocation

data class IpLocation(
  val accuracyRadius: Int,
  val latitude: Double,
  val longitude: Double,
  val postalCode: String,
  val timezone: String,
  val city: City,
  val country: Country,
  val continent: Continent,
  val subdivisions: List<Subdivisions>
) {
  data class City(
    val name: String
  )
  data class Country(
    val code: String,
    val name: String
  )
  data class Continent(
    val code: String,
    val name: String
  )
  data class Subdivisions(
    val isoCode: String,
    val name: String
  )
}

Region

public enum class Region(public val endpointUrl: String) {
  US("https://api.fpjs.io"),
  EU("https://eu.api.fpjs.io"),
  AP("https://ap.api.fpjs.io")
}

Timestamp

data class Timestamp(
  val global: String,
  val subscription: String
}