didit_sdk 3.6.0
didit_sdk: ^3.6.0 copied to clipboard
Didit Identity Verification SDK for Flutter. Wraps native iOS and Android SDKs for document scanning, NFC passport reading, face verification, and liveness detection.
DiditSDK for Flutter #
A Flutter plugin for Didit Identity Verification. Wraps the native iOS and Android SDKs with a unified Dart API for document scanning, NFC passport reading, face verification, and liveness detection.
Requirements #
| Requirement | Minimum Version |
|---|---|
| Flutter | 3.3+ |
| Dart | 3.11+ |
| iOS | 13.0+ (NFC requires iOS 15.0+) |
| Android | API 23+ (6.0 Marshmallow) |
Installation #
Add the dependency to your pubspec.yaml:
dependencies:
didit_sdk: ^3.6.0
Then run:
flutter pub get
iOS Setup #
The Flutter plugin selects the native iOS SDK variant from DIDIT_SDK_IOS_NFC_ENABLED. Configure your ios/Podfile with the DiditSDK podspec URL (it's not on CocoaPods trunk):
didit_sdk_ios_nfc_enabled = ENV.fetch('DIDIT_SDK_IOS_NFC_ENABLED', 'true').downcase != 'false'
platform :ios, didit_sdk_ios_nfc_enabled ? '15.0' : '13.0'
didit_sdk_ios_pod = didit_sdk_ios_nfc_enabled ? 'DiditSDK' : 'DiditSDK/Core'
didit_sdk_ios_podspec = 'https://raw.githubusercontent.com/didit-protocol/sdk-ios/main/DiditSDK.podspec'
target 'Runner' do
use_frameworks!
pod didit_sdk_ios_pod, :podspec => didit_sdk_ios_podspec
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = didit_sdk_ios_nfc_enabled ? '15.0' : '13.0'
end
end
end
Set DIDIT_SDK_IOS_NFC_ENABLED=false before running pod install to switch the Flutter plugin dependency from DiditSDK to DiditSDK/Core, removing NFCPassportReader, CoreNFC-linked NFC reader code, and the OpenSSL framework used by the NFC reader. Leave the value unset, or set it to true, to keep the full NFC-enabled SDK. NFC-enabled iOS builds require a deployment target of iOS 15.0 or newer; core-only builds can target iOS 13.0.
Use the default full SDK with NFC:
cd ios
pod install
Use the core SDK without NFC:
cd ios
DIDIT_SDK_IOS_NFC_ENABLED=false pod install
When switching between NFC-enabled and no-NFC builds, clean CocoaPods first so the previous native SDK variant is not reused:
cd ios
rm -rf Pods Podfile.lock
# Full SDK with NFC
pod install
# Or core SDK without NFC
DIDIT_SDK_IOS_NFC_ENABLED=false pod install
Android Setup #
By default, the Flutter plugin depends on the full Android SDK, including NFC passport reading. To build an Android app without NFC dependencies, add this to android/gradle.properties:
diditSdkAndroidNfcEnabled=false
This switches the Android dependency from me.didit:didit-sdk to me.didit:didit-sdk-core, removing the NFC reader module and its JMRTD/SCUBA/BouncyCastle dependencies. Leave the property unset, or set it to true, to keep the full NFC-enabled SDK.
If NFC is enabled, add the following packaging rule to your android/app/build.gradle.kts inside the android block:
android {
packaging {
resources {
pickFirsts += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
}
}
}
This resolves a duplicate metadata file shipped by the SDK's cryptography dependencies (BouncyCastle). Without it the build will fail with a mergeDebugJavaResource error. This rule is not needed when diditSdkAndroidNfcEnabled=false.
Permissions #
iOS #
Add the following keys to your app's Info.plist:
| Permission | Info.plist Key | Description | Required |
|---|---|---|---|
| Camera | NSCameraUsageDescription |
Document scanning and face verification | Yes |
| Microphone | NSMicrophoneUsageDescription |
Video recording for liveness checks | Yes |
| Photo Library | NSPhotoLibraryUsageDescription |
Upload documents from device gallery | Yes |
| NFC | NFCReaderUsageDescription |
Read NFC chips in passports/ID cards | If using NFC |
| Location | NSLocationWhenInUseUsageDescription |
Geolocation for fraud prevention | Optional |
<key>NSCameraUsageDescription</key>
<string>Camera access is required for identity verification.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required for liveness verification.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access is required to upload documents.</string>
<key>NFCReaderUsageDescription</key>
<string>NFC is used to read passport chip data for identity verification.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location access is used to detect your country for identity verification.</string>
If any required iOS privacy key is missing, iOS terminates the app as soon as the SDK tries to access that protected resource. For example, missing NSCameraUsageDescription causes a crash when the user taps the document camera's take photo button.
NFC Configuration (for passport/ID chip reading)
-
Add NFC Capability in Xcode:
- Select your target > Signing & Capabilities > + Capability > Near Field Communication Tag Reading
-
Add ISO7816 Identifiers to
Info.plist:<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key> <array> <string>D23300000045737445494420763335</string> <string>A0000002471001</string> <string>A0000002472001</string> <string>00000000000000</string> </array> -
Add an entitlements file with NFC tag reading enabled:
<key>com.apple.developer.nfc.readersession.formats</key> <array> <string>TAG</string> </array>
Make sure the app's provisioning profile includes the NFC Tag Reading capability. If the bundle ID is not configured for NFC in your Apple Developer account, Xcode will fail signing with a missing com.apple.developer.nfc.readersession.formats entitlement.
This NFC configuration is not needed when DIDIT_SDK_IOS_NFC_ENABLED=false.
Android #
The following permissions are declared in the native SDK's AndroidManifest.xml and merged automatically:
| Permission | Description | Required |
|---|---|---|
INTERNET |
Network access for API communication | Yes |
ACCESS_NETWORK_STATE |
Detect network availability | Yes |
CAMERA |
Document scanning and face verification | Yes |
NFC |
Read NFC chips in passports/ID cards | If using NFC |
Camera and NFC hardware features are declared as optional (android:required="false"), so your app can be installed on devices without these features. When diditSdkAndroidNfcEnabled=false, the Android NFC permission and feature are not added by the SDK.
Runtime Permissions
The SDK handles Android runtime permission requests automatically. When the user reaches a step that requires camera access:
- The SDK prompts for camera permission if not already granted
- If the user denies the permission, an error message is displayed with a "Try Again" button
- If the user grants the permission, the verification flow continues
You do not need to request camera permission in your app code before calling startVerification() — the SDK manages this internally.
Quick Start #
import 'package:didit_sdk/sdk_flutter.dart';
final result = await DiditSdk.startVerification('your-session-token');
switch (result) {
case VerificationCompleted(:final session):
print('Status: ${session.status}');
print('Session ID: ${session.sessionId}');
case VerificationCancelled():
print('User cancelled');
case VerificationFailed(:final error):
print('Error: ${error.type} - ${error.message}');
}
Integration Methods #
The SDK supports two integration methods:
Method 1: API Integration (Recommended for Production) #
Your backend creates a session via the Didit API and returns the session token. This gives you full control over session creation, user tracking, and security.
Read more about how the create session API works here: https://docs.didit.me/reference/create-session-verification-sessions
// Your backend creates a session and returns the token
final sessionToken = await yourBackend.createVerificationSession(userId);
// Pass the token to the SDK
final result = await DiditSdk.startVerification(sessionToken);
This approach gives you full control over:
- Associating sessions with your users (
vendor_data) - Setting contact details, expected details, and metadata
- Configuring callbacks per session
Method 2: Unilink Integration (Simpler) #
For simpler integrations, the SDK can create sessions directly using your workflow ID — no backend needed:
final result = await DiditSdk.startVerificationWithWorkflow(
'your-workflow-id',
vendorData: 'user-123',
config: DiditConfig(loggingEnabled: true),
);
Note: Advanced session parameters (
contact_details,expected_details,metadata) are only available through the API Integration method, where your backend calls the Create Session API directly.
Configuration #
Customize the SDK behavior by passing a DiditConfig object:
final result = await DiditSdk.startVerification(
'your-session-token',
config: DiditConfig(
languageCode: 'es', // Force Spanish language
fontFamily: 'Avenir', // Custom font
loggingEnabled: true, // Debug logging
),
);
Configuration Options #
| Option | Type | Default | Description |
|---|---|---|---|
languageCode |
String? |
Device locale | ISO 639-1 language code (e.g. "en", "fr", "ar") |
fontFamily |
String? |
System font | Custom font family name |
loggingEnabled |
bool |
false |
Enable SDK debug logging |
All fields are optional. If no config is provided, the SDK uses sensible defaults.
languageCode #
Sets the language for the entire verification UI. Pass an ISO 639-1 code (e.g. "en", "fr", "es", "ar"). If not set, the SDK automatically detects the device locale and falls back to English.
// Force French
await DiditSdk.startVerification(token, config: DiditConfig(languageCode: 'fr'));
// Use device locale (default)
await DiditSdk.startVerification(token);
fontFamily #
Overrides the font used throughout the SDK UI. The font must be registered in your app's native configuration:
- iOS: Add the font file to your Xcode project and list it in
Info.plistunderUIAppFonts. - Android: Place the font file in
android/app/src/main/res/font/.
await DiditSdk.startVerification(token, config: DiditConfig(fontFamily: 'Avenir'));
loggingEnabled #
Enables verbose debug logging from the native SDK. Useful during development to inspect the SDK's internal state, API calls, and error details. Should be disabled in production.
await DiditSdk.startVerification(token, config: DiditConfig(loggingEnabled: true));
Language Support #
The SDK supports 53 languages. If no language is specified, the SDK uses the device locale with English as fallback.
Supported Languages
| Language | Code | Language | Code |
|---|---|---|---|
| Albanian | sq |
Kazakh | kk |
| Arabic | ar |
Korean | ko |
| Armenian | hy |
Kyrgyz | ky |
| Bengali | bn |
Latvian | lv |
| Bosnian | bs |
Lithuanian | lt |
| Bulgarian | bg |
Macedonian | mk |
| Catalan | ca |
Malay | ms |
| Chinese | zh |
Montenegrin | cnr |
| Chinese (Simplified) | zh-CN |
Norwegian | no |
| Chinese (Traditional) | zh-TW |
Persian | fa |
| Croatian | hr |
Polish | pl |
| Czech | cs |
Portuguese | pt |
| Danish | da |
Portuguese (Brazil) | pt-BR |
| Dutch | nl |
Romanian | ro |
| English | en |
Russian | ru |
| Estonian | et |
Serbian | sr |
| Finnish | fi |
Slovak | sk |
| French | fr |
Slovenian | sl |
| Georgian | ka |
Somali | so |
| German | de |
Spanish | es |
| Greek | el |
Swedish | sv |
| Hebrew | he |
Thai | th |
| Hindi | hi |
Turkish | tr |
| Hungarian | hu |
Ukrainian | uk |
| Indonesian | id |
Uzbek | uz |
| Italian | it |
Vietnamese | vi |
| Japanese | ja |
Advanced Session Parameters #
Parameters like contact_details, expected_details, and metadata are only supported through the API Integration method. Your backend creates the session with full parameter support, then passes the session_token to the SDK.
Read more about how the create session API works here: https://docs.didit.me/reference/create-session-verification-sessions
// Your backend handles the full session creation:
// POST /v3/session/ with contact_details, expected_details, metadata, etc.
final sessionToken = await yourBackend.createSession(userId);
// The SDK only needs the token
final result = await DiditSdk.startVerification(sessionToken);
Verification Results #
Both startVerification and startVerificationWithWorkflow return a Future<VerificationResult>. The result is a sealed class — use pattern matching to determine the outcome.
Result Types #
| Type | Description | Fields |
|---|---|---|
VerificationCompleted |
Verification flow completed | session (always present) |
VerificationCancelled |
User cancelled the flow | session (optional) |
VerificationFailed |
An error occurred | error (always present), session (optional) |
SessionData #
| Property | Type | Description |
|---|---|---|
sessionId |
String |
The unique session identifier |
status |
VerificationStatus |
approved, pending, or declined |
VerificationError #
| Property | Type | Description |
|---|---|---|
type |
VerificationErrorType |
Error category (see table below) |
message |
String |
Human-readable error description |
Error Types #
| Error Type | Description |
|---|---|
sessionExpired |
The session has expired |
networkError |
Network connectivity issue |
cameraAccessDenied |
Camera permission not granted |
notInitialized |
SDK not initialized (Android only) |
apiError |
API request failed |
unknown |
Other error with message |
Complete Result Handling Example #
import 'package:didit_sdk/sdk_flutter.dart';
Future<void> verify(String token) async {
final result = await DiditSdk.startVerification(token);
switch (result) {
case VerificationCompleted(:final session):
switch (session.status) {
case VerificationStatus.approved:
print('Approved! Session: ${session.sessionId}');
// User is verified — grant access
case VerificationStatus.pending:
print('Under review. Session: ${session.sessionId}');
// Show "verification in progress" UI
case VerificationStatus.declined:
print('Declined. Session: ${session.sessionId}');
// Handle declined verification
}
case VerificationCancelled(:final session):
print('User cancelled.');
if (session != null) {
print('Session: ${session.sessionId}');
}
// Maybe show retry option
case VerificationFailed(:final error):
print('Error [${error.type}]: ${error.message}');
// Handle error — show retry or contact support
}
}
API Reference #
DiditSdk.startVerification(token, {config}) #
Start verification with an existing session token.
| Parameter | Type | Required | Description |
|---|---|---|---|
token |
String |
Yes | Session token from the Didit API |
config |
DiditConfig? |
No | SDK configuration options |
Returns: Future<VerificationResult>
DiditSdk.startVerificationWithWorkflow(workflowId, {...}) #
Start verification by creating a new session with a workflow ID (Unilink Integration).
| Parameter | Type | Required | Description |
|---|---|---|---|
workflowId |
String |
Yes | Workflow ID that defines verification steps |
vendorData |
String? |
No | Your user identifier or reference |
config |
DiditConfig? |
No | SDK configuration options |
Returns: Future<VerificationResult>
Running the Example App #
The repository includes a fully functional example app.
iOS #
cd example
flutter pub get
cd ios && pod install && cd ..
flutter run
To run on a real device, open example/ios/Runner.xcworkspace in Xcode, configure your signing team, and select your device.
Android #
cd example
flutter pub get
flutter run
License #
Copyright (c) 2026 Didit. All rights reserved.