SurePass Video KYC Flutter SDK
Drop-in SurePass Video KYC verification for Flutter apps. One call pushes the whole flow — session setup, permissions, and the verification WebView — and returns a typed result.
Requirements
Flutter >=3.24.0 (Dart >=3.5.0) · Android API 28+ · iOS 15.0+
Installation
dependencies:
videokyc_flutter: ^1.5.1
Platform setup
The SDK requests permissions at runtime but cannot declare them for you. Skip this and the requests fail — and on iOS, a missing Info.plist key crashes the app.
Android
Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
Set minSdk = 28 in android/app/build.gradle.kts (or minSdkVersion 28 in android/app/build.gradle on older Groovy projects).
If your Android build fails on proguard-android.txt
flutter_inappwebview ^6.1.5 does not build under Android Gradle Plugin 9, the default in recent Flutter. Add this to your app's pubspec.yaml, then run flutter pub get:
dependency_overrides:
flutter_inappwebview: 6.2.0-beta.3
dependency_overrides only takes effect in the root app. Remove it once flutter_inappwebview 6.2.0 ships stable — this SDK's ^6.1.5 constraint picks it up automatically.
iOS
Add to ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is required for video KYC verification.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required for video KYC verification.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location access is required for video KYC verification.</string>
In ios/Podfile, set platform :ios, '15.0' and enable the permissions in your existing post_install block (merge these lines in — don't add a second block). permission_handler compiles its iOS permissions out by default, so without this the prompts never appear and the flow ends immediately with VideoKycStatus.error:
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['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
'PERMISSION_CAMERA=1',
'PERMISSION_MICROPHONE=1',
'PERMISSION_LOCATION=1',
]
end
end
end
Usage
import 'package:videokyc_flutter/videokyc_flutter.dart';
final result = await startSurepassVideoKyc(
context: context,
token: 'your_surepass_api_token',
env: Env.sandbox, // or Env.prod
workflowId: 'your_workflow_id',
email: 'user@example.com',
fullName: 'John Doe',
mobileNumber: '9876543210',
userImage: selfieBytes, // optional Uint8List from your own image picker
onInitialized: (VideoKycModel model) {
debugPrint('User: ${model.userId}, session: ${model.sessionId}');
},
);
switch (result?.status) {
case VideoKycStatus.success:
debugPrint('Completed — session ${result!.sessionId}');
case VideoKycStatus.cancelled:
debugPrint('Cancelled by the user');
case VideoKycStatus.error:
debugPrint('Error: ${result!.errorMessage}');
case VideoKycStatus.failed:
debugPrint('Verification failed: ${result!.errorMessage}');
case null: // dismissed before reaching a terminal status
break;
}
See example/ for a runnable app.
Appearance
The SDK's screens and dialogs take their colours and type from the host app's Theme, dark mode included, so the flow looks like the rest of your app. There is no separate palette to configure.
Parameters
| Parameter | Required | Description |
|---|---|---|
context |
✅ | BuildContext used to push the KYC flow. |
token |
✅ | Your SurePass API authentication token. |
env |
✅ | Env.sandbox or Env.prod. |
workflowId |
✅ | Your SurePass workflow id. |
email |
— | User's email address. |
fullName |
— | User's full name. |
mobileNumber |
— | 10-digit mobile number, no country-code prefix. |
userImage |
— | Raw image bytes (Uint8List) from your app's gallery or camera picker, base64-encoded and sent as advance_parameters.user_image. Omitted from the request entirely when not provided. |
onInitialized |
— | Callback receiving the VideoKycModel once the session initializes: userId, workflowId, sessionId, videoKycUrl, plus the optional workflowSessionId, eventType, and signature. |
The create-user API requires email, fullName, and mobileNumber, so omitting one — or passing an empty string — sends a placeholder in its place (vkyc.user@example.com, vkyc user, 1234567890). The flow runs normally, but the KYC record then carries placeholder identity data instead of the customer's own. Pass real values whenever you have them.
Result
startSurepassVideoKyc() returns a SurepassVideoKycResult?, or null if the flow is dismissed before reaching a terminal status.
| Field | Description |
|---|---|
status |
success, failed, cancelled, or error. success, failed and cancelled are the server's own verdict on the session; error covers everything that stopped the SDK from getting one — network errors, permission denials, API failures, and a verification the SDK could not follow to its end. |
sessionId |
The session id for tracking, when available. |
errorMessage |
For failed, the server's own reason (its error_safe_description and error_code) when it gave one. For error, the setup or API failure; may be null for in-flow WebView load errors. |
How the outcome is decided
Once the verification page is open, the SDK polls SurePass for the session's
current_status every 3 seconds and ends the flow when the server reports a
terminal one — COMPLETED, FAILED, or CANCELED. The server is the
authority: nothing in the page itself is trusted to report the outcome, so a
reload, a backgrounded app, or a network that blocks WebSockets cannot lose the
result. Polling pauses while your app is in the background and reads again the
moment it returns.
The verification page sits below a thin strip carrying a back arrow at its
leading edge. The user can leave the flow before it ends — with that arrow, or
the system back button on Android — which asks for confirmation first and then
returns VideoKycStatus.cancelled.
If the session has still not reached a terminal status after 20 minutes, or if
several consecutive reads fail, the flow ends with VideoKycStatus.error rather
than guessing at an outcome. The verification itself may well have succeeded —
treat that status as "ask the server", not as a failure.
Permissions
Camera (video capture), microphone (session audio), and location (location verification) are requested when the flow starts. The in-flow WebView re-requests them on demand if the verification page asks.
A denial does not end the flow outright — the SDK shows a dialog matched to what the user can still do:
- Denied — Try Again re-triggers the system prompt.
- Permanently denied, so the OS will not prompt again (Android: a second denial or "Don't ask again"; iOS: a single denial) — Open Settings opens the app's settings page and re-checks the permissions when the user returns. On Android, changing a permission there can restart the app process, in which case your app resumes at its own entry point.
- Restricted by device policy or parental controls — explained, with no action to offer.
Cancelling that dialog ends the flow with VideoKycStatus.error and an errorMessage naming the permissions that were not granted.
License
Released under the MIT License — see LICENSE for details.
Libraries
- core/config/app_config
- core/config/env
- core/errors/failures
- core/network/api_client
- core/permissions/permission_handler
- features/video_kyc/data/datasources/video_kyc_remote_datasource
- features/video_kyc/data/models/advance_parameters
- features/video_kyc/data/models/create_user_request
- features/video_kyc/data/models/initiate_video_kyc_request
- features/video_kyc/data/models/user_model
- features/video_kyc/data/models/video_kyc_model
- features/video_kyc/data/models/workflow_session_model
- features/video_kyc/data/repositories/video_kyc_repository_impl
- features/video_kyc/domain/entities/user_entity
- features/video_kyc/domain/entities/video_kyc_entity
- features/video_kyc/domain/entities/workflow_session_entity
- features/video_kyc/domain/repositories/video_kyc_repository
- features/video_kyc/domain/usecases/create_user_usecase
- features/video_kyc/domain/usecases/get_workflow_session_usecase
- features/video_kyc/domain/usecases/initiate_video_kyc_usecase
- features/video_kyc/presentation/pages/video_kyc_page
- features/video_kyc/presentation/pages/webview_page
- features/video_kyc/presentation/providers/video_kyc_provider
- features/video_kyc/presentation/services/workflow_session_poller
- features/video_kyc/presentation/widgets/cancel_dialog
- features/video_kyc/presentation/widgets/permission_dialog
- features/video_kyc/presentation/widgets/status_dialog
- videokyc_flutter