Skip to main content
A lightweight, server-driven Android SDK for identity verification with minimal configuration required.

GitHub Repository

View source code and examples on GitHub

Requirements

RequirementMinimum Version
Android API23+ (Android 6.0 Marshmallow)
Kotlin1.9+
Jetpack ComposeIncluded as transitive dependency

Installation

Step 1: Add the Repository

Add the Didit Maven repository to the repositories block in your settings.gradle.kts:
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository") }
    }
}
Or if using settings.gradle (Groovy):
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url "https://raw.githubusercontent.com/didit-protocol/sdk-android/main/repository" }
    }
}

Step 2: Add the Dependency

Add the SDK dependency to your app’s build.gradle.kts:
dependencies {
    implementation("me.didit:didit-sdk:1.0.0")
}
Or if using build.gradle (Groovy):
dependencies {
    implementation "me.didit:didit-sdk:1.0.0"
}

Step 3: Add Packaging Exclusion

Add this to your app’s android block to avoid build conflicts:
android {
    packaging {
        resources {
            excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
        }
    }
}
That’s it! Gradle will automatically resolve all transitive dependencies.

Permissions

The SDK requires the following permissions. These are declared in the SDK’s AndroidManifest.xml and will be merged automatically into your app’s manifest:
PermissionDescriptionRequired
INTERNETNetwork access for API communication✅ Yes
ACCESS_NETWORK_STATEDetect network availability✅ Yes
CAMERADocument scanning and face verification✅ Yes
NFCRead NFC chips in passports/ID cards⚠️ If using NFC

Camera and NFC Features

The SDK declares android.hardware.camera and android.hardware.nfc as optional features (android:required="false"). This ensures your app can be installed on devices without a camera or NFC hardware — the SDK will gracefully handle missing hardware at runtime.

Quick Start

Step 1: Initialize the SDK

Initialize the SDK in your Application.onCreate():
import me.didit.sdk.DiditSdk

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        DiditSdk.initialize(this)
    }
}

Step 2: Start Verification and Handle Results

import me.didit.sdk.DiditSdk
import me.didit.sdk.DiditSdkState
import me.didit.sdk.VerificationResult

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Observe SDK state to launch UI when ready
        lifecycleScope.launch {
            DiditSdk.state.collect { state ->
                when (state) {
                    is DiditSdkState.Ready -> DiditSdk.launchVerificationUI(this@MainActivity)
                    is DiditSdkState.Error -> Log.e("Didit", "Error: ${state.message}")
                    else -> { /* Loading, Idle, CreatingSession */ }
                }
            }
        }
    }

    private fun startVerification() {
        // Option A: With session token from your backend
        DiditSdk.startVerification(
            token = "your-session-token"
        ) { result ->
            handleResult(result)
        }

        // Option B: With workflow ID (SDK creates session)
        // DiditSdk.startVerification(
        //     workflowId = "your-workflow-id",
        //     vendorData = "user-123"
        // ) { result ->
        //     handleResult(result)
        // }
    }

    private fun handleResult(result: VerificationResult) {
        when (result) {
            is VerificationResult.Completed -> {
                Log.d("Didit", "Session: ${result.session.sessionId}")
                Log.d("Didit", "Status: ${result.session.status.rawValue}")
            }
            is VerificationResult.Cancelled -> {
                Log.d("Didit", "User cancelled")
            }
            is VerificationResult.Failed -> {
                Log.e("Didit", "Failed: ${result.error.message}")
            }
        }
    }
}

Integration Methods

The SDK supports two integration methods: Create a session on your backend using the Create Verification Session API, then pass the token to the SDK:
// Your backend creates a session and returns the token
val sessionToken = yourBackend.createVerificationSession(userId = currentUser.id)

// Pass the token to the SDK
DiditSdk.startVerification(
    token = sessionToken
) { result ->
    handleResult(result)
}
This approach gives you full control over:
  • Associating sessions with your users (vendor_data)
  • Setting custom metadata
  • Configuring callbacks per session

Method 2: Workflow ID (Simpler Integration)

For simpler integrations, the SDK can create sessions directly using your workflow ID:
DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    vendorData = "user-123"
) { result ->
    handleResult(result)
}

Configuration

Customize the SDK behavior:
import me.didit.sdk.Configuration
import me.didit.sdk.core.localization.SupportedLanguage

val configuration = Configuration(
    languageLocale = SupportedLanguage.SPANISH,  // Force Spanish language
    customIntroScreen = false,                    // Use SDK's intro screen
    fontFamily = "my_custom_font",                // Custom font (must be in res/font/)
    loggingEnabled = true                         // Enable debug logging
)

DiditSdk.startVerification(
    token = "your-session-token",
    configuration = configuration
) { result ->
    handleResult(result)
}

Configuration Options

PropertyTypeDefaultDescription
languageLocaleSupportedLanguage?Device localeForce a specific language
customIntroScreenBooleanfalseSkip SDK’s intro screen (use your own)
fontFamilyString?System fontCustom font resource name (from res/font/)
loggingEnabledBooleanfalseEnable SDK debug logging
Theming & Colors: Colors, backgrounds, and intro screen settings are configured through your White Label settings in the Didit Console, not in the SDK configuration. This ensures consistent branding across all platforms.

Language Support

The SDK supports 40+ languages. If no language is specified, the SDK uses the device locale with English as fallback.
// Use device locale (default)
val config = Configuration()

// Force specific language
val config = Configuration(languageLocale = SupportedLanguage.FRENCH)
View All Supported Languages →

Advanced Options

Contact Details (Prefill & Notifications)

Provide contact details to prefill verification forms and enable email notifications:
import me.didit.sdk.models.ContactDetails

val contactDetails = ContactDetails(
    email = "[email protected]",
    sendNotificationEmails = true,  // Send status update emails
    emailLang = "en",               // Email language (ISO 639-1)
    phone = "+14155552671"          // E.164 format
)

DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    contactDetails = contactDetails
) { result ->
    handleResult(result)
}

Expected Details (Cross-Validation)

Provide expected user details for automatic cross-validation with extracted document data:
import me.didit.sdk.models.ExpectedDetails

val expectedDetails = ExpectedDetails(
    firstName = "John",
    lastName = "Doe",
    dateOfBirth = "1990-05-15",   // YYYY-MM-DD format
    nationality = "USA",          // ISO 3166-1 alpha-3
    country = "USA"
)

DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    expectedDetails = expectedDetails
) { result ->
    handleResult(result)
}

Custom Metadata

Store custom JSON metadata with the session (not displayed to user):
DiditSdk.startVerification(
    workflowId = "your-workflow-id",
    vendorData = "user-123",
    metadata = "{\"internalId\": \"abc123\", \"source\": \"mobile\"}"
) { result ->
    handleResult(result)
}

Handling Results

The VerificationResult sealed class provides the outcome of the verification:

Result Cases

CaseDescription
Completed(session)Verification flow completed (check session.status for result)
Cancelled(session)User cancelled the verification flow
Failed(error, session)An error occurred during verification

SessionData Properties

PropertyTypeDescription
sessionIdStringUnique session identifier
statusVerificationStatusAPPROVED, PENDING, or DECLINED

Error Types

ErrorDescription
SessionExpiredThe session has expired
NetworkErrorNetwork connectivity issue
CameraAccessDeniedCamera permission not granted
NotInitializedSDK not initialized
Unknown(message)Other error with message

Complete Result Handling Example

DiditSdk.startVerification(token = "your-token") { result ->
    when (result) {
        is VerificationResult.Completed -> {
            when (result.session.status) {
                VerificationStatus.APPROVED -> {
                    Log.d("Didit", "Approved! Session: ${result.session.sessionId}")
                    // User is verified - grant access
                }
                VerificationStatus.PENDING -> {
                    Log.d("Didit", "Under review. Session: ${result.session.sessionId}")
                    // Show "verification in progress" UI
                }
                VerificationStatus.DECLINED -> {
                    Log.d("Didit", "Declined. Session: ${result.session.sessionId}")
                    // Handle declined verification
                }
            }
        }
        is VerificationResult.Cancelled -> {
            Log.d("Didit", "Cancelled: ${result.session?.sessionId ?: "unknown"}")
            // User chose to cancel - maybe show retry option
        }
        is VerificationResult.Failed -> {
            Log.e("Didit", "Error: ${result.error.message}")
            // Handle error - show retry or contact support
        }
    }
}

Observing SDK State

You can observe the SDK state for custom loading UI:
lifecycleScope.launch {
    DiditSdk.state.collect { state ->
        when (state) {
            is DiditSdkState.Idle -> {
                // Ready to start verification
            }
            is DiditSdkState.CreatingSession -> {
                // Show "Creating session..." progress
            }
            is DiditSdkState.Loading -> {
                // Show loading indicator
            }
            is DiditSdkState.Ready -> {
                // Verification UI is ready - launch it
                DiditSdk.launchVerificationUI(this@MainActivity)
            }
            is DiditSdkState.Error -> {
                // Show error message
                Log.e("Didit", "Error: ${state.message}")
            }
        }
    }
}

ProGuard / R8

The SDK includes its own consumer ProGuard rules. No additional configuration is needed. If you use R8 full mode, you may need to add this to your gradle.properties:
android.enableR8.fullMode=false

Complete Example

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import me.didit.sdk.Configuration
import me.didit.sdk.DiditSdk
import me.didit.sdk.DiditSdkState
import me.didit.sdk.VerificationResult
import me.didit.sdk.VerificationStatus
import me.didit.sdk.core.localization.SupportedLanguage
import me.didit.sdk.models.ContactDetails

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Observe SDK state
        lifecycleScope.launch {
            DiditSdk.state.collect { state ->
                when (state) {
                    is DiditSdkState.Ready -> DiditSdk.launchVerificationUI(this@MainActivity)
                    is DiditSdkState.Error -> Log.e("Didit", "Error: ${state.message}")
                    else -> { /* Idle, Loading, CreatingSession */ }
                }
            }
        }
    }

    fun startVerification() {
        val config = Configuration(
            languageLocale = SupportedLanguage.ENGLISH,
            loggingEnabled = true
        )

        // Option A: With session token from your backend
        DiditSdk.startVerification(
            token = "your-session-token",
            configuration = config
        ) { result ->
            handleResult(result)
        }

        // Option B: With workflow ID (SDK creates session)
        // DiditSdk.startVerification(
        //     workflowId = "your-workflow-id",
        //     vendorData = "user-123",
        //     contactDetails = ContactDetails(email = "[email protected]"),
        //     configuration = config
        // ) { result ->
        //     handleResult(result)
        // }
    }

    private fun handleResult(result: VerificationResult) {
        when (result) {
            is VerificationResult.Completed -> {
                when (result.session.status) {
                    VerificationStatus.APPROVED -> {
                        Log.d("Didit", "Approved! Session: ${result.session.sessionId}")
                    }
                    VerificationStatus.PENDING -> {
                        Log.d("Didit", "Under review")
                    }
                    VerificationStatus.DECLINED -> {
                        Log.d("Didit", "Declined")
                    }
                }
            }
            is VerificationResult.Cancelled -> {
                Log.d("Didit", "Cancelled: ${result.session?.sessionId ?: "unknown"}")
            }
            is VerificationResult.Failed -> {
                Log.e("Didit", "Error: ${result.error.message}")
            }
        }
    }
}