Device Intelligence Android Native
Device Fingerprinting helps you understand your user’s unique hardware with their device data. It efficiently syncs the data in the background, processes them and the data processed can be used to generate a fingerprint id.
Integration Overview
- Integrate Android SDK in your application
- Call the API to query device information

Device Intelligence Flow
- SessionKey and UserID is generated from client backend and sent to the SDK.
- Invoke the submit function in SDK to pass the data to Bureau backend.
- Upon successful transmission of the parameters, a callback is received in the SDK, based on the callback (Success/Failure) next steps can be taken.
- If the callback is successful, Invoke Bureau's backend API
/v1/suppliers/device-fingerprint
to fetch the results. - Use the fingerprint and risk signals to allow, block or redirect the user to a desired flow.
Usage
The SDK is initialised in the client app and once the submit function is called the data relating to the user and device are automatically synced in the background.
Minimum Requirements
- minSdkVersion 21
- AndroidX
Getting Started
Add following lines in your root build.gradle
Properties properties = new Properties()
properties.load(new FileInputStream(project.rootProject.file('local.properties')))
buildscript {
.....
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io"}
}
}
Add following lines in your module level build.gradle. The latest dependency can be obtained from here
dependencies {
//add the following dependency in your gradle file
implementation 'com.github.Bureau-Inc:prism-android-fingerprint-sdk:0.00.0'}
This library also uses some common android libraries. So if you are not already using them then make sure you add these libraries to your module level build.gradle
- androidx.appcompat:appcompat:1.2.0
Initialise SDK
//Get SDK Instance with Client Id and Environment
val bureauAPI : BureauAPI = BureauInstanceProvider.getBureauApiInstance(context,YOUR_CLIENT_ID,
ENV_SANDBOX or ENV_PRODUCTION)
bureauAPI.setSessionId(YOUR_SESSION_ID)
bureauAPI.setFlow(YOUR_FLOW_NAME)//optional
bureauAPI.setUserId(YOUR_USER_ID)
//Start collecting and submit data to Bureau's backend using the submit function
bureauAPI.submit(object :
DataCallback {
override fun onError(errorMessage: ErrorResponse) {
}
override fun onResult(message: SubmitResponse) {
}
})
//Get SDK Instance with Client Id and Environment
BureauAPI bureauAPI = BureauInstanceProvider.getBureauApiInstance(context, "YOUR_CLIENT_ID", Environment.ENV_PRODUCTION);
bureauAPI.setSessionId("YOUR_SESSION_ID"); //Mandatory
bureauAPI.setFlow("your_flow_name"); //optional
bureauAPI.setUserId("your_user_id"); //optional
//Start collecting and submit data to Bureau's backend using the submit function
bureauAPI.submit((new DataCallback() {
public void onError(@NotNull ErrorResponse errorMessage) {
//implement your own logic
}
public void onResult(@NotNull SubmitResponse message) {
//implement your own logic
}
}));
Optional : Collect Behavioral Biometrics Data
After Initialization and before submit call below api . This needs to be called on the page where behavioral biometrics session data is needed. Once the user flow is completed, submit api needs to be called, for the session to end.
bureauAPI.startSession()
//Get SDK Instance with Client Id and Environment
BureauAPI bureauAPI = BureauInstanceProvider.getBureauApiInstance(context, "YOUR_CLIENT_ID", Environment.ENV_PRODUCTION);
bureauAPI.setSessionId("YOUR_SESSION_ID"); //Mandatory
bureauAPI.setFlow("your_flow_name"); //optional
bureauAPI.setUserId("your_user_id"); //optional
//Start collecting and submit data to Bureau's backend using the submit function
bureauAPI.submit((new DataCallback() {
public void onError(@NotNull ErrorResponse errorMessage) {
//implement your own logic
}
public void onResult(@NotNull SubmitResponse message) {
//implement your own logic
}
}));
Note:
- To initialise the SDK we need to provide CREDENTIAL_ID.
- Session Id is mandatory and unique for each submission.
- To obtain the fingerprint Id query Bureau backend.
- The default environment is production. If you want to run on UAT pass ENV_SANDBOX in getBureauApiInstance function.
Response returned from the SDK
The DataCallback added in the Submit function returns whether the device data has been registered or not.
object :DataCallback{
override fun onError(errorMessage: ErrorResponse) {
//Failure Callback
Log.w(TAG,"Error "+errorMessage)
}
override fun onResult(message: SubmitResponse) {
//Success Callback
Log.w(TAG,"Success "+message)
}
}}
bureauAPI.submit((new DataCallback() {
public void onError(@NotNull ErrorResponse errorMessage) {
//implement your own logic
}
public void onResult(@NotNull SubmitResponse message) {
//implement your own logic
}
}));
Backend API Integration
Backend URL's
- Sandbox - https://api.overwatch.stg.bureau.id/v1/suppliers/device-fingerprint
- Production - https://api.overwatch.bureau.id/v1/suppliers/device-fingerprint
Authentication
API's are authenticated via an clientID and secret, they have to be base64 encoded and sent in the header with the parameter name as Authorisation.
Authorisation : Base64(clientID:secret)
Request
curl --location --request POST 'https://api.overwatch.stg.bureau.id/v1/suppliers/device-fingerprint' \
--header 'Authorization: Basic MzNiNxxxx2ItZGU2M==' \
--header 'Content-Type: application/json' \
--data-raw '{
"sessionKey": "697bb2d6-1111-1111-1111-548d6a809360"
}'
curl --location --request POST 'https://api.overwatch.bureau.id/v1/suppliers/device-fingerprint' \
--header 'Authorization: Basic MzNiNxxxx2ItZGU2M==' \
--header 'Content-Type: application/json' \
--data-raw '{
"sessionKey": "697bb2d6-1111-1111-1111-548d6a809360"
}'
Response
{
"GPSLocation": {
"city": "Ahmedabad",
"country": "IN",
"latitude": 23.03499984741211,
"longitude": 72.56400299072266,
"region": "Gujarat"
},
"IP": "43.242.116.163",
"IPLocation": {
"city": "Ahmedabad",
"country": "IN",
"latitude": 23.03499984741211,
"longitude": 72.56400299072266,
"region": "Gujarat"
},
"IPSecurity": {
"VPN": false,
"isCrawler": false,
"isProxy": false,
"isTor": false,
"threatLevel": "low"
},
"IPType": "v4",
"OS": "android",
"VPN": null,
"conditionsEvaluationStatus": true,
"debuggable": true,
"emulator": true,
"error": null,
"fingerprint": "ce53c2cd-xxxx-40c3-xxxx-41400751a07e",
"firstSeenDays": 11,
"isAppCloned": false,
"isAppTampered": false,
"mockgps": false,
"model": "sdk_gphone64_arm64",
"package": "com.rxxxo.app.staging",
"riskLevel": "HIGH",
"rooted": false,
"sessionId": "stgrestest11",
"status": "OK",
"totalUniqueUserId": 3,
"userId": "9xxxx6x4"
}
}
{
"data": null,
"errors": {
"status": 401,
"errorCode": "UNAUTHORIZED",
"service": "Overwatch"
},
"message": "",
"meta": {
"length": 0,
"took": 0,
"total": 0
}
}
{
"error": {
"code": 0,
"description": "",
"message": "Server encountered an error",
"metadata": null,
"referenceId": "86529a18-a5cb-4da9-91b0-8d04cdb9167e",
"type": "INTERNAL_SERVER_ERROR"
},
"merchantId": "auth0|61dfxxxx0071be7021",
"requestId": "c69d86f0-xxxx-4ef0-xxxx-e687d595a507",
"statusCode": 500,
"timestamp": 1657009043753
}
{
"error": {
"code": 422,
"description": "Failed to find fingerprint for given session key",
"message": "NO_RECORD_FOUND",
"metadata": null,
"referenceId": "",
"type": "NO_RECORD_FOUND"
},
"merchantId": "auth0|61dfbbxxxx420071be7021",
"requestId": "24e1aa7f-xxxx-404d-xxxx-5f8a0227e8f0",
"statusCode": 422,
"timestamp": 1658402132141
}
{
"statusCode": 400,
"error": {
"code": 0,
"type": "BAD_REQUEST",
"message": "Session key is missing",
"description": "request does not contain additionalData.sessionKey param in request",
"referenceId": "24f94ae8-xxxx-48a4-xxxx-b25f99fb06d9",
"metadata": null
},
"timestamp": 1658402143450,
"merchantId": "auth0|61dfbbxxxx3420071be7021",
"requestId": "66403193-xxxx-44bc-xxxx-14735a45dfeb"
}
Response Description
Key | Description |
---|---|
GPSLocation(city, country, latitude, longitude, region) | GPS Based location of the user, user's consent is required to be taken to get this details. |
IPLocation(city, country, latitude, longitude, region) | IP based location of the user. |
IP | IP address of the user. |
VPN | Flag to indicate if the IP being used by the user is a VPN. (Note the VPN within the IPSecurity JSON object should be used and not the one outside. |
isCrawler | Flag to indicate if the IP being used by the user is associated with a crawler. |
isProxy | Flag to indicate if the IP being used by the user is a proxy. |
isTor | Flag to indicate if the IP being used by the user is of a Tor network. |
threatLevel | The threat level associated with the IP. Possible values can be ["low", "medium", "high"] |
IPType | The type of IP, ["v4", "v6"] |
OS | The OS of the user's device. |
debuggable | Flag to indicate if the app is in debug mode. |
emulator | Flag to indicate if the app is being run on an emulator |
fingerprint | A hash generated for the device, this identifier will be unique for a device. |
firstSeenDays | The number of days from which the device is identified on Bureau's network. |
isAppCloned | Flag to indicate if the app is cloned. |
isAppTampered | Flag to indicate if the app is tampered. |
mockgps | Flag to indicate if the user is spoofing their GPS location. This will need users permission for background location. |
model | The device model. |
package | The package name. |
riskLevel | Risk level of the user, calculated based on the flags that are exposed in the above sections. Possible values ["LOW", "MEDIUM", "HIGH"] |
rooted | Flag to indicate if the device is rooted. |
sessionId | The session identifier, that was used to invoke the SDK. |
Optional :Behavioural Biometrics Additional Response Fields
Response
{
"GPSLocation": {
"city": "Ahmedabad",
"country": "IN",
"latitude": 23.03499984741211,
"longitude": 72.56400299072266,
"region": "Gujarat"
},
"IP": "43.242.116.163",
"IPLocation": {
"city": "Ahmedabad",
"country": "IN",
"latitude": 23.03499984741211,
"longitude": 72.56400299072266,
"region": "Gujarat"
},
"IPSecurity": {
"VPN": false,
"isCrawler": false,
"isProxy": false,
"isTor": false,
"threatLevel": "low"
},
"IPType": "v4",
"OS": "android",
"VPN": null,
"conditionsEvaluationStatus": true,
"debuggable": true,
"emulator": true,
"error": null,
"fingerprint": "ce53c2cd-xxxx-40c3-xxxx-41400751a07e",
"firstSeenDays": 11,
"isAppCloned": false,
"isAppTampered": false,
"mockgps": false,
"model": "sdk_gphone64_arm64",
"package": "com.rxxxo.app.staging",
"riskLevel": "HIGH",
"rooted": false,
"status": "OK",
"totalUniqueUserId": 3,
"userId": "9xxxx6x4",
"behaviourRisk" : "low",
"botDetected" : "false",
"hesitationBehaviour" : "low",
"expertBehaviour": "low"
"distractionBehaviour" : "low",
}
}
{
"data": null,
"errors": {
"status": 401,
"errorCode": "UNAUTHORIZED",
"service": "Overwatch"
},
"message": "",
"meta": {
"length": 0,
"took": 0,
"total": 0
}
}
{
"error": {
"code": 0,
"description": "",
"message": "Server encountered an error",
"metadata": null,
"referenceId": "86529a18-a5cb-4da9-91b0-8d04cdb9167e",
"type": "INTERNAL_SERVER_ERROR"
},
"merchantId": "auth0|61dfxxxx0071be7021",
"requestId": "c69d86f0-xxxx-4ef0-xxxx-e687d595a507",
"statusCode": 500,
"timestamp": 1657009043753
}
{
"error": {
"code": 422,
"description": "Failed to find fingerprint for given session key",
"message": "NO_RECORD_FOUND",
"metadata": null,
"referenceId": "",
"type": "NO_RECORD_FOUND"
},
"merchantId": "auth0|61dfbbxxxx420071be7021",
"requestId": "24e1aa7f-xxxx-404d-xxxx-5f8a0227e8f0",
"statusCode": 422,
"timestamp": 1658402132141
}
{
"statusCode": 400,
"error": {
"code": 0,
"type": "BAD_REQUEST",
"message": "Session key is missing",
"description": "request does not contain additionalData.sessionKey param in request",
"referenceId": "24f94ae8-xxxx-48a4-xxxx-b25f99fb06d9",
"metadata": null
},
"timestamp": 1658402143450,
"merchantId": "auth0|61dfbbxxxx3420071be7021",
"requestId": "66403193-xxxx-44bc-xxxx-14735a45dfeb"
}
Additional Behaviour parameters Description
Key | Description |
---|---|
behaviourRisk | Flag to indicate the riskiness of user based on Behaviour Biometrics |
botDetected | Flag to indicate whether the session has a bot like behaviour |
hesitationBehaviour | Flag to indicate whether user has too many hesitation events |
expertBehaviour | Flag to indicate whether the user was familiar with process or data |
distractionBehaviour | Flag to indicate whether the user was distracted. |
To Note:
In case of Behavioral Biometrics, there will be a training period in which additional parameters can be added based on the training data which correlates to Fraud
Go live Checklist
- For determining the app tamper check, we would require your package name and signature hash code, kindly ensure this is shared before going live. The hash code can be obtained from PackageManager GET_SIGNING_CERTIFICATES
signingInfo.signingCertificateHistory
this will be a byte array.
Updated 3 months ago