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
| Parameter | Default | Description |
|---|
from | — | The calling Context |
apiKey | — | Your SmartComply API key — find it in the Dashboard |
clientId | — | A unique ID per verification attempt — use UUID.randomUUID().toString() |
darkTheme | null | true forces dark mode, false forces light, null follows the device setting |
environment | PRODUCTION | PRODUCTION for live verification, SANDBOX for testing |
Read from the Intent returned to your activity result callback.
| Constant | Type | Present when |
|---|
RESULT_TYPE | String | Always — "success", "failure", or "cancelled" |
RESULT_ENTRY_ID | Int | TYPE_SUCCESS |
RESULT_STATUS | String | TYPE_SUCCESS — e.g. "submitted", "verified" |
RESULT_SUBMITTED_AT | String | TYPE_SUCCESS — ISO 8601 timestamp |
RESULT_VERIFIED_NAME | String | TYPE_SUCCESS — full name from the identity provider, if available |
RESULT_ID_TYPE_NAME | String | TYPE_SUCCESS — e.g. "National ID", "BVN" |
RESULT_ERROR_MSG | String | TYPE_FAILURE |
Verification Flow
The SDK steps through these states automatically.
| Step | Description |
|---|
| Loading | Session creation and brand config fetch |
| Welcome | Brand splash, country picker, and ID type selection |
| Camera Permission | Requests camera permission at runtime before any camera is opened |
| Document Capture | Camera view for the front (and back, if required) of the ID document |
| ID Input | Form fields for data-mode verification (BVN, NIN, etc.) |
| Liveness | Live camera challenge — blink, turn head |
| Processing | Upload and backend verification in progress |
| Success | Verification complete — shows a summary card, then calls back |
| Failure | Unrecoverable 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
)
| Parameter | Default | Description |
|---|
apiKey | — | Your SmartComply API key (required) |
clientId | — | Unique identifier per verification attempt (required) |
environment | PRODUCTION | SANDBOX for testing, PRODUCTION for live verification |
requestTimeoutMs | 30000 | Timeout in milliseconds for standard API calls |
uploadTimeoutMs | 120000 | Timeout in milliseconds for video upload |
maxUploadRetries | 3 | Automatic retry attempts on upload failure |
debug | false | Prints verbose network logs to Logcat when true |
Error Handling
SmartComplyActivity handles and displays all error states automatically. Common scenarios:
| Scenario | Cause | Resolution |
|---|
TYPE_FAILURE with "401" | Invalid or missing API key | Check your key in the SmartComply Dashboard |
TYPE_FAILURE — session expired | Session tokens have a 30-minute TTL | Generate a new clientId on the next launch |
TYPE_CANCELLED | User pressed back | Re-launch when the user is ready to retry |
| Upload failed | Network instability | The 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*