Requirements and prerequisites
Requirements
Veriff Android SDK needs your minSdkVersion to be of 26 or above
Kotlin
1.9.0or aboveSupports
android-gradle-pluginversion7.2.0and aboveThe SDK is using AndroidX support libraries
List of all direct transitive dependencies
androidx.annotation:annotation:1.7.1
androidx.appcompat:appcompat:1.6.1
androidx.constraintlayout:constraintlayout:2.1.4
androidx.core:core-ktx:1.9.0
androidx.databinding:viewbinding:8.8.0
androidx.exifinterface:exifinterface:1.3.7
androidx.fragment:fragment-ktx:1.5.7
androidx.lifecycle:lifecycle-runtime-ktx:2.5.1
androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1
androidx.vectordrawable:vectordrawable-seekable:1.0.0-beta01
com.google.android.gms:play-services-mlkit-face-detection:17.1.0
com.google.android.material:material:1.4.0
com.google.auto.value:auto-value-annotations:1.7
com.google.dagger:dagger:2.48.1
com.squareup.okhttp3:logging-interceptor:4.10.0
com.squareup.okhttp3:okhttp:4.10.0
com.squareup.okio:okio:3.2.0
com.squareup.okio:okio-jvm:3.2.0
org.bouncycastle:bcprov-jdk18on:1.76
org.bouncycastle:bcutil-jdk18on:1.76
org.jetbrains.kotlin:kotlin-stdlib:1.9.0
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4
androidx.annotation:annotation-experimental:1.1.0
androidx.concurrent:concurrent-futures:1.1.0
androidx.core:core:1.9.0
androidx.lifecycle:lifecycle-common:2.5.1
androidx.lifecycle:lifecycle-livedata:2.5.1
com.google.guava:listenablefuture:1.0
androidx.compose:compose-bom:2023.08.00
androidx.compose.foundation:foundation:1.5.0
androidx.compose.foundation:foundation-layout:1.5.0
androidx.compose.material3:material3:1.1.1
androidx.compose.runtime:runtime:1.5.0
androidx.compose.ui:ui:1.5.0
com.google.android.play:integrity:1.3.0
Prerequisites
You have an active account with Veriff (see the Getting Started section)
You have an integration with Veriff (see the Getting Started section)
You have set up webhook(s) to get replies from Veriff (see the Webhooks section)
Add Android SDK to the project
Step 1: Add a new Maven destination
Open the root build.gradle file and add a new Maven destination to the repositories in the allprojects section:
allprojects {
repositories {
maven { url = uri("https://cdn.veriff.me/android/") }
google()
mavenCentral()
}
}allprojects {
repositories {
maven { url "https://cdn.veriff.me/android/" }
google()
mavenCentral()
}
}Alternatively, when using Gradle 7+, add the Maven repository to your settings.gradle file:
dependencyResolutionManagement {
repositories {
maven { url = uri("https://cdn.veriff.me/android/") }
google()
mavenCentral()
}
}dependencyResolutionManagement {
repositories {
maven { url "https://cdn.veriff.me/android/" }
google()
mavenCentral()
}
}Step 2: Add the Veriff SDK dependency
Add to the application build.gradle file:
implementation("com.veriff:veriff-library:$latestVeriffAndroidSdkVersion")implementation 'com.veriff:veriff-library:$latestVeriffAndroidSdkVersion'Add permissions
The Veriff Android SDK automatically adds required permissions to your app through Android's manifest merger. You do not need to manually declare these permissions in your app's AndroidManifest.xml, they are included automatically when you integrate the SDK.
The SDK requires the following permissions to function properly.
Runtime permissions (requires user approval)
Permission | Purpose | When required? |
|---|---|---|
CAMERA | Capture photos and videos for identity verification | When the end-user starts verification flow |
RECORD_AUDIO | Record video with audio during verification | When the end-user starts video recording |
Normal permissions (auto-granted)
Permission | Purpose | When required? / Details |
|---|---|---|
INTERNET | Upload verification media and communicate with Veriff servers | Required for all SDK operations |
ACCESS_NETWORK_STATE | Check network connectivity before uploads | Ensures uploads don't fail on poor connections |
WAKE_LOCK | Keep CPU running during background uploads | Prevents incomplete uploads when screen turns off (max 2 minutes) |
FOREGROUND_SERVICE | Run upload service reliably | Required for Android 8.0+ background upload service |
Declare foreground service type | Required for Android 14+ (data synchronization service) | |
NFC | Read NFC-enabled identity documents | Used for passport/ID card NFC reading feature. If enabled, you can set up NFC data listener to get real-time data. |
VIBRATE | Provide haptic feedback | Enhances user experience during verification |
Foreground service information declaration in Play Console
The SDK declares and uses the FOREGROUND_SERVICE_DATA_SYNC.
If you distribute your application on Google Play, then you must declare the foreground service information in Play Console (Policy > App content > Foreground service Permissions) . Read the instructions in the Google Play[↗].
According to Google, you need to:
- Provide a description of the app functionality that is using each foreground service type.
- You may use the following description: “The Veriff SDK uses the foreground service to upload end-user data to Veriff's servers for verification purposes.”
- Describe the user impact if the task is deferred by the system (does not start immediately), and/or the task is interrupted by the system (paused and/or restarted).
- You may use the following description: “If the task is deferred or interrupted by the system, the end-user verification will be delayed.”
- Include a link to a video demonstrating each foreground service feature. The video should demonstrate the steps the user needs to take in your app in order to trigger the feature.
- Please record a video of your app's Veriff SDK integration and share it (via link, Youtube, etc.)
- Choose your specific use case for each foreground service type.
- Select use case: "Network transfer: Upload or download / Other"
See also Veriff's note on data collection purposes in your app [↗].
Note that all the info above is only for Google for review purposes, it is not accessible to the end-users.
FAQ - Permissions
Can I reduce the number of permissions?
No. All permissions are required for core SDK functionality. Removing any permission will cause crashes.
Why does the SDK need WAKE_LOCK?
To ensure verification uploads complete even if the user locks their phone. Without it, uploads may fail on slow connections.
Is NFC permission required if we don't use NFC verification?
The permission is declared but harmless if unused. It's a "normal" permission (auto-granted) and won't prompt users.
Does FOREGROUND_SERVICE_DATA_SYNC require user permission?
No, it's a normal permission. The foreground service shows a notification but doesn't require explicit user approval.
Will these permissions affect App Store approval?
No, these are standard permissions for identity verification SDKs. Ensure your privacy policy accurately describes their usage.
Start the verification flow
The verification flow must be launched from the activity class with a unique session (= sessionURL).
import com.veriff.Sdk
val intent = Sdk.createLaunchIntent(activity, sessionUrl)
startActivityForResult(intent, REQUEST_CODE)import com.veriff.Sdk;
Intent intent = Sdk.createLaunchIntent(activity, sessionUrl);
startActivityForResult(intent, REQUEST_CODE);Parameter | Description |
|---|---|
| An constant integer that is defined in your activity and identifies the request. It helps differentiate this request from others when the result is returned in the A constant integer that identifies the request. It helps differentiate this request from others when the result is returned in the |
| A combination of the |
* Required parameter
A session is valid for 7 days and expires automatically after that.
What happens after the end-user leaves the flow?
When the end-user leaves the verification flow, i.e. a session is canceled or finished, the Veriff SDK is closed. The end-user is taken back to your application. The end-user flow completion status is returned to the host application, see the Get verification session status sub-section below for more info.
Verification session status
When a session is cancelled or finished, the Veriff SDK is closed and the end-user is taken back to your application.
Callbacks about the end-user flow completion status are sent to your mobile application. To capture the status, override the onActivityResult method in your activity that started the verification flow.
This is not the verification session decision.
This indicates whether the end-user was able to complete all the steps in the verification flow or not.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE) {
val result = Result.fromResultIntent(data)
result?.let {
handleResult(it)
}
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun handleResult(result: Result) {
when (result.status) {
Status.DONE -> {
// The end-user successfully submitted the session, the session is completed from their perspective
}
Status.CANCELED -> {
// The end-user canceled the verification process
}
Status.ERROR -> {
// An error occurred during the flow, Veriff has already shown UI, no need to display
// a separate error message here
Log.w(TAG, "Verification error occurred: ${result.error}")
}
}
}@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
Result result = Result.fromResultIntent(data);
if (result != null) {
handleResult(result); //see below for handling the result
}
}
super.onActivityResult(requestCode, resultCode, data);
}
public void handleResult(Result result) {
switch (result.getStatus()) {
case DONE:
// The end-user successfully submitted the session, the session is completed from their perspective
break;
case CANCELED:
// The end-user canceled the verification process
break;
case ERROR:
// An error occurred during the flow, Veriff has already shown UI, no need to display
// a separate error message here
Log.w(TAG, "Verification error occurred: " + result.getError());
break;
}
}Verification session decision
Veriff returns info about the verification session decision, extracted data, registries checks etc. via webhooks. You need to set up webhooks and tie them to your system.
→ See Webhooks Guide > Set up webhooks sub-section for detailed overview of the setup process
Add error logging
To turn on logging, add your logging implementation instance (instance of com.veriff.Logger class) to the SDK before launching the SDK.
Sdk.setLogger(myLoggerImplementation)
val intent = Sdk.createLaunchIntent(activity, sessionUrl)
startActivityForResult(intent, REQUEST_CODE)Sdk.setLogger(myLoggerImplementation);
Intent intent = Sdk.createLaunchIntent(activity, sessionUrl);
startActivityForResult(intent, REQUEST_CODE);Customize the SDK
SDK customization is optional
It is possible to customize the look and feel of the UI to match your branding. You can change primitives such as colors and fonts, set the language settings for the SDK, and change if/how an intro screen is displayed.
Match the brand
You can customize the look and feel of the SDK flow by passing a Branding object via Configuration to createLaunchIntent as shown and explained in the example below.
Note: all custom values for branding are optional. If a value is not provided for them, the default Veriff color and logo will be used.
Branding properties list
Property | Type | Description | Usage |
|---|---|---|---|
| ColorInt | Main brand color used for primary actions and accents | Buttons, highlights |
| ColorInt | Secondary brand color for alternative actions | Secondary buttons |
| ColorInt | Main background color | Screen backgrounds |
| ColorInt | Primary text/content color on background | Main text |
| ColorInt | Secondary text color for supporting content | Hint text, secondary info |
| ColorInt | Tertiary text color for less important content | Disabled text, placeholders |
| ColorInt | Background color for camera overlay | Camera screen background |
| ColorInt | Text/content color on camera overlay | Camera screen text |
| ColorInt | Border and divider color | Borders, separators |
| ColorInt | Error state color | Error messages, feedback |
| ColorInt | Success state color | Success messages, feedback |
| ColorInt | Content color on primary color backgrounds | Text on primary buttons |
| ColorInt | Content color on secondary color backgrounds | Text on secondary buttons |
| Float (DP) | Corner radius for buttons in density pixels | Button styling |
| DrawableRes | Brand logo resource ID | Header/branding display |
| DrawableRes | Notification icon resource ID | Push notifications |
| Font | Custom font configuration (optional) | Typography styling |
Branding object options
import com.example.mysdk.Branding
import com.example.mysdk.Configuration
import com.example.mysdk.Sdk
// ... other imports
fun launchSdk() {
val branding = Branding.Builder()
.logo(R.drawable.logo)
.background(resources.getColor(R.color.background_color))
.onBackground(resources.getColor(R.color.on_background_color))
.onBackgroundSecondary(resources.getColor(R.color.on_background_secondary_color))
.onBackgroundTertiary(resources.getColor(R.color.on_background_tertiary_color))
.primary(resources.getColor(R.color.primary_color))
.onPrimary(resources.getColor(R.color.on_primary_color))
.secondary(resources.getColor(R.color.secondary_color))
.onSecondary(resources.getColor(R.color.on_secondary_color))
.cameraOverlay(resources.getColor(R.color.camera_overlay_color))
.onCameraOverlay(resources.getColor(R.color.on_camera_overlay_color))
.outline(resources.getColor(R.color.outline_color))
.success(resources.getColor(R.color.success_color))
.error(resources.getColor(R.color.error_color))
.buttonRadius(48f)
.build()
val configuration = Configuration.Builder()
.branding(branding)
.build()
val intent = Sdk.createLaunchIntent(this, sessionUrl, configuration)
startActivityForResult(intent, REQUEST_CODE)
}Branding branding = new Branding.Builder()
.logo(R.drawable.logo)
// Screen and dialog background color
.background(getResources().getColor(R.color.background_color))
// Non-surface content (such as text, icons) displayed on `background`.
// Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
.onBackground(getResources().getColor(R.color.on_background_color))
// Secondary non-surface content (such as text) displayed on `background`.
// Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
.onBackgroundSecondary(getResources().getColor(R.color.on_background_secondary_color))
// Tertiary non-surface content (such as text) displayed on `background`.
// Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
.onBackgroundTertiary(getResources().getColor(R.color.on_background_tertiary_color))
// Primary surfaces (such as buttons) displayed on `background`.
// Accessibility: Must have a contrast ratio of at least 3:1 vs `background`
.primary(getResources().getColor(R.color.primary_color))
// Non-surface content (such as text) displayed on `primary` surfaces.
// Accessibility: Must have a contrast ratio of at least 4.5:1 vs `primary`
.onPrimary(getResources().getColor(R.color.on_primary_color))
// Secondary surfaces (such as bullet points and illustrations) displayed on `background`.
// Accessibility: Must have a contrast ratio of at least 3:1 vs `background`
.secondary(getResources().getColor(R.color.secondary_color))
// Non-surface content (such as text) displayed on `secondary` surfaces.
// Accessibility: Must have a contrast ratio of at least 4.5:1 vs `secondary`
.onSecondary(getResources().getColor(R.color.on_secondary_color))
// Backgroung color of the overlay area on all the screens with camera
.cameraOverlay(getResources().getColor(R.color.camera_overlay_color))
// All UI elements on all the screens with camera on top of camera overlay
// Accessibility: Must have a contrast ratio of at least 4.5:1 vs `cameraOverlay`
.onCameraOverlay(getResources().getColor(R.color.on_camera_overlay_color))
// Color used for various outlines and boundaries of UI elements
.outline(getResources().getColor(R.color.outline_color))
// Error indicators (such as text, borders, icons) displayed on `background`
// Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
.success(getResources().getColor(R.color.success_color))
// Success indicators (such as borders, icons) displayed on `background`
// Accessibility: Must have a contrast ratio of at least 3:1 vs `background`
.error(getResources().getColor(R.color.error_color))
// Button corner radius, in `dp`
.buttonRadius(48f)
.build();
Configuration configuration = new Configuration.Builder()
.branding(branding)
.build();
Intent intent = Sdk.createLaunchIntent(activity, sessionUrl, configuration);
startActivityForResult(intent, REQUEST_CODE);→ See the Visual SDK customization guides article for design examples
Font
You can customize the fonts used in the SDK by passing the resource IDs of the fonts you want to use. Make sure that you have added the font files to the font resource folder in your app.
A custom font can be set by passing a com.veriff.Font object to the font method of Branding builder. The com.veriff.Font builder accepts three types of fonts via the setRegular, setMedium and setBold methods.
brandingBuilder.font = com.veriff.Font.Builder()
.setRegular(R.font.comic_neue_regular)
.setMedium(R.font.comic_neue_medium)
.setBold(R.font.comic_neue_bold)
.build()brandingBuilder.font(
new com.veriff.Font.Builder()
.setRegular(R.font.comic_neue_regular)
.setMedium(R.font.comic_neue_medium)
.setBold(R.font.comic_neue_bold)
.build()
);Intro screen
It is possible to customise if the end-user flow begins with Veriff intro screen or no intro screen at all.
In some cases, it is possible to skip the Veriff’s generic introduction screen and use your own before Veriff’s SDK is launched.
Check with your Solutions Engineer to confirm if this feature can be enabled for your integration
If it is possible, then:
You agree your own introduction screen visuals and copy with our Solutions Engineer and get relevant legal documents signed in case they are needed
After that Veriff will enable custom introduction screen from backend for your integrations
After you have implemented your own introduction screen you can change the configuration option specified below
val configuration = Configuration.Builder()
.customIntroScreen(true)
.build()Configuration configuration = new Configuration.Builder()
.customIntroScreen(true)
.build();Adding the configuration alone in your app is not enough to enable the custom intro screen. Make sure to contact your solutions engineer so they can enable the feature for your integration.
User interface locale settings
You can set a locale(java.util.Locale) for the SDK from the app itself.
val appLocale = Locale.ENGLISH
val configuration = Configuration.Builder()
.locale(appLocale)
.build()
val intent = Sdk.createLaunchIntent(activity, sessionUrl, configuration)
startActivityForResult(intent, REQUEST_CODE)Locale appLocale = Locale.ENGLISH;
Configuration configuration = new Configuration.Builder()
.locale(appLocale)
.build();
Intent intent = Sdk.createLaunchIntent(activity, sessionUrl, configuration);
startActivityForResult(intent, REQUEST_CODE);→ See Supported languages in SDKs article for more info
Light/dark mode
Cross-platform support
Light/dark mode is supported through branding settings (Branding object), but not through automatic system detection. You can define two sets of branding colors and manually switch between them based on the end-user's system preference. This means that runtime theme switching is not supported: if the end-user flow is already started with provided set of colors, changing theme in the setting will not be reflected in the SDK.
In a nutshell it works as follows:
You create two separate
Brandingconfigurations (one for light, one for dark) for your host app.Your host app detects the end-user’s system's dark/light mode.
You pass the appropriate branding configuration when launching the Veriff SDK.
→ See the table with branding properties above for list of available branding properties.
Step 1: create two branding configurations
Light mode
The sample code below uses placeholder color values. Ensure that you use your brand colors.
val lightBranding = Branding.Builder()
// Background Colors
.background(Color.WHITE) // #FFFFFF
// Primary Brand Colors
.primary(Color.parseColor("#03282C")) // Dark teal
.secondary(Color.parseColor("#14E5C5")) // Light teal/cyan
// Content on Light Background
.onBackground(Color.parseColor("#03282C")) // Dark text
.onBackgroundSecondary(Color.parseColor("#757575")) // Gray text
.onBackgroundTertiary(Color.parseColor("#11615C")) // Muted text
// Primary Button Colors
.onPrimary(Color.WHITE) // White text on primary
.onSecondary(Color.parseColor("#03282C")) // Dark text on secondary
// Camera Screen
.cameraOverlay(Color.parseColor("#03282C")) // Dark overlay
.onCameraOverlay(Color.WHITE) // White text
// Feedback & Borders
.outline(Color.parseColor("#919191")) // Gray borders
.error(Color.parseColor("#E02006")) // Red error
.success(Color.parseColor("#5BC868")) // Green success
// Styling
.buttonRadius(48f) // Fully rounded buttons
.logo(R.drawable.my_logo_light)
.notificationIcon(R.drawable.ic_notification)
.build()Branding lightBranding = new Branding.Builder()
// Background Colors
.background(Color.WHITE) // #FFFFFF
// Primary Brand Colors
.primary(Color.parseColor("#03282C")) // Dark teal
.secondary(Color.parseColor("#14E5C5")) // Light teal/cyan
// Content on Light Background
.onBackground(Color.parseColor("#03282C")) // Dark text
.onBackgroundSecondary(Color.parseColor("#757575")) // Gray text
.onBackgroundTertiary(Color.parseColor("#11615C")) // Muted text
// Primary Button Colors
.onPrimary(Color.WHITE) // White text on primary
.onSecondary(Color.parseColor("#03282C")) // Dark text on secondary
// Camera Screen
.cameraOverlay(Color.parseColor("#03282C")) // Dark overlay
.onCameraOverlay(Color.WHITE) // White text
// Feedback & Borders
.outline(Color.parseColor("#919191")) // Gray borders
.error(Color.parseColor("#E02006")) // Red error
.success(Color.parseColor("#5BC868")) // Green success
// Styling
.buttonRadius(48f) // Fully rounded buttons
.logo(R.drawable.my_logo_light)
.notificationIcon(R.drawable.ic_notification)
.build();Dark mode
The sample code below uses placeholder color values. Ensure that you use your brand colors.
val darkBranding = Branding.Builder()
// Background Colors
.background(Color.parseColor("#03282C")) // Dark background
// Primary Brand Colors (More vibrant in dark mode)
.primary(Color.parseColor("#14E5C5")) // Bright teal/cyan
.secondary(Color.parseColor("#14E5C5")) // Same bright teal
// Content on Dark Background
.onBackground(Color.WHITE) // White text
.onBackgroundSecondary(Color.parseColor("#B0B0B0")) // Light gray
.onBackgroundTertiary(Color.parseColor("#14E5C5")) // Brand color accent
// Primary Button Colors
.onPrimary(Color.parseColor("#03282C")) // Dark text on bright primary
.onSecondary(Color.WHITE) // White text on secondary
// Camera Screen
.cameraOverlay(Color.BLACK) // Pure black overlay
.onCameraOverlay(Color.WHITE) // White text
// Feedback & Borders
.outline(Color.parseColor("#505050")) // Dark gray borders
.error(Color.parseColor("#FF6B6B")) // Bright red
.success(Color.parseColor("#69DB7C")) // Bright green
// Styling
.buttonRadius(48f)
.logo(R.drawable.my_logo_dark) // Light-colored logo for dark background
.notificationIcon(R.drawable.ic_notification)
.build()Branding darkBranding = new Branding.Builder()
// Background Colors
.background(Color.parseColor("#03282C")) // Dark background
// Primary Brand Colors (More vibrant in dark mode)
.primary(Color.parseColor("#14E5C5")) // Bright teal/cyan
.secondary(Color.parseColor("#14E5C5")) // Same bright teal
// Content on Dark Background
.onBackground(Color.WHITE) // White text
.onBackgroundSecondary(Color.parseColor("#B0B0B0")) // Light gray
.onBackgroundTertiary(Color.parseColor("#14E5C5")) // Brand color accent
// Primary Button Colors
.onPrimary(Color.parseColor("#03282C")) // Dark text on bright primary
.onSecondary(Color.WHITE) // White text on secondary
// Camera Screen
.cameraOverlay(Color.BLACK) // Pure black overlay
.onCameraOverlay(Color.WHITE) // White text
// Feedback & Borders
.outline(Color.parseColor("#505050")) // Dark gray borders
.error(Color.parseColor("#FF6B6B")) // Bright red
.success(Color.parseColor("#69DB7C")) // Bright green
// Styling
.buttonRadius(48f)
.logo(R.drawable.my_logo_dark) // Light-colored logo for dark background
.notificationIcon(R.drawable.ic_notification)
.build();Step 2: detect system theme
The sample code below uses placeholder values. Your production code must reference your real values.
import android.content.res.Configuration
fun isSystemDarkModeEnabled(context: Context): Boolean {
val isDarkMode = when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
Configuration.UI_MODE_NIGHT_YES -> true
Configuration.UI_MODE_NIGHT_NO -> false
else -> false
}
return isDarkMode
}
// Usage in Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val isDarkMode = isSystemDarkModeEnabled(this)
val branding = if (isDarkMode) darkBranding else lightBranding
// Pass branding to Veriff SDK
startVeriffFlow(branding)
}import android.content.Context;
import android.content.res.Configuration;
public static boolean isSystemDarkModeEnabled(Context context) {
int uiMode = context.getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK;
if (uiMode == Configuration.UI_MODE_NIGHT_YES) {
return true;
} else if (uiMode == Configuration.UI_MODE_NIGHT_NO) {
return false;
} else {
return false;
}
}
// Usage in Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean isDarkMode = isSystemDarkModeEnabled(this);
Branding branding = isDarkMode ? darkBranding : lightBranding;
// Pass branding to Veriff SDK
startVeriffFlow(branding);
}Step 3: launch app with appropriate branding configuration
The sample code below uses placeholder values. Your production code must reference your real values.
class MyActivity : AppCompatActivity() {
// Define theme configurations
private val lightBranding = Branding.Builder()
.background(Color.WHITE)
.primary(Color.parseColor("#03282C"))
.secondary(Color.parseColor("#14E5C5"))
.onBackground(Color.parseColor("#03282C"))
.onBackgroundSecondary(Color.parseColor("#757575"))
.onBackgroundTertiary(Color.parseColor("#11615C"))
.onPrimary(Color.WHITE)
.onSecondary(Color.parseColor("#03282C"))
.cameraOverlay(Color.parseColor("#03282C"))
.onCameraOverlay(Color.WHITE)
.outline(Color.parseColor("#919191"))
.error(Color.parseColor("#E02006"))
.success(Color.parseColor("#5BC868"))
.buttonRadius(48f)
.logo(R.drawable.logo_light)
.build()
private val darkBranding = Branding.Builder()
.background(Color.parseColor("#03282C"))
.primary(Color.parseColor("#14E5C5"))
.secondary(Color.parseColor("#14E5C5"))
.onBackground(Color.WHITE)
.onBackgroundSecondary(Color.parseColor("#B0B0B0"))
.onBackgroundTertiary(Color.parseColor("#14E5C5"))
.onPrimary(Color.parseColor("#03282C"))
.onSecondary(Color.WHITE)
.cameraOverlay(Color.BLACK)
.onCameraOverlay(Color.WHITE)
.outline(Color.parseColor("#505050"))
.error(Color.parseColor("#FF6B6B"))
.success(Color.parseColor("#69DB7C"))
.buttonRadius(48f)
.logo(R.drawable.logo_dark)
.build()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Detect system theme and apply appropriate branding
val branding = getThemeAwareBranding()
// Launch Veriff with appropriate branding
launchVeriff(branding)
}
private fun getThemeAwareBranding(): Branding {
val isDarkMode = when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
Configuration.UI_MODE_NIGHT_YES -> true
Configuration.UI_MODE_NIGHT_NO -> false
else -> false
}
return if (isDarkMode) darkBranding else lightBranding
}
private fun launchVeriff(branding: Branding) {
val sessionBundle = Bundle().apply {
putString("SESSION_TOKEN", "your_session_token")
// Pass branding to Veriff SDK
}
// Start Veriff activity with branding
// Implementation depends on your Veriff SDK integration method
}
}import android.content.res.Configuration;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MyActivity extends AppCompatActivity {
// Define theme configurations
private final Branding lightBranding = new Branding.Builder()
.background(Color.WHITE)
.primary(Color.parseColor("#03282C"))
.secondary(Color.parseColor("#14E5C5"))
.onBackground(Color.parseColor("#03282C"))
.onBackgroundSecondary(Color.parseColor("#757575"))
.onBackgroundTertiary(Color.parseColor("#11615C"))
.onPrimary(Color.WHITE)
.onSecondary(Color.parseColor("#03282C"))
.cameraOverlay(Color.parseColor("#03282C"))
.onCameraOverlay(Color.WHITE)
.outline(Color.parseColor("#919191"))
.error(Color.parseColor("#E02006"))
.success(Color.parseColor("#5BC868"))
.buttonRadius(48f)
.logo(R.drawable.logo_light)
.build();
private final Branding darkBranding = new Branding.Builder()
.background(Color.parseColor("#03282C"))
.primary(Color.parseColor("#14E5C5"))
.secondary(Color.parseColor("#14E5C5"))
.onBackground(Color.WHITE)
.onBackgroundSecondary(Color.parseColor("#B0B0B0"))
.onBackgroundTertiary(Color.parseColor("#14E5C5"))
.onPrimary(Color.parseColor("#03282C"))
.onSecondary(Color.WHITE)
.cameraOverlay(Color.BLACK)
.onCameraOverlay(Color.WHITE)
.outline(Color.parseColor("#505050"))
.error(Color.parseColor("#FF6B6B"))
.success(Color.parseColor("#69DB7C"))
.buttonRadius(48f)
.logo(R.drawable.logo_dark)
.build();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Detect system theme and apply appropriate branding
Branding branding = getThemeAwareBranding();
// Launch Veriff with appropriate branding
launchVeriff(branding);
}
private Branding getThemeAwareBranding() {
int uiMode = getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK;
boolean isDarkMode = (uiMode == Configuration.UI_MODE_NIGHT_YES);
return isDarkMode ? darkBranding : lightBranding;
}
private void launchVeriff(Branding branding) {
Bundle sessionBundle = new Bundle();
sessionBundle.putString("SESSION_TOKEN", "your_session_token");
// Pass branding to Veriff SDK
// Start Veriff activity with branding
// Implementation depends on your Veriff SDK integration method
}
}Multiple theme presets management
For managing multiple theme presets, use a data class.
The sample code below uses placeholder values. If you decide to create a data class, your production code must reference the real class name.
@Serializable
data class ThemeConfig(
val name: String,
@ColorInt val primary: Int,
@ColorInt val secondary: Int,
@ColorInt val background: Int,
@ColorInt val onBackground: Int,
@ColorInt val onBackgroundSecondary: Int,
@ColorInt val onBackgroundTertiary: Int,
@ColorInt val cameraOverlay: Int,
@ColorInt val onCameraOverlay: Int,
@ColorInt val outline: Int,
@ColorInt val error: Int,
@ColorInt val success: Int,
@ColorInt val onPrimary: Int,
@ColorInt val onSecondary: Int,
val buttonRadius: Float = 8f,
) {
fun toBranding(): Branding = Branding.Builder()
.primary(primary)
.secondary(secondary)
.background(background)
.onBackground(onBackground)
.onBackgroundSecondary(onBackgroundSecondary)
.onBackgroundTertiary(onBackgroundTertiary)
.cameraOverlay(cameraOverlay)
.onCameraOverlay(onCameraOverlay)
.outline(outline)
.error(error)
.success(success)
.onPrimary(onPrimary)
.onSecondary(onSecondary)
.buttonRadius(buttonRadius)
.build()
}
// Usage
val themes = mapOf(
"light" to ThemeConfig("light", /* colors... */),
"dark" to ThemeConfig("dark", /* colors... */)
)
val selectedTheme = if (isDarkMode) themes["dark"] else themes["light"]
val branding = selectedTheme?.toBranding()// ThemeConfig.java
public class ThemeConfig {
public final String name;
public final int primary;
public final int secondary;
public final int background;
public final int onBackground;
public final int onBackgroundSecondary;
public final int onBackgroundTertiary;
public final int cameraOverlay;
public final int onCameraOverlay;
public final int outline;
public final int error;
public final int success;
public final int onPrimary;
public final int onSecondary;
public final float buttonRadius;
public ThemeConfig(
String name,
int primary,
int secondary,
int background,
int onBackground,
int onBackgroundSecondary,
int onBackgroundTertiary,
int cameraOverlay,
int onCameraOverlay,
int outline,
int error,
int success,
int onPrimary,
int onSecondary,
float buttonRadius
) {
this.name = name;
this.primary = primary;
this.secondary = secondary;
this.background = background;
this.onBackground = onBackground;
this.onBackgroundSecondary = onBackgroundSecondary;
this.onBackgroundTertiary = onBackgroundTertiary;
this.cameraOverlay = cameraOverlay;
this.onCameraOverlay = onCameraOverlay;
this.outline = outline;
this.error = error;
this.success = success;
this.onPrimary = onPrimary;
this.onSecondary = onSecondary;
this.buttonRadius = buttonRadius;
}
// Overload with default buttonRadius = 8f
public ThemeConfig(String name, int primary, int secondary, int background,
int onBackground, int onBackgroundSecondary, int onBackgroundTertiary,
int cameraOverlay, int onCameraOverlay, int outline, int error,
int success, int onPrimary, int onSecondary) {
this(name, primary, secondary, background, onBackground,
onBackgroundSecondary, onBackgroundTertiary, cameraOverlay,
onCameraOverlay, outline, error, success, onPrimary, onSecondary, 8f);
}
public Branding toBranding() {
return new Branding.Builder()
.primary(primary)
.secondary(secondary)
.background(background)
.onBackground(onBackground)
.onBackgroundSecondary(onBackgroundSecondary)
.onBackgroundTertiary(onBackgroundTertiary)
.cameraOverlay(cameraOverlay)
.onCameraOverlay(onCameraOverlay)
.outline(outline)
.error(error)
.success(success)
.onPrimary(onPrimary)
.onSecondary(onSecondary)
.buttonRadius(buttonRadius)
.build();
}
}
// Usage
Map<String, ThemeConfig> themes = new HashMap<>();
themes.put("light", new ThemeConfig("light", /* colors... */));
themes.put("dark", new ThemeConfig("dark", /* colors... */));
ThemeConfig selectedTheme = isDarkMode ? themes.get("dark") : themes.get("light");
Branding branding = selectedTheme != null ? selectedTheme.toBranding() : null;Best practices
Define both light and dark variants for all colors
Test with actual system dark mode toggle
Ensure sufficient contrast for accessibility (WCAG AA minimum)
Store theme configurations for easy updates
Use proper color values that work in both themes
Do not use hardcoded colors without theme consideration
Ensure you have defined
onCameraOverlayfor camera screens
Need to exclude ML Kit support?
Veriff Android SDK uses ML Kit[↗] for things like automatic selfie capture and accessibility feedback. It uses on-device models that are pre-downloaded by Play services.
If your app cannot use Play services at all, then you can exclude the transitive mlkit dependency. This will remove any dependencies on ML Kit and disable the use of these ML modules at runtime.
implementation("com.veriff:veriff-library:6.+") {
exclude(group = "com.veriff", module = "mlkit")
}implementation('com.veriff:veriff-library:6.+') {
exclude group: 'com.veriff', module: 'mlkit'
}Changelog
Date | Description |
|---|---|
Mar 9, 2026 |
|
Feb 3, 2026 | Link to new article "Android SDK: NFC data listener” added to Normal permissions (auto-granted) table |
Jan 19, 2026 | Details added to Add permissions section:
|
Mar 12, 2025 | Documentation published |