Flutter Get Verified
A comprehensive Flutter package for identity verification and anti-scalping solutions. This package provides a complete verification flow including document scanning with OCR, face biometric matching, liveness detection, and user registration.
Overview
This package integrates two industry-leading SDKs to provide secure identity verification:
- Regula Document Reader SDK - For scanning and extracting data from identity documents (passports, driver's licenses, etc.)
- FaceTec/Face SDK - For face verification, liveness detection, and face matching
The package includes pre-built UI screens, extensive customization options, and a unified verification flow that can be easily integrated into any Flutter application.
Features
Document Scanning
- OCR data extraction from identity documents
- Support for various document types (passports, driver's licenses, ID cards)
- RFID/NFC reading for enhanced security and data verification
- Authenticity checks to detect forged documents
- Multi-page document support
- Customizable scanning interface with camera frame, toolbar, and status messages
Face Biometrics
- Face liveness detection to prevent spoofing attacks
- Face matching against document photos
- Customizable onboarding, camera, processing, success, and retry screens
- Color, font, and image customization for all face SDK screens
Complete Verification Flow
- OnboardingScreen - Intro and preparation screens with SDK initialization
- LoadingScreen - Configurable loading indicator during processing
- VerificationCompleteScreen - Display extracted data for user review
- RegisterScreen - User registration with customizable form fields
- EmailOTPScreen - Email verification support (placeholder for integration)
Customization
- Fluent API for configuring document reader and face SDK
- Color themes, fonts, and image assets customization
- Camera frame styling (border, corner radius, aspect ratio)
- Toolbar controls (torch, camera switch, close button)
- Progress indicators and loading states
- Form validation with regex support
Architecture
- Centralized configuration management via
SDKConfigManager - Clean separation between SDK initialization, steps, and customization
- Callback-based flow control with
GetVerifiedSolution - Reusable UI components (
AdaptiveImage,CircularIconProgress)
Getting Started
Prerequisites
- Flutter SDK >= 3.0.0
- Dart SDK >= 3.0.0
- Android: minSdkVersion 24+, targetSdkVersion 33+
- iOS: iOS 13.0+
Installation
Add this to your pubspec.yaml:
dependencies:
get_verified: ^0.0.3
Platform Configuration
Android
Add to android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 24
}
}
iOS
Add to ios/Podfile:
platform :ios, '13.0'
Quick Start
Basic Integration
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get_verified/get_verified.dart';
import 'package:get_verified/screen/onboarding/onboarding_screen.dart';
import 'package:get_verified/manager/sdk_config_manager.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize SDK configuration
SDKConfigManager.instance.initialize(
license: await rootBundle.load('assets/regula.license'),
faceApiUrl: 'https://your-face-api.com',
documentReaderUrl: 'https://your-doc-reader.com',
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Get Verified Demo',
theme: ThemeData(primarySwatch: Colors.red),
home: OnboardingScreen(onVerificationStart: () {}),
);
}
}
Core Components
GetVerifiedSolution
The main orchestrator class that manages the complete verification flow:
GetVerifiedSolution().startProcess(
faceApiUrl: 'https://your-face-api.com',
mode: 'match',
documentReaderConfig: documentReaderConfig,
faceSDKConfig: faceSDKConfig,
onDocumentFetched: (scanResult) {
// Document scanning completed
print('Name: ${scanResult.name}');
print('Passport: ${scanResult.passportNumber}');
},
onFaceMismatch: () {
// Face verification failed
},
onVerificationSuccess: (scanResult) {
// All verification steps passed
},
);
ScanResult
The result object containing extracted document data:
class ScanResult {
final String name;
final String passportNumber;
final String nationality;
final Uint8List imageBase64;
}
SDKConfigManager
Centralized configuration manager for all SDK settings:
SDKConfigManager.instance.initialize(
verifiedResultConfig: VerifiedResultScreenConfig(...),
loadingScreenConfig: LoadingScreenConfig(...),
onboardingConfig: OnboardingConfig(...),
faceSDKConfig: faceSDKConfig,
documentReaderConfig: documentReaderConfig,
license: license,
faceApiUrl: faceApiUrl,
documentReaderUrl: documentReaderUrl,
);
Document Reader SDK
Initialization
final initializer = DocReaderSdkInitializer();
// Initialize with license and backend URL
final success = await initializer.initialize(
license: license,
webServiceUrl: 'https://your-doc-reader.com',
);
// Or prepare database and initialize (for first run)
final success = await initializer.prepareDatabaseAndInitialize(
license: license,
webServiceUrl: 'https://your-doc-reader.com',
);
Scanning
final steps = DocReaderSdkSteps();
steps.scan(
faceApiUrl: 'https://your-face-api.com',
mode: 'match',
handleCompletion: (action, result, error) {
if (action == DocReaderAction.COMPLETE && result != null) {
// Handle successful scan
}
},
);
Customization
Use the fluent API to configure the document reader:
final config = DocumentReaderConfig()
.withColorTheme(
ColorThemeConfig(
primaryColor: '#4CAF50',
onPrimaryColor: '#FFFFFF',
backgroundColor: '#000000',
reticleSuccessColor: '#4CAF50',
reticleErrorColor: '#F44336',
),
)
.withCameraFrame(
CameraFrameConfig(
show: true,
lineWidth: 3,
borderColor: Colors.red,
cornerRadius: 10.0,
aspectRatio: 1.5,
),
)
.withToolbar(
ToolbarConfig(
showCloseButton: true,
showTorchButton: true,
showCameraSwitchButton: true,
),
)
.withMessages(
MessagesConfig(
showStatus: true,
showResultStatus: true,
hintMessages: {
'moveCloser': 'Move closer to document',
'holdSteady': 'Hold device steady',
},
),
)
.withFunctionality(
FunctionalityConfig(
cameraMode: CameraMode.AUTO,
zoomEnabled: true,
isVibration: true,
),
)
.withProcessParams(
ProcessParamsConfig(
scenario: 'FullAuth',
returnCroppedImage: true,
imageQuality: ImageQualityConfig(
dpiThreshold: 150,
focusCheck: true,
glaresCheck: true,
),
),
);
await config.apply();
Configuration Classes
| Class | Description |
|---|---|
ColorThemeConfig |
Primary, background, text, and UI element colors |
CameraFrameConfig |
Camera frame styling (border, corner radius, aspect ratio) |
ToolbarConfig |
Toolbar buttons visibility and styling |
MessagesConfig |
Status messages, hints, and fonts |
FunctionalityConfig |
Camera mode, zoom, capture mode, exposure |
ProcessParamsConfig |
Scanning scenario, image quality, date format |
LivenessCustomConfig |
Liveness check motion control and capture button |
RFIDConfig |
RFID reading UI and timeout configuration |
MultipageConfig |
Multi-page document scanning settings |
IndicatorsConfig |
Activity indicator positioning |
InstructionsConfig |
Help animation settings |
BackgroundConfig |
Background mask and border styling |
Face SDK
Initialization
final success = await FaceSdkInitializer.initialize(
webServiceUrl: 'https://your-face-api.com',
);
Face Verification Steps
final steps = FaceSdkSteps();
// Start liveness check
final liveFaceImage = await steps.startLiveness();
// Match faces (document photo vs live photo)
final isMatched = await steps.matchFaces(
documentFaceImage,
liveFaceImage,
);
Customization
final faceConfig = FaceSDKConfig()
.withColors(
FaceColorsConfig(
onboardingScreenBackground: Colors.black,
onboardingScreenTitleLabelText: Colors.white,
cameraScreenStrokeActive: Colors.green,
cameraScreenStrokeNormal: Colors.white,
processingScreenBackground: Colors.black,
successScreenBackground: Colors.green,
retryScreenBackground: Colors.red,
),
)
.withFonts(
FaceFontsConfig(
fontFamily: 'Roboto',
onboardingScreenTitleLabelSize: 24,
onboardingScreenSubtitleLabelSize: 16,
cameraScreenHintLabelSize: 14,
),
)
.withImages(
FaceImagesConfig(
successScreenImage: successImageByteData,
retryScreenHintSubject: hintSubjectByteData,
),
);
await faceConfig.apply();
Configuration Classes
| Class | Description |
|---|---|
FaceColorsConfig |
Colors for all face SDK screens |
FaceFontsConfig |
Font family and sizes for all screens |
FaceImagesConfig |
Custom images for success and retry screens |
Pre-built Screens
OnboardingScreen
The entry point for the verification flow with SDK initialization:
OnboardingScreen(
config: OnboardingConfig(
buttonColor: Colors.red,
buttonTextColor: Colors.white,
imageWidth: 500,
imageHeight: 500,
),
introContent: const OnboardingContent(
title: 'Welcome',
subtitle: 'Get started with identity verification',
imagePath: 'https://example.com/intro.png',
),
preparationContent: const OnboardingContent(
title: 'Prepare Documents',
subtitle: 'Have your ID ready for scanning',
imagePath: 'https://example.com/prep.png',
),
onVerificationStart: () {
// Called when user clicks Continue
},
)
LoadingScreen
A configurable loading screen for processing states:
LoadingScreen(
config: LoadingScreenConfig(
backgroundColor: Colors.white,
progressColor: Colors.red,
textColor: Colors.black,
loadingText: 'Processing...',
logoSize: 40,
logoWidget: Icon(Icons.security, size: 40),
),
)
VerificationCompleteScreen
Displays extracted document data for user review:
VerificationCompleteScreen(
scanResult: scanResult,
uiConfigOverride: VerifiedResultScreenConfig(
primaryColor: Colors.red,
buttonColor: Colors.red,
),
onContinue: () {
// Navigate to registration
},
)
RegisterScreen
A customizable registration form with validation:
RegisterScreen(
config: RegisterScreenConfig(
formConfig: FormConfig(
title: 'Create Account',
subtitle: 'Join our community',
showTerms: true,
navigationType: NavigationType.otp,
fields: [
FieldConfig(key: 'email', label: 'Email', inputType: TextInputType.emailAddress),
FieldConfig(key: 'name', label: 'Full Name'),
FieldConfig(key: 'dob', label: 'Date of Birth', isDate: true),
FieldConfig(key: 'password', label: 'Password', inputType: TextInputType.visiblePassword),
],
),
uiConfig: UIConfig(
scaffoldBackgroundColor: Colors.white,
submitButtonStyle: ElevatedButton.styleFrom(backgroundColor: Colors.red),
),
),
onSubmit: (formData) {
// Handle form submission
print(formData);
},
)
Usage Example
See the example directory for a complete implementation:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get_verified/get_verified.dart';
import 'package:get_verified/screen/onboarding/onboarding_screen.dart';
import 'package:get_verified/manager/sdk_config_manager.dart';
import 'package:get_verified/config/loading_screen_config.dart';
import 'package:get_verified/config/onboarding_config.dart';
import 'package:get_verified/config/verified_result_config.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SDKConfigManager.instance.initialize(
verifiedResultConfig: VerifiedResultScreenConfig(
primaryColor: Colors.red,
buttonColor: Colors.red,
),
loadingScreenConfig: LoadingScreenConfig(
progressIndicatorSize: 100,
logoWidget: FlutterLogo(size: 30),
),
onboardingConfig: OnboardingConfig(
buttonColor: Colors.red,
buttonTextColor: Colors.white,
),
faceApiUrl: 'https://poc.ticketrecipe.com:41101',
documentReaderUrl: 'https://poc.ticketrecipe.com',
license: await rootBundle.load('assets/regula.license'),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Get Verified Demo',
theme: ThemeData(primarySwatch: Colors.red),
home: OnboardingScreen(onVerificationStart: () {}),
);
}
}
Sending Results to Backend
After verification, you can send the transaction ID to your backend:
// Static method to send transaction ID
final success = await GetVerifiedSolution.sendToCustomerBackend(
transactionId: 'transaction-id',
customerApiUrl: 'https://your-api.com/verify',
customHeaders: {'Authorization': 'Bearer token'},
);
// Or use the combined finalize and send method
await GetVerifiedSolution.finalizeAndSendToCustomer(
customerApiUrl: 'https://your-api.com/verify',
customHeaders: {'Authorization': 'Bearer token'},
);
UI Components
AdaptiveImage
A widget that automatically handles both local assets and network images:
AdaptiveImage(
imagePath: 'https://example.com/image.png', // or 'assets/images/logo.png'
width: 200,
height: 200,
fit: BoxFit.contain,
borderRadius: BorderRadius.circular(12),
)
CircularIconProgress
An animated circular progress indicator with a customizable icon:
CircularIconProgress(
icon: Icon(Icons.security, size: 40),
progressColor: Colors.red,
backgroundColor: Colors.white,
size: 100,
strokeWidth: 4,
duration: Duration(seconds: 2),
)
Testing
Run tests with:
flutter test
The package includes test coverage for:
- Registration screen validation logic
- Form field validation (regex, match keys)
Troubleshooting
Logs for Document Reader
# Get device ID
adb devices
# Pull logs
adb -s {device_id} pull -a storage/emulated/0/Android/data/com.ticketrecipe.example/files/Regula/ ~/regula/
Reprocessing Transactions
curl --request POST \
--url "https://poc.ticketrecipe.com/api/v2/transaction/bee28087-3574-44ed-8741-c65465732bf6/process" \
--header "Content-Type: application/json" \
--data '{ "processParam": { "scenario": "FullAuth" } }'
Common Issues
-
Database preparation takes too long: This is normal for first-time initialization. The SDK downloads document definition files.
-
Face matching fails: Ensure good lighting and that the document photo is clearly visible.
-
License not found: Make sure the license file is properly loaded in
rootBundle.load().
Additional Information
- Dart Packages
- Regula Document Reader Documentation
- Face Verification SDK Documentation
- TicketRecipe GitHub
License
MIT License - see LICENSE for details.
curl -X POST
"https://poc.ticketrecipe.com/api/v1/transactions/54cf7e22-1309-472a-b97f-f9934ff1ccd4/reprocess"
-H "Content-Type: application/json"
-d '{
"faceLivenessTransactionId": "d9f00532-4fea-47c2-81ef-6cfb8d940fd8"
}'
Libraries
- config/loading_screen_config
- config/onboarding_config
- config/verified_result_config
- core/error_codes
- core/exceptions
- core/get_verified
- core/get_verified_config
- core/result
- core/screens_config
- document/customization/background_config
- document/customization/camera_frame_config
- document/customization/color_theme_config
- document/customization/doc_reader_customization
- document/customization/functionality_config
- document/customization/image_quality_config
- document/customization/indicator_config
- document/customization/instructions_config
- document/customization/liveness_custom_config
- document/customization/message_config
- document/customization/multi_page_config
- document/customization/process_params_config
- document/customization/rfid_config
- document/customization/toolbar_config
- document/doc_reader_sdk_initializer
- document/doc_reader_sdk_steps
- document/model/scan_result
- face/customization/colors_config
- face/customization/face_sdk_customization
- face/customization/fonts_config
- face/customization/images_config
- face/face_sdk_initializer
- face/face_sdk_steps
- face/model/custom_image
- get_verified
- get_verified/get_verified_solution
- get_verified/get_verified_upload_solution
- manager/deep_link_manager
- manager/sdk_config_manager
- screen/email_otp_screen
- screen/get_verified/get_verified_upload_screen
- screen/loading_screen
- screen/onboarding/model/onboarding_model
- screen/onboarding/onboarding_screen
- screen/register/config/registration_defaults
- screen/register/model/registration_model
- screen/register/register_screen
- screen/register/widget/terms_section
- screen/register_screen_example
- screen/verified_result/models/verification_result_data
- screen/verified_result/utils/status_helper
- screen/verified_result/widgets/copyable_info_row
- screen/verified_result/widgets/error_page
- screen/verified_result/widgets/info_row
- screen/verified_result/widgets/success_page
- screen/verified_result/widgets/verification_status_section
- screen/verified_result_screen
- ui/components/adaptive_image
- ui/components/circular_icon_progress