Skip to main content

SmartComply Android SDK

The SmartComply Android SDK delivers a fully self-contained identity verification flow for Android apps. Launch one Activity and the SDK handles session management, country and ID-type selection, document capture, identity verification, and liveness detection automatically.

Features

  • Single-Activity launch — start verification with one Intent and receive a typed result back
  • Two verification modes — document photo capture or ID number data entry, configured from your Dashboard
  • Guide-box document capture — frames the ID card precisely so images are always clean and correctly cropped
  • Liveness detection — camera-based face challenge system (blink, turn head) runs automatically after identity verification
  • Dynamic ID types — channels and fields are fetched live from your Dashboard configuration
  • Multi-country support — renders a country picker automatically when more than one country is configured
  • Dark and light mode — theme adapts to the system setting; override via the launch intent

Requirements

  • Android API 24 (Android 7.0) or later
  • Kotlin 1.9 or later
  • Jetpack Compose enabled in your module

Installation

1 — Add Maven Central

In settings.gradle.kts (already present in most projects):
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}

2 — Add the dependency

In your app or feature module build.gradle.kts:
dependencies {
    implementation("io.github.386konsult:android-sdk:1.0.0")
}

3 — Enable Compose

android {
    buildFeatures {
        compose = true
    }
}

Permissions

The SDK declares these permissions automatically via manifest merge. You do not need to add them manually unless your project uses a custom manifest merge strategy:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
The SDK requests the CAMERA permission at runtime before the camera is used. Your app does not need to request it separately.

Quick Start

1 — Register the result launcher

In your Activity or Fragment:
import androidx.activity.result.contract.ActivityResultContracts
import com.smartcomply.sdk.ui.SmartComplyActivity
import com.smartcomply.sdk.types.FlowResult

val verificationLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    val data = result.data ?: return@registerForActivityResult
    when (data.getStringExtra(SmartComplyActivity.RESULT_TYPE)) {
        SmartComplyActivity.TYPE_SUCCESS -> {
            val entryId      = data.getIntExtra(SmartComplyActivity.RESULT_ENTRY_ID, -1)
            val status       = data.getStringExtra(SmartComplyActivity.RESULT_STATUS)
            val verifiedName = data.getStringExtra(SmartComplyActivity.RESULT_VERIFIED_NAME)
            val idTypeName   = data.getStringExtra(SmartComplyActivity.RESULT_ID_TYPE_NAME)
            // handle success
        }
        SmartComplyActivity.TYPE_FAILURE -> {
            val errorMsg = data.getStringExtra(SmartComplyActivity.RESULT_ERROR_MSG)
            // handle error
        }
        SmartComplyActivity.TYPE_CANCELLED -> {
            // user pressed back
        }
    }
}

2 — Launch verification

import com.smartcomply.sdk.client.Environment
import java.util.UUID

val intent = SmartComplyActivity.buildIntent(
    from        = this,
    apiKey      = "pk_live_xxxxxxxxxxxx",   // your SmartComply API key
    clientId    = UUID.randomUUID().toString(), // unique per verification attempt
    environment = Environment.PRODUCTION
)
verificationLauncher.launch(intent)

Jetpack Compose

If you are launching from a composable, use rememberLauncherForActivityResult:
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.rememberCoroutineScope
import com.smartcomply.sdk.ui.SmartComplyActivity
import com.smartcomply.sdk.client.Environment
import java.util.UUID

@Composable
fun StartVerificationButton() {
    val context = LocalContext.current

    val launcher = rememberLauncherForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        val data = result.data ?: return@rememberLauncherForActivityResult
        when (data.getStringExtra(SmartComplyActivity.RESULT_TYPE)) {
            SmartComplyActivity.TYPE_SUCCESS   -> { /* handle success */ }
            SmartComplyActivity.TYPE_FAILURE   -> { /* handle error */ }
            SmartComplyActivity.TYPE_CANCELLED -> { /* user cancelled */ }
        }
    }

    Button(onClick = {
        val intent = SmartComplyActivity.buildIntent(
            from        = context,
            apiKey      = "pk_live_xxxxxxxxxxxx",
            clientId    = UUID.randomUUID().toString(),
            environment = Environment.PRODUCTION
        )
        launcher.launch(intent)
    }) {
        Text("Verify Identity")
    }
}

buildIntent Parameters

