Skip to main content

Header Graphic

Integration Guide for Android SDK

Jumio’s products allow businesses to establish the genuine identity of their users by verifying government-issued IDs in real-time. ID Verification, Selfie Verification and other services are used by financial service organizations and other leading brands to create trust for safe onboarding, money transfers and user authentication.

Release Notes

Please refer to our Change Log for more information. Current SDK version: 4.15.0

For technical changes that should be considered when updating the SDK, please read our Transition Guide.

Code Documentation

Full API documentation for the Jumio Android SDK can be found here.

Setup

The basic setup is required before continuing with the following setup for the Jumio SDK. If you are updating your SDK to a newer version, please also refer to:

➡️  Changelog
➡️  Transition Guide

Dependencies

The SDK Setup Tool is a web tool that helps determine available product combinations and corresponding dependencies for the Jumio SDK, as well as an export feature to easily import the applied changes straight into your codebase.

Jumio Setup

Below you can find a list of dependencies that can be added to your application to enable different functionality of the Jumio SDK. Some modules are mandatory, others are optional.

If an optional module is not linked, some functionalities may not be available, but the library size will be reduced. The Sample app apk size is currently around 13.63 MB.

// [Mandatory] Jumio Core library
dependencies {
implementation "com.jumio.android:core:4.15.0"
...
}

// [Optional] Extraction methods
dependencies {
implementation "com.jumio.android:docfinder:4.15.0" // Autocapture library, includes all previous scanning methods
implementation "com.jumio.android:barcode-mlkit:4.15.0" // Barcode scanning library, assists Autocapture
implementation "com.jumio.android:nfc:4.15.0" // NFC scanning library, assists Autocapture
implementation "com.jumio.android:iproov:4.15.0" // Face Liveness library
implementation "com.jumio.android:liveness:4.15.0" // Face Liveness library
implementation "com.jumio.android:digital-identity:4.15.0" // Digital Identity verification library
...
}

// [Optional] Jumio Default UI
dependencies {
implementation "com.jumio.android:defaultui:4.15.0"
...
}

// [Optional] Additional functionality
dependencies {
implementation "com.jumio.android:camerax:4.15.0" // CameraX library
...
}

In addition to specifying individual dependencies, you can also use a BOM (Bill of Materials) to manage all the dependency versions at once. By using BOM, you ensure that all the dependencies are automatically aligned to the correct versions, reducing the need to manually update version numbers across your dependencies.

dependencies {
implementation platform("com.jumio.android:bom:4.15.0")
implementation "com.jumio.android:core"
implementation "com.jumio.android:barcode-mlkit"
implementation "com.jumio.android:camerax"
implementation "com.jumio.android:defaultui"
implementation "com.jumio.android:digital-identity"
implementation "com.jumio.android:docfinder"
implementation "com.jumio.android:iproov"
implementation "com.jumio.android:liveness"
implementation "com.jumio.android:nfc"
}

Autocapture

The module com.jumio.android:docfinder offers one generic scanning method across all ID documents, providing a more seamless capture experience for the end user. The SDK will automatically detect which type of ID document is presented by the user and guide them through the capturing process with live feedback. The models can be bundled with the app directly to save time on the download during the SDK runtime. Please see section ML Models for more information.

Certified Face Liveness

Jumio uses Certified Liveness technology to determine liveness. Link com.jumio.android:liveness and com.jumio.android:iproov modules in order to use Jumio Liveness. Please note: com.jumio.android:camerax will be linked transitively when com.jumio.android:liveness is linked. If necessary, the iProov SDK version can be overwritten with a more recent one:

implementation "com.jumio.android:iproov:4.15.0"
implementation("com.iproov.sdk:iproov:9.1.2") {
exclude group: 'org.json', module: 'json'
}

Barcode Scanning

In order to benefit from barcode scanning functionality included in the com.jumio.android:docfinder dependency, please add com.jumio.android:barcode-mlkit to your build-gradle file.

This dependency includes com.google.android.gms:play-services-mlkit-barcode-scanning library - if your application includes other Google ML-kit libraries, it might be necessary to override meta-data specified in the application tag of the play-services-mlkit-barcode-scanning manifest by merging multiple manifests:

<meta-data
android:name="com.google.android.gms.vision.DEPENDENCIES"
android:value="barcode"
tools:replace="android:value" />

NFC Scanning

In order to benefit from NFC scanning functionality included in the com.jumio.android:docfinder dependency, please add com.jumio.android:nfc to your build-gradle file.

SDK Version Check

Use JumioSDK.sdkVersion to check which SDK version is being used.

Root Detection

For security reasons, applications implementing the SDK should not run on rooted devices. Use either the below method or a self-devised check to prevent usage of SDK scanning functionality on rooted devices.

JumioSDK.isRooted(context: Context)
note

Please be aware that the JumioSDK root check uses various mechanisms for detection, but doesn't guarantee to detect 100% of all rooted devices.

Device Supported Check

Use the method below to check if the current device platform is supported by the SDK.

JumioSDK.isSupportedPlatform(context: Context)

Privacy Notice

If you submit your app to the Google Play Store a Prominent Disclosure explaining the collected User Data is required. The collected user data also needs to be declared in your Data Safety Form and the Privacy Policy related to your application.

Other stores might require something similar - please check before submitting your app to the store.

Please see the Jumio Privacy Policy for Online Services for further information.

Digital Identity (DID)

In case Digital Identity Verification has been enabled for your account you can add the com.jumio.android:digital-identity dependency to your application. This will enable you to make use of DID verification within the SDK.

Over the course of DID verification the SDK will launch an according third party application representing your Digital Identity. Communication between both applications (your integrating application and the Digital Identity application) is done via a so-called "deep link". For more information on deep link handling on Android please check out their official guide.

To enable your app specific deep link, our support team has to setup an according scheme of your choice for you. This scheme will be used by the SDK to identify your application while returning from the DID provider's application. For the scheme basically any string can be used, however it is recommended that it is unique to your application in some way. A suggestion would be your company name.

Following snippet shows how the deep link needs to be setup in your application's AndroidManifest.xml file:

<activity
android:name="com.jumio.app.HostingActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/Theme.Jumio">
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="&lt;your-app-scheme&gt;" />
</intent-filter>
</activity>

Please note that the properties android:exported="true" and android:launchMode="singleTask" need to be specified as well. The first parameter basically tells the Android system that your Activity can be found by the system and other applications. By specifying launchMode="singleTask" any already running task for this Activity will be resumed (instead of creating a new instance). Both are requirements so that the SDK can handle the according deep link correctly.

In case you are using Jumio's Default UI in your app (see section Default UI) you also need to specify tools:replace="android:exported" to JumioActivity's <activity> tag like so:

<activity
android:name="com.jumio.defaultui.JumioActivity"
android:exported="true"
android:launchMode="singleTask"
tools:replace="android:exported">
<intent-filter>
...
</intent-filter>
</activity>

As deep link handling happens on Activity level, the according data needs to be forwarded to the SDK via Activity.onNewIntent(). The following code snippet shows how this can be achieved. If you're using Jumio's Default UI you can ignore this step.

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)

intent.data?.let { deepLink ->
val activeScanPart = scanPart ?: return

JumioDeepLinkHandler.consumeForScanPart(deepLink, activeScanPart)
}
}

Risk Signal: Device Risk

If you want to include risk signals into your application, please check our Risk Signal guide.

Iovation setup

To integrate the device risk vendor Iovation into your application, please follow the Iovation integration guide.

API call

To provide Jumio with the generated Device Risk blackbox, please follow the Device Risk API guide.

ML Models

By default, required models get downloaded by the SDK if not provided via the assets folder or preloaded.

Bundling models in the app

You can download our encrypted models and add them to your assets folder for the following modules.

warning

Make sure not to alter the downloaded models (name or content) before adding them to your assets folder.

DocFinder

If you are using the com.jumio.android:docfinder module, find the required models here and here.

Liveness

If you are using the com.jumio.android:liveness module, find the required model here.

Preloading models

In version 4.9.0 we introduced the [JumioPreloader][jumiopreloader]. It provides functionality to preload models without the JumioSDK being initialized. To do so call:

with(JumioPreloader) {
init(`<Your Context>`) // init with Context
preloadIfNeeded()
}

The [JumioPreloader][jumiopreloader] will identify which models are required based on your configuration.

Preloaded models are cached so they will not be downloaded again. To clean the models call:

with(JumioPreloader) {
init(`<Your Context>`) // init with Context
clean()
}
warning

clean should never be called while the SDK is running!

To get notified that preloading has finished, you can implement [JumioPreloadCallback][jumiopreloadcallback] methods and set the callback as follows:

with(JumioPreloader) {
init("&lt;Your Context&gt;") // init with Context
setCallback("&lt;Your callback&gt;")
...
}

Initialization

Requesting a Token (via OAuth2)

Your OAuth2 credentials are constructed using your API token as the Client ID and your API secret as the Client secret. You can view and manage your Client ID and secret in the Jumio Portal under:

  • Settings < API credentials < OAuth2 Clients

Client ID and Client secret are used to generate an OAuth2 access token. Send a workflow request using the acquired OAuth2 access token to receive the SDK token necessary to initialize the Jumio SDK.

OAuth2 has to be activated for your account. Contact your Jumio Account Manager for activation. For more details, please refer to Authentication and Encryption.

Initializing the Jumio SDK

Use your aquired SDK token and your according datacenter to initialize the JumioSDK:

const val YOUR_SDK_TOKEN = ""
const val YOUR_DATACENTER = ""

sdk = JumioSDK(context: Context).apply {
token = "YOUR_SDK_TOKEN"
datacenter = "YOUR_DATACENTER"
}

Data center is set to "US" by default. If your customer account is in the EU data center, use "EU" instead. Alternatively, use "SG" for Singapore.

tip

We strongly recommend storing all credentials outside of your app! We suggest loading them during runtime from your server-side implementation.

Configuration

Every Jumio SDK instance is initialized using a specific [sdk.token][token]. This token contains information about the workflow, credentials, transaction identifiers and other parameters. Configuration of this token allows you to provide your own internal tracking information for the user and their transaction, specify what user information is captured and by which method, as well as preset options to enhance the user journey. Values configured within the [sdk.token][token] during your API request will override any corresponding settings configured in the Jumio Portal.

Worfklow Selection

Use ID verification callback to receive a verification status and verified data positions (see Callback section). Make sure that your customer account is enabled to use this feature. A callback URL can be specified for individual transactions (for URL constraints see chapter Jumio Callback IP Addresses). This setting overrides any callback URL you have set in the Jumio Portal. Your callback URL must not contain sensitive data like PII (Personally Identifiable Information) or account login. Set your callback URL using the callbackUrl parameter.

Use the correct workflow definition key in order to request a specific workflow. Set your key using the workflowDefinition.key parameter.

{
"customerInternalReference": "CUSTOMER_REFERENCE",
"workflowDefinition": {
"key": "X"
},
"callbackUrl": "YOUR_CALLBACK_URL"
}

For more details, please refer to our Workflow Description Guide.

note

Selfie Verification requires portrait orientation in your app.

Transaction Identifiers

There are several options in order to uniquely identify specific transactions. customerInternalReference allows you to specify your own unique identifier for a certain scan (max. 100 characters). Use reportingCriteria, to identify the scan in your reports (max. 100 characters). You can also set a unique identifier for each user using userReference (max. 100 characters).

For more details, please refer to the Account Request section in our KYX Guide.

{
"customerInternalReference": "CUSTOMER_REFERENCE",
"workflowDefinition": {
"key": "X"
},
"reportingCriteria": "YOUR_REPORTING_CRITERIA",
"userReference": "YOUR_USER_REFERENCE"
}
note

Transaction identifiers must not contain sensitive data like PII (Personally Identifiable Information) or account login.

Preselection

You can specify issuing country using ISO 3166-1 alpha-3 country codes, as well as ID types to skip selection during the scanning process. In the example down below, Austria ("AUT") and the USA ("USA") have been preselected. PASSPORT and DRIVER_LICENSE have been chosen as preselected document types. If all parameters are preselected and valid and there is only one given combination (one country and one document type), the document selection screen in the SDK can be skipped entirely.

For more details, please refer to the Account Request section in our KYX Guide.

note

"Digital Identity" document type can not be preselected!

{
"customerInternalReference": "CUSTOMER_REFERENCE",
"workflowDefinition": {
"key": X,
"credentials": [
{
"category": "ID",
"type": {
"values": [
"DRIVING_LICENSE",
"PASSPORT"
]
},
"country": {
"values": [
"AUT",
"USA"
]
}
}
]
}
}

Miscellaneous

Use [cameraFacing][camerafacing] attribute of [JumioScanView][jumioscanview] to configure the default camera and set it to FRONT or BACK.

scanView.cameraFacing = JumioCameraFacing.FRONT

SDK Workflow

Retrieving Information

The SDK returns a [JumioResult][jumioresult] object which contains the result of the finished workflow. Extracted ID data will not be returned by default - please contact Jumio Customer Service at support@jumio.com in case this is needed.

The following tables give information on the specification of all data parameters and errors:

  • [JumioIDResult][jumioidresult]
  • [JumioFaceResult][jumiofaceresult]
  • [JumioRejectReason][jumiorejectreason]
  • [JumioError][jumioerror]

Class JumioIDResult

ParameterTypeMax. lengthDescription
issuingCountryString3Country of issue as ISO 3166-1 alpha-3 country code
idTypeStringPASSPORT, DRIVER_LICENSE, IDENTITY_CARD or VISA as provided or selected
idSubTypeStringSub type of the scanned ID
firstNameString100First name of the customer
lastNameString100Last name of the customer
dateOfBirthStringDate of birth
issuingDateStringDate of issue
expiryDateStringDate of expiry
documentNumberString100Identification number of the document
personalNumberStringPersonal number of the document
genderStringGender M, F or X
nationalityStringNationality of the customer
placeOfBirthString255Place of birth
countryStringCountry of residence
addressString64Street name of residence
cityString64City of residence
subdivisionString3Last three characters of ISO 3166-2:US or ISO 3166-2:CA subdivision code
postalCodeString15Postal code of residence
mrzLine1String50MRZ line 1
mrzLine2String50MRZ line 2
mrzLine3String50MRZ line 3
curpStringThe Clave Única de Registro de Población (CURP) identity code for Mexican documents.
extractionMethodJumioScanMode[jumioscanmode]Extraction method used during scanning
imageDataJumioImageDataWrapper class for accessing image data of all credential parts from an ID verification session. This feature has to be enabled by your account manager.

Class JumioFaceResult

ParameterTypeMax. lengthDescription
passedBoolean
extractionMethodJumioScanMode[jumioscanmode]Extraction method used during scanning (FACE_MANUAL, FACE_IPROOV, JUMIO_LIVENESS)
imageDataJumioImageDataWrapper class for accessing image data of all credential parts from an ID verification session. This feature has to be enabled by your account manager.

Class JumioRejectReason

List of all possible reject reasons the SDK could return if Instant Feedback is used:

info

Please be aware that the list of reject reasons that get returned depends on server-side configuration for every individual merchant.

CodeMessageDescription
102BLACK_WHITE_COPYDocument appears to be a black and white photocopy
103COLOR_PHOTOCOPYDocument appears to be a colored photocopy
104DIGITAL_COPYDocument appears to be a digital copy
200NOT_READABLEDocument is not readable
201NO_DOCNo document could be detected
206MISSING_BACKBackside of the document is missing
214MISSING_FRONTFrontside of the document is missing
401UNSUPPORTED_DOCUMENTDocument is not supported
501INVALID_CERTIFICATEDocument certificate could not be validated
2001BLURRYDocument image is unusable because it is blurry
2003MISSING_PART_DOCPart of the document is missing
2004HIDDEN_PART_DOCPart of the document is hidden
2005DAMAGED_DOCUMENTDocument appears to be damaged
2006GLAREDocument image is unusable because of glare

Error Codes

List of all error codes that are available via the code and message properties of the [JumioError][jumioerror] object. The first letter (A-J) represents the error case. The remaining characters are represented by numbers that contain information helping us understand the problem situation (format: [xx][yyyy]).

CodeMessageDescription
A[xx][yyyy]We have encountered a network communication problemRetry possible, user decided to cancel
B[xx][yyyy]Authentication failedSecure connection could not be established, retry impossible
C[xx]0401Authentication failedAPI credentials invalid, retry impossible
E[xx]0000Connection errorRetry possible, user decided to cancel
F[xx]0000Scanning not available at this time, please contact the app vendorResources cannot be loaded, retry impossible
G[xx]0000Cancelled by end-userNo error occurred
H[xx]0000The camera is currently not availableCamera cannot be initialized, retry impossible
I[xx]0000Certificate not valid anymore. Please update your applicationEnd-to-end encryption key not valid anymore, retry impossible
J[xx]0000Transaction already finishedUser did not complete SDK journey within session lifetime
N[xx]0000Scanning not available at this time, please contact the app vendorRequired images are missing to finalize the acquisition
tip

Please always include error code and message when filing an error related issue to our support team.

Session Initialization Best Practices

  • Generate SDK tokens just-in-time before SDK launch.
  • Implement backend-controlled retry logic.
  • Use reportingCriteria and Customer Internal Reference for tracking.
  • Ensure runtime permissions are granted before launch.

Default UI

In case you're using Jumio's Default UI module (see Dependencies) you may declare the JumioActivity in your AndroidManifest.xml. With this you can use Jumio's default theme or specify a custom theme (see Customization for details). Also you can set the orientation to be sensor based or locked by using the attribute android:screenOrientation. Please note though that some screens in Jumio SDK launch in portrait mode only.

<activity
android:theme="@style/Theme.Jumio"
android:hardwareAccelerated="true"
android:name="com.jumio.defaultui.JumioActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" />

Custom UI

ID Verification can be also implemented as a custom scan view. This means that only the scan view (including the scan overlays) are provided by the SDK. The handling of the lifecycle, document selection, readability confirmation, intermediate callbacks, and all other steps necessary to complete a scan have to be handled by the client application that implements the SDK.

The following sequence diagram outlines components, callbacks and methods for a basic ID Verification workflow:

Custom UI Happy Path Diagram

note

The new 3D face liveness capturing technology is not optimized for tablets. When using Selfie Verification, the face scanner will fallback to a simple face capturing functionality instead. Portrait orientation support is required in your app.

CustomUI enables you to use a custom scan view with a plain scanning user interface. Initialize the Jumio SDK and set [token][token] and [datacenter][datacenter].

sdk = JumioSDK(context: Context).apply {
token = "YOUR_SDK_TOKEN"
datacenter = JumioDataCenter.YOUR_DATACENTER
}
  • [JumioDataCenter][datacenter] values: US, EU, SG

UI/UX Best Practices

  • Launch SDK only after explicit user consent.
  • Show pre-permission screens explaining camera use.
  • Prompt better lighting for retries.
  • Avoid flashlight use by default.
  • Use SDK localization.

Controller Handling

Start the SDK by passing context and an instance of your class that implements [JumioControllerInterface][jumiocontrollerinterface]. You will receive a [JumioController][jumiocontroller] object in return:

val jumioController: JumioController = sdk.start(context, jumioControllerInterface)

When the jumioController is initialized, the following callback will be triggered:

onInitialized(credentials: List<JumioCredentialInfo>, consentItems: List<JumioConsentItems>?)

To support compliance with various data protection laws, if a user’s consent is required the parameter consentItems will provide a list of [JumioConsentItems][jumioconsentitem]. Each consent item contains a text, a consent type and an URL that will redirect the user to Jumio’s consent details. Each [JumioConsentItem][jumioconsentitem] also provides a method spannedTextWithLinkColor(color: Int) that will return a spanned string containing the consent text and the link holder. If no color is specified, the link portion of the spanned string will only be underlined.

If no consent is required, the parameter consentItems will be null.

Each consent item can be one of two types:

  • [JumioConsentType.ACTIVE][jumioconsenttype]
  • [JumioConsentType.PASSIVE][jumioconsenttype]

For ACTIVE types, the user needs to accept the consent items explicitly, e.g. by enabling a UI switch or checking a checkbox for each consent item. For PASSIVE types, it is enough to present the consent text and URL to the user. The user implicitly accepts the passive consent items by continuing with the journey. For details please check out consent handling (1) (2) and consent adapter in our sample app.

The user can open and continue to the provided consent link if they choose to do so. If the user consents to Jumio's policy, [jumioController.userConsented(consentItem: JumioConsentItem, userConsent: Boolean)][userconsented] is required to be called internally before any credential can be initialized and the user journey can continue. If no consent is required, the list of [JumioConsentItems][jumioconsentitem] will be null. If the user does not consent or if [jumioController.userConsented(consentItem: JumioConsentItem, userConsent: Boolean)][userconsented] is not called for all the items inside the consentItems list, the user will not be able to continue the user journey.

note

Please be aware that in cases where the list of consentItems is not null, the user must consent to Jumio's processing of personal information, including biometric data, and be provided a link to Jumio's Privacy Notice. Do not accept automatically without showing the user any terms.

Credential Handling

Obtain an instance of [JumioCredential][jumiocredential] which will contain all necessary information about the verification process by calling start on the JumioController.

For ID verification you will receive a [JumioIDCredential][jumioidcredential], for Selfie Verification a [JumioFaceCredential][jumiofacecredential], and so on. Call [isConfigured][isconfigured] to check if the credential is already pre-configured. If so, it can be started right away.

val currentCredentialInfo = ...

val currentCredential = jumioController.start(currentCredentialInfo)
if (currentCredential?.isConfigured == true) {
// credential can be started
}

If the credential is not configured yet, it needs some more configuration before scan parts can be initialized. Details on how to configure each credential and retrieve the first [scan part][jumioscanpart] can be found below.

  • [JumioCredentialCategory][jumiocredentialcategory] values: ID, FACE, DOCUMENT, DATA

Jumio ID Credential

In case of [JumioIDCredential][jumioidcredential], you can retrieve all available countries from [supportedCountries][supportedcountries]. After selecting a specific country from that list, you can query available documents for that country by either calling [getPhysicalDocumentsForCountry][getphysicaldocuments] or [getDigitalDocumentsForCountry][getdigitaldocuments]. To configure the [JumioIDCredential][jumioidcredential], pass your desired document as well as the country to [setConfiguration()][setidconfiguration].

Retrieve the supported countries:

idCredential = ... // Credential received via jumioController.start

val countries: List<String> = idCredential.countries

val country = countries.first { ... } // Select your desired country

Query available physical documents (e.g. passports or driving licenses):

val jumioDocuments = idCredential.getPhysicalDocumentsForCountry(country)

val document = jumioDocuments.first { it.type == JumioDocumentType.PASSPORT }

Query available digital documents ("Digital Identities"):

val jumioDocuments = idCredential.getDigitalDocumentsForCountry(country)

val document = jumioDocuments.first()

Set a valid country / document configuration:

idCredential.setConfiguration(country, document)
  • [JumioPhysicalDocument][jumiophysicaldocument] represents a single JumioDocumentType and JumioDocumentVariant combination

    • [JumioDocumentType][jumiodocumenttype] values: PASSPORT, VISA, DRIVING_LICENSE, ID_CARD

    • [JumioDocumentVariant][jumiodocumentvariant] values: PAPER, PLASTIC

  • [JumioDigitalDocument][jumiodigitaldocument] represents a digital document ("Digital Identity")

Once the credential is configured, it is ready to initialize it's first scan part and start the verification process:

val credentialPart = idCredential.credentialParts.first()
idCredential.initScanPart(credentialPart, yourScanPartInterface)

Jumio Face Credential

In case of [JumioFaceCredential][jumiofacecredential], Jumio uses Certified Liveness technology to determine liveness. The mode can be detected by checking the [JumioScanMode][jumioscanmode] of the [JumioScanPart][jumioscanpart]. Make sure to also implement FACE_MANUAL as a fallback, in case JUMIO_LIVENESS or FACE_IPROOV is not available.

Retrieve the credential part of the credential to start the scanning process by calling:

val credentialPart = currentCredential?.credentialParts?.first()
val scanPart = currentCredential?.initScanPart(credentialPart, yourScanPartInterface)

or use the convenience method

val scanPart = currentCredential?.initScanPart(yourScanPartInterface)

Jumio Document Credential

In case of [JumioDocumentCredential][jumiodocumentcredential], there is the option to either acquire the image using the camera or selecting a PDF file from the device. Call setConfiguration with a [JumioAcquireMode][acquiremode] to select the preferred mode as described in the code documentation.

  • [JumioAcquireMode][acquiremode] values: CAMERA, FILE
val acquireModes: List<JumioAcquireMode> = (credential as JumioDocumentCredential).availableAcquireModes

(currentCredential as JumioDocumentCredential).setConfiguration(acquireModes[0])

Retrieve the credential part of the credential to start the scanning process by calling:

val credentialPart = currentCredential?.credentialParts?.first()
val scanPart = currentCredential?.initScanPart(credentialPart, yourScanPartInterface)

or use the convenience method

val scanPart = currentCredential?.initScanPart(yourScanPartInterface)

If [JumioAcquireMode][acquiremode] FILE is used, the [JumioFileAttacher][jumiofileattacher] needs to be utilized to add a File or FileDescriptor for the selected [JumioScanPart][jumioscanpart].

val fileAttacher = JumioFileAttacher()
fileAttacher.attach(scanPart)

val file = File("/path/to/your/file.pdf")
fileAttacher.setFile(file)

Jumio Data Credential

note

JumioDataCredential is only available from SDK version 4.2.0 to 4.8.1 (inclusively).

[JumioDataCredential][jumiodatacredential] is used for the device fingerprinting. There are some optional configurations you can do to enhance it's behavior.

  1. Add the following Android permissions to your AndroidManifest.xml, if not already added:
<manifest>
<!--Get user's GPS Location.-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!--Get User's Wifi name and Status.-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

<!--Get User's Network information and State.-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<!--Get Phone and Network information (MNC, MCC, IMEI, Phone Number, Phone Type (GSM/CDMA), SIM Number, etc).-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<!--Get user's Biometric authentication settings (Face or Fingerprint authentication).-->
<uses-permission android:name="android.permission.USE_BIOMETRIC" />

<!--Get user's Biometric authentication settings (Face or Fingerprint authentication).-->
<uses-permission android:name="android.permission.USE_FINGERPRINT" />

<!--Write data into device to check re-installation behavior.-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<!--Get External storage status, total size, free size, etc.-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<!--Get GSFID (Google Services Id) for accurate identification for unique users.-->
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
</manifest>
note
  • The reason for the requirement of the given permission is added as inline comment.
  • Some of them are dangerous permissions, and you have to ask for the permission from the user. More information about permissions can be found in the official Android documentation
  • The above permissions imply to add some features to your manifest file:
  <uses-feature
android:name="android.hardware.location"
android:required="false"/>

<uses-feature
android:name="android.hardware.telephony"
android:required="false"/>

<uses-feature
android:name="android.hardware.wifi"
android:required="false"/>
  1. If you use proguard for obfuscation, you have to add some rules to your [proguard-rules.pro][proguardrules] configuration file:
   -keep com.google.android.gms.*
-keep com.google.android.gms.tasks.*
-keep com.google.android.gms.ads.identifier.AdvertisingIdClient

ScanPart Handling

The following sequence diagram outlines an overview of ScanPart handling details: ScanPart Happy Path Diagram

Start the scanning process by initializing the [JumioScanPart][jumioscanpart]. A list of mandatory [JumioCredentialPart][jumiocredentialpart]s is retrievable over currentCredential?.credentialParts as soon as the credential is configured. Possible values are:

currentScanPart = currentCredential?.initScanPart(credentialPart, yourJumioScanPartInterface)

  • [JumioCredentialPart][jumiocredentialpart] values: FRONT, BACK, MULTIPART, FACE, DOCUMENT, NFC, DIGITAL

Each [jumioScanPart][jumioScanPart] has an associated scanMode. Depending on the scan mode, you need to provide a different user guidance. The following scan modes are available for the different JumioCredentialParts:

  • [JumioScanMode][jumioScanMode] values:
    • FRONT, BACK, MULTIPART: MANUAL, BARCODE, DOCFINDER
    • DIGITAL: WEB, FILE
    • NFC: NFC
    • FACE: FACE_MANUAL, FACE_IPROOV, JUMIO_LIVENESS, JUMIO_PREMIUM
    • DOCUMENT: MANUAL, FILE

During the scanning process, use the onUpdate function of the JumioScanPartInterface to check on the scanning progress and update your user guidance accordingly.

MULTIPART handles the scanning of multiple sides in one seamless capture experience. When a [MULTIPART][jumiomultipart] scan part is started, an additional [NEXT_PART][nextpart] step is sent after [IMAGE_TAKEN][imagetaken]. This signals that another side of the document should be scanned now. The step returns the [JumioCredentialPart][jumiocredentialpart] that should be scanned next. We suggest to actively guide the user to move to the next part, e.g. by showing an animation and by disabling the extraction during the animation. Please also check the new [NEXT_PART][nextpart] scan step for this [JumioCredentialPart][jumiocredentialpart]

Start the execution of the acquired [JumioScanPart][jumioscanpart] by calling [currentScanPart?.start()][startscanpart].

When the scanning is done, the parameter [JumioScanStep.CAN_FINISH][canfinish] will be received and the scan part can be finished by calling [currentScanPart?.finish()][finishscanpart].

Check if the credential is complete by calling [currentCredential?.isComplete][iscompletecredential] and finish the current credential by calling [currentCredential?.finish()][finishcredential].

Continue that procedure until all needed credentials (e.g. ID, FACE, DOCUMENT) are finished. Check if all credentials are finished with [jumioController.isComplete][iscompletecontroller], then call [jumioController?.finish()][finishcontroller] to finish the user journey.

The callback [onFinished()][onfinished] will be received after the controller has finished:

override fun onFinished(result: JumioResult) {
log("onFinished")
sdkResult.value = result
}

Scan Steps

During the scanning process [onScanStep()][onscanstep] will be called as soon as the [JumioScanPart][jumioscanpart] needs additional input to continue the scanning journey. The provided [JumioScanStep][jumioscanstep] indicates what needs to be done next.

[JumioScanStep][jumioscanstep]s cover lifecycle events which require action from the customer to continue the process.

[JumioScanStep][jumioscanstep] values: PREPARE, STARTED, ATTACH_ACTIVITY, ATTACH_FILE, SCAN_VIEW, NEXT_PART, IMAGE_TAKEN, PROCESSING, CONFIRMATION_VIEW, REJECT_VIEW, RETRY, CAN_FINISH, ADDON_SCAN_PART, DIGITAL_IDENTITY_VIEW, THIRD_PARTY_VERIFICATION

[PREPARE][prepare] is only sent if a scan part requires upfront preparation and the customer should be notified (e.g. by displaying a loading screen):

JumioScanStep.PREPARE -> {
showLoadingView()
}

[STARTED][started] is always sent when a scan part is started. If a loading spinner was triggered before, it can now be dismissed:

JumioScanStep.STARTED -> {
hideLoadingView()
}

[DIGITAL_IDENTITY_VIEW][digitalidentityview] points out that the current [JumioScanPart][jumioscanpart] needs to be attached to a [JumioDigitalIdentityView][jumiodiview]. The [JumioDigitalIdentityView][jumiodiview] is a custom view that can be placed in your layout.

JumioScanStep.DIGITAL_IDENTITY_VIEW -> {
currentScanPart?.let {
jumioDigitalIdentityView.attach(it)
}
}

[THIRD_PARTY_VERIFICATION][thirdpartyverification] is triggered in case the current [JumioScanPart][jumioscanpart] will switch to a third party's application to continue the verification process (e.g. for Digital Identity verification). As this might take some time, showing a loading indicator is recommended.

JumioScanStep.THIRD_PARTY_VERIFICATION -> {
showLoadingView()
}

[ATTACH_ACTIVITY][attachactivity] indicates that an Activity Context is needed. Please see [JumioActivityAttacher][jumioactivityattacher] for more information.

JumioScanStep.ATTACH_ACTIVITY -> {
currentScanPart?.let {
JumioActivityAttacher(this).attach(it)
}
}

[ATTACH_FILE][attachfile] is sent when the user needs to select and upload a file. For this, you should create a [JumioFileAttacher][jumiofileattacher], add it to your [JumioScanPart][jumioscanpart] and provide the document. This step is only sent, when the scan method is FILE.

JumioScanStep.ATTACH_FILE -> {
currentScanPart?.let {
val jumioFileAttacher = JumioFileAttacher()
jumioFileAttacher.attach(it)
// Choose how the file should be attached
// jumioFileAttacher.setFileDescriptor(<your file descriptor>)
// jumioFileAttacher.setFile(<your file>)
}
}

[SCAN_VIEW][scanview] is sent, when the scan view should be displayed. On this view, the user will capture a photo or a sequence of photos of a document or of a face with the camera. [JumioScanView][jumioscanview] needs to be attached to the [JumioScanPart][jumioscanpart]. The [JumioScanView][jumioscanview] is a custom view that can be placed in your layout. During runtime it just needs to be attached to the [JumioScanPart][jumioscanpart]. Make sure to re-attach the scanview from scan steps [STARTED][started] or [NEXT_PART][nextpart] in case the activity gets recreated and the scanview was attached before.

JumioScanStep.SCAN_VIEW -> {
currentScanPart?.let {
jumioScanView.attach(it)
}
}

[IMAGE_TAKEN][imagetaken] is triggered as soon as all required images for the current part are captured and uploaded to the Jumio server. This event might be followed by a [NEXT_PART][nextpart] event with additional information on which part has to be scanned next (if any).

When all parts are done and background processing is executed, [JumioScanStep.PROCESSING][processing] is triggered. The camera preview might be stopped during that step.

If images for confirmation or rejection need to be displayed then [JumioScanStep.CONFIRMATION_VIEW][confirmationview] or [JumioScanStep.REJECT_VIEW][rejectview] is triggered. Attach the [JumioConfirmationHandler][jumioconfirmationhandler] or [JumioRejectHandler][jumiorejecthandler] once the steps are triggered and render the available [JumioCredentialParts][jumiocredentialpart] in [JumioConfirmationView][jumioconfirmationview] or [JumioRejectView][jumiorejectview] objects:

JumioScanStep.CONFIRMATION_VIEW -> {
val confirmationHandler = ConfirmationHandler()
confirmationHandler.attach(scanPart)
confirmationHandler.parts.forEach {
val confirmationView = JumioConfirmationView(context)
confirmationHandler.renderPart(it, confirmationView)
...
}
}
JumioScanStep.REJECT_VIEW -> {
val rejectHandler = RejectHandler()
rejectHandler.attach(scanPart)
rejectHandler.parts.forEach {
val rejectView = JumioRejectView(context)
rejectHandler.renderPart(it, rejectView)
...
}
}

The scan part can be confirmed by calling [confirmationView.confirm()][confirm] or retaken by calling [confirmationView.retake()][retakeconfirmation] or [rejectView.retake()][retakereject].

The retry scan step returns a data object of type [JumioRetryReason][jumioretryreason]. On [RETRY][retry], a retry should be triggered on the scan part.

JumioScanStep.RETRY -> {
val reason = data as? JumioRetryReason ?: return

val retryCode = reason.code
val retryMessage = reason.message
...

currentScanPart?.retry(reason)
}

For possible retry codes please checkout [JumioRetryReasonGeneric][jumioretrygeneric], [JumioRetryReasonDocumentVerification][jumioretrydv], [JumioRetryReasonNfc][jumioretrynfc], [JumioRetryReasonIproov][jumioretryiproov] and [JumioRetryReasonDigitalIdentity][jumioretrydi].

As soon as the scan part has been confirmed and all processing has been completed [CAN_FINISH][canfinish] is triggered. [scanPart.finish()][finishscanpart] can now be called. During the finish routine the SDK checks if there is an add-on functionality for this part available, e.g. possible NFC scanning after an MRZ scan part. In this case [ADDON_SCAN_PART][addonscanpart] will be called.

When an add-on to the current scan part is available, [JumioScanStep.ADDON_SCAN_PART][addonscanpart] is sent. The add-on scan part can be retrieved using the method addonScanPart = currentCredential?.getAddonPart().

To see if the finished credential part was the last one of the credential, check currentCredentialPart == currentCredential?.credentialPart?.last(). Check if the credential is complete by calling [currentCredential?.isComplete][isComplete] and finish the current credential by calling [currentCredential?.finish()][credentialFinish].

Continue that procedure until all necessary credentials (e.g. ID, FACE, DOCUMENT, DATA) are finished. Check if the last credential is finished, then call [controller?.finish()][controllerFinish] to end the user journey.

Scan Updates

[JumioScanUpdates][jumioscanupdate]s are distributed via the JumioScanPartInterface method [onUpdate()][onupdate] and cover scan information that is relevant and might need to be displayed during scanning process.
An optional value data of type Any can contain additional information for each scan update as described.

[JumioScanUpdate][jumioscanupdate] values: CAMERA_AVAILABLE, FALLBACK, NFC_EXTRACTION_STARTED, NFC_EXTRACTION_PROGRESS, NFC_EXTRACTION_FINISHED, CENTER_ID, HOLD_STRAIGHT, MOVE_CLOSER, TOO_CLOSE, HOLD_STILL, MOVE_FACE_CLOSER, FACE_TOO_CLOSE, NEXT_POSITION, FLASH, TILT, IMAGE_ANALYSIS

In case of FALLBACK, the scanMode has changed and you should adapt the user interface to reflect the new scan mode. Check the JumioScanView[jumioscanview] method isShutterEnabled[isshutterenabled] and see if it returns true. If this is the case, a manual shutter button needs to be displayed for the end user to capture an image.

All possible [JumioFallbackReason][fallbackreason] values are sent in the optional data value to indicate the reason of the fallback.

NFC_EXTRACTION_STARTED, NFC_EXTRACTION_PROGRESS, and NFC_EXTRACTION_FINISHED make it possible to track the progress of an NFC scan. NFC_EXTRACTION_PROGRESS additionally delivers an integer in the data parameter in the range of 0-100 to signal the progress in the current data group.

NEXT_POSITION signals that the user needs to take a second image, e.g., needs to move the face in a liveness scan.

For the scanMode DOCFINDER, the following scan updates are sent: CENTER_ID, TOO_CLOSE, MOVE_CLOSER, HOLD_STRAIGHT, TILT, FLASH

FOR ID scans, a Long representing the time for which the user needs to hold still is sent in the data parameter of JumioScanPartInterface.onUpdate, when the extraction state HOLD_STILL is returned.

TILT signals that during an ID scan, the document in front of the camera needs to be tilted. The current angle as well as the target angle are transmitted as [JumioTiltState][jumiotiltstate] via the data parameter. A negative current angle indicates that the document needs to be tilted in the other direction. When a tilt update is sent, advise the user to tilt the identity document by e.g. showing an animation or an overlay.

FLASH signals the enabling or disabling of the camera flash.

IMAGE_ANALYSIS signals that the image is being analyzed.

We suggest to disable orientation changes during the states FLASH and IMAGE_ANALYSIS. Please note - fallback and camera switch will also not be available during these stages.

We send the following extraction states for the scan modes JUMIO_LIVENESS and JUMIO_PREMIUM: CENTER_FACE, FACE_TOO_CLOSE, MOVE_FACE_CLOSER, MOVE_FACE_INTO_FRAME, LEVEL_EYES_AND_DEVICE, HOLD_STILL, TILT_FACE_UP, TILT_FACE_DOWN, TILT_FACE_LEFT, TILT_FACE_RIGHT

override fun onUpdate(jumioScanUpdate: JumioScanUpdate, data: Any?) {
when(jumioScanUpdate) {
JumioScanUpdate.FALLBACK -> handleFallback(data as JumioFallbackReason)
JumioScanUpdate.FLASH -> handleFlash(data as JumioFlashState)
JumioScanUpdate.TILT -> handleTilt(data as JumioTiltState)
... // handle other scan updates
}
}

Result and Error Handling

Instead of using the standard method onActivityResult(), implement the following methods within your [jumioControllerInterface][jumiocontrollerinterface] for successful scans and error notifications:

The method onFinished(result: JumioResult) has to be implemented to handle data after a successful scan, which will return [JumioResult][jumioresult].

override fun onFinished(result: JumioResult) {
val data = result
// handle success case
finish()
}

The method onError(error: JumioError) has to be implemented to handle data after an unsuccessful scan, which will return [JumioError][jumioerror]. Check the parameter [error.isRetryable][isretryable] to see if the failed scan attempt can be retried.

override fun onError(error: JumioError) {
if (error.isRetryable) {
// retry scan attempt
} else {
// handle error case
}
log(String.format("onError: %s, %s, %s", error.code, error.message, if (error.isRetryable) "true" else "false"))
}

If an error is retryable, [jumioController.retry()][retrycontroller] should be called to execute a retry.

Error Handling & Retry Strategy

  • Categorize errors: soft (retry allowed) vs hard (exit flow).
  • On failure: create new account ID or reuse existing account ID with new session.
  • Redirect to retry/support screen instead of immediate SDK relaunch.
  • Log errors without storing PII.

Instant Feedback

The use of Instant Feedback provides immediate end user feedback by performing a usability check on any image the user took and prompting them to provide a new image immediately if this image is not usable, for example because it is too blurry. Please refer to the JumioRejectReason table for a list of all reject possibilities.

Customization

The Jumio SDK provides various options to customize its UI. If you are using Default UI you can change each screen to fulfil your needs. In case you decide to implement the verification workflow on your own (see Custom UI) you also have the possibility to influence the look and feel of some views provided by the SDK, e.g. [JumioScanView][jumioscanview].

Customization Tool

Jumio Surface is a web tool that offers the possibility to apply and visualize all available customization options for the Jumio SDK, as well as an export feature that generates all data needed to import the desired changes straight into your codebase.

Jumio Surface

Default UI customization

The surface tool utilizes each screen of Jumio's Default UI to visualize all items and colors that can be customized. If you are planning to use the Default UI implementation, you can specify the Theme.Jumio as a parent style in your application and override according attributes within this theme to match your application's look and feel.

After customizing the SDK via the surface tool, you can click the Android-Xml button in the Output menu on the bottom right to copy the code from the theme AppThemeCustomJumio to your Android app's styles.xml file.

Apply your custom theme that you defined before by replacing Theme.Jumio in the AndroidManifest.xml:

<activity
android:name="com.jumio.defaultui.JumioAcitivty"
android:theme="@style/AppThemeCustomJumio">
...
</activity>

Dark Mode

Theme.Jumio attributes can also be customized for dark mode. If you haven't done so already, create a values-night folder in your resources directory and add a new styles.xml file. Adapt your custom Jumio theme for dark mode. The SDK will switch automatically to match the system settings of the user device.

Custom UI customization

If you implement your own UI, you can still customize how some views provided by the SDK look. In particular this means you can customize Jumio's scan overlay, NFC scanning and iProov Face liveness views at the moment.

By following the steps explained in Default UI customization you can see potential attributes to override in the generated XML file.

Testing & Validation

  • Use Jumio official sample apps to validate flows.
  • Test on varied device tiers and OS versions.
  • Test multiple ID types and lighting conditions.

Security

All SDK related traffic is sent over HTTPS using TLS and public key pinning. Additionally, the information itself within the transmission is also encrypted utilizing Application Layer Encryption (ALE). ALE is a Jumio custom-designed security protocol that utilizes RSA-OAEP and AES-256 to ensure that the data cannot be read or manipulated even if the traffic was captured.

Token Management & Session Security

  • Always create SDK tokens server-side.
  • Auth Tokens are valid for 60 Mins. Kindly reuse it
  • Pass Auth tokens securely using HTTPS only and store in-memory only.
  • Never hard-code or store tokens creation mechanism on devices.
  • Always log Account ID and workflowExecutionId.

Support

Licenses

The software contains third-party open source software. For more information, see licenses.

This software is based in part on the work of the Independent JPEG Group.

Contact

If you have any questions regarding our implementation guide please contact Jumio Customer Service at support@jumio.com. The Jumio online helpdesk contains a wealth of information regarding our services including demo videos, product descriptions, FAQs, and other resources that can help to get you started with Jumio.