fun buildIntent(
    from:        Context,
    apiKey:      String,
    clientId:    String,
    darkTheme:   Boolean? = null,                    // null = follow system
    environment: Environment = Environment.PRODUCTION
): Intent
ParameterDefaultDescription
fromThe calling Context
apiKeyYour SmartComply API key — find it in the Dashboard
clientIdA unique ID per verification attempt — use UUID.randomUUID().toString()
darkThemenulltrue forces dark mode, false forces light, null follows the device setting
environmentPRODUCTIONPRODUCTION for live verification, SANDBOX for testing

Result Extras

Read from the Intent returned to your activity result callback.
ConstantTypePresent when
RESULT_TYPEStringAlways — "success", "failure", or "cancelled"
RESULT_ENTRY_IDIntTYPE_SUCCESS
RESULT_STATUSStringTYPE_SUCCESS — e.g. "submitted", "verified"
RESULT_SUBMITTED_ATStringTYPE_SUCCESS — ISO 8601 timestamp
RESULT_VERIFIED_NAMEStringTYPE_SUCCESS — full name from the identity provider, if available
RESULT_ID_TYPE_NAMEStringTYPE_SUCCESS — e.g. "National ID", "BVN"
RESULT_ERROR_MSGStringTYPE_FAILURE

Verification Flow

The SDK steps through these states automatically.
StepDescription
LoadingSession creation and brand config fetch
WelcomeBrand splash, country picker, and ID type selection
Camera PermissionRequests camera permission at runtime before any camera is opened
Document CaptureCamera view for the front (and back, if required) of the ID document
ID InputForm fields for data-mode verification (BVN, NIN, etc.)
LivenessLive camera challenge — blink, turn head
ProcessingUpload and backend verification in progress
SuccessVerification complete — shows a summary card, then calls back
FailureUnrecoverable error — shows the message and a retry button

SDK Configuration

data class SDKConfig(
    val apiKey:             String,
    val clientId:           String,
    val environment:        Environment = Environment.PRODUCTION,
    val requestTimeoutMs:   Long        = 30_000L,
    val uploadTimeoutMs:    Long        = 120_000L,
    val maxUploadRetries:   Int         = 3,
    val debug:              Boolean     = false
)
ParameterDefaultDescription
apiKeyYour SmartComply API key (required)
clientIdUnique identifier per verification attempt (required)
environmentPRODUCTIONSANDBOX for testing, PRODUCTION for live verification
requestTimeoutMs30000Timeout in milliseconds for standard API calls
uploadTimeoutMs120000Timeout in milliseconds for video upload
maxUploadRetries3Automatic retry attempts on upload failure
debugfalsePrints verbose network logs to Logcat when true

Error Handling

SmartComplyActivity handles and displays all error states automatically. Common scenarios:
ScenarioCauseResolution
TYPE_FAILURE with "401"Invalid or missing API keyCheck your key in the SmartComply Dashboard
TYPE_FAILURE — session expiredSession tokens have a 30-minute TTLGenerate a new clientId on the next launch
TYPE_CANCELLEDUser pressed backRe-launch when the user is ready to retry
Upload failedNetwork instabilityThe built-in failure screen offers a retry; if retries are exhausted TYPE_FAILURE is returned

Advanced: Custom Host Activity

If you need to embed the verification flow directly inside your own ComponentActivity instead of launching a separate screen, you can use SmartComplyFlowScreen as a Compose composable:
import com.smartcomply.sdk.SmartComply
import com.smartcomply.sdk.client.SDKConfig
import com.smartcomply.sdk.client.Environment
import com.smartcomply.sdk.ui.SmartComplyFlowScreen
import java.util.UUID

val sdk = SmartComply(
    SDKConfig(
        apiKey      = "pk_live_xxxxxxxxxxxx",
        clientId    = UUID.randomUUID().toString(),
        environment = Environment.PRODUCTION
    )
)

// In your composable:
SmartComplyFlowScreen(
    sdk        = sdk,
    darkTheme  = null,            // null = follow system setting
    onComplete = { result ->
        // result.entryId, result.status, result.verifiedName, etc.
    },
    onError = { message ->
        // unrecoverable error not handled by the built-in failure screen
    }
)
Your host Activity must be a ComponentActivity and must be in the foreground with an active window. Embedding SmartComplyFlowScreen inside a Dialog or bottom sheet will cause the camera to fail on some devices.

ProGuard / R8

The SDK ships with its own consumer ProGuard rules. If you see obfuscation-related issues, add to your proguard-rules.pro:
-keep class com.smartcomply.sdk.** { *; }
-keepattributes *Annotation*