face_liveness_verification
Production-focused Flutter package for face detection workflow integration, challenge-based face liveness checks, and FaceNet identity verification.
Best for onboarding, login protection, attendance, and KYC-like mobile verification flows.
Banner

Table of Contents
- Banner
- Features
- Use Cases
- Getting Started
- Architecture (Image + Diagram)
- How It Works
- Quick Start
- Complete Developer Example
- Enrollment and Verification Flows
- UI Integration
- Configuration Reference
- Result Model and Failure Reasons
- Performance and Tuning
- Security and Privacy
- API Map
- SEO and Discoverability
- Example App
- Validation
- License
Features
- End-to-end pipeline: liveness + embedding + matching.
- Action-based liveness flow: smile, blink, turn left/right, look up/down, neutral.
- Configurable thresholds, timeouts, retries, and action order randomization.
- FaceNet embedding extraction with TFLite.
- Template enrollment and verification orchestration.
- Template storage abstraction for custom secure persistence.
- Built-in default UI plus custom UI builder option.
- Unified result models with normalized failure reasons.
Use Cases
- User onboarding with selfie liveness and identity binding.
- Returning-user face verification for authentication.
- Attendance/check-in with replay-resistance via challenge flow.
- Step-up verification before sensitive actions.
Getting Started
1. Add dependency
dependencies:
face_liveness_verification: ^1.0.1
flutter pub get
2. Import package
import 'package:face_liveness_verification/face_liveness_verification.dart';
3. Add permissions
Android, android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
iOS, ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera is required for face liveness verification.</string>
4. SDK requirements
- Dart SDK: ^3.13.0
- Flutter: >=1.17.0
Platform Support
| Platform | Status |
|---|---|
| Android | Supported |
| iOS | Supported |
| Web | Not officially supported |
| macOS / Windows / Linux | Not officially supported |
Architecture (Image + Diagram)

Add your generated image to this path so it renders in GitHub and pub.flutter-io.cn:
- doc/mermaid-diagram.png
How It Works
- Your app sends per-frame faces, image size, and image bytes to the service.
- The package checks frame validity: single face, position, and face size range.
- Liveness state machine drives challenge actions until completion.
- After liveness passes, FaceNet creates an embedding from the best available face crop.
- Live embedding is compared with template embedding using selected metric.
- You receive one unified result object for UI updates and business decisions.
Quick Start
final service = FaceLivenessMatchService(
livenessConfig: const FaceLivenessConfig(),
matchingConfig: const FaceMatchingConfig(
metric: FaceSimilarityMetric.euclidean,
threshold: 1.0,
),
templateStore: InMemoryFaceTemplateStore(),
);
await service.warmUp();
Complete Developer Example
import 'dart:typed_data';
import 'dart:ui';
import 'package:face_liveness_verification/face_liveness_verification.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
class FaceVerificationEngine {
FaceVerificationEngine()
: _service = FaceLivenessMatchService(
livenessConfig: const FaceLivenessConfig(
actions: [
FaceLivenessAction.smile,
FaceLivenessAction.blink,
FaceLivenessAction.turnLeft,
FaceLivenessAction.turnRight,
],
challengeTimeout: Duration(seconds: 12),
totalSessionTimeout: Duration(seconds: 45),
randomizeActionOrder: true,
),
matchingConfig: const FaceMatchingConfig(
metric: FaceSimilarityMetric.euclidean,
threshold: 1.0,
),
templateStore: InMemoryFaceTemplateStore(),
);
final FaceLivenessMatchService _service;
Future<void> initialize() async {
await _service.warmUp();
}
Future<FaceLivenessMatchResult> enroll({
required String faceId,
required List<Face> faces,
required Size imageSize,
required Uint8List imageBytes,
}) {
return _service.enrollAndPersist(
faceId: faceId,
faces: faces,
imageSize: imageSize,
imageBytes: imageBytes,
requireLiveness: true,
);
}
Future<FaceLivenessMatchResult> verify({
required List<Face> faces,
required Size imageSize,
required Uint8List imageBytes,
}) {
return _service.verifyWithStoredTemplate(
faces: faces,
imageSize: imageSize,
imageBytes: imageBytes,
);
}
FaceLivenessUiState toUi(FaceLivenessMatchResult result) {
return FaceLivenessUiState.fromLivenessMatchResult(result);
}
void reset() {
_service.reset();
}
void dispose() {
_service.dispose();
}
}
Enrollment and Verification Flows
Enrollment
final enrollResult = await service.enrollAndPersist(
faceId: 'user_001',
faces: faces,
imageSize: imageSize,
imageBytes: imageBytes,
requireLiveness: true,
);
if (enrollResult.enrolledTemplate != null) {
// Enrollment successful
}
If you want to persist outside the service, call enrollFirstTime and save template in your own store.
Verification
final result = await service.verifyWithStoredTemplate(
faces: faces,
imageSize: imageSize,
imageBytes: imageBytes,
);
final uiState = FaceLivenessUiState.fromLivenessMatchResult(result);
You can also verify against a specific template with verifyWithTemplate.
UI Integration
Default UI:
FaceLivenessUi(
preview: cameraPreviewWidget,
state: uiState,
)
Custom UI:
FaceLivenessUi(
preview: cameraPreviewWidget,
state: uiState,
builder: (context, state) {
return Stack(
children: [
Positioned.fill(child: cameraPreviewWidget),
Align(
alignment: Alignment.bottomCenter,
child: Text(state.message),
),
],
);
},
)
Configuration Reference
FaceLivenessConfig
| Parameter | Type | Default | Purpose |
|---|---|---|---|
| smileThreshold | double | 0.6 | Smile confidence threshold |
| eyeOpenThreshold | double | 0.6 | Blink open/close threshold |
| headEulerXThreshold | double | 10 | Pitch threshold |
| headEulerYThreshold | double | 10 | Yaw threshold |
| headEulerZThreshold | double | 10 | Roll threshold |
| minimumFaceSize | double | 0.18 | Lower face-area ratio bound |
| maximumFaceSize | double | 0.75 | Upper face-area ratio bound |
| challengeTimeout | Duration | 12s | Timeout per challenge |
| totalSessionTimeout | Duration | 45s | Total session timeout |
| frameProcessingInterval | Duration | 180ms | Recommended processing cadence |
| actions | List | smile, blink | Challenge sequence |
| maxFailedAttempts | int | 4 | Allowed challenge timeouts |
| randomizeActionOrder | bool | true | Shuffle action order on reset |
FaceMatchingConfig
| Parameter | Type | Default | Purpose |
|---|---|---|---|
| metric | FaceSimilarityMetric | euclidean | Similarity metric |
| threshold | double | 1.0 | Match threshold |
Result Model and Failure Reasons
Key fields from FaceLivenessMatchResult:
- isValidFace
- isLivenessComplete
- isMatchComplete
- isMatch
- nextAction
- message
- distance
- threshold
- similarityMetric
- similarityScore
- failureReason
Failure reasons to map in UX:
- noFace
- multipleFaces
- invalidPosition
- invalidHeadPose
- challengeTimeout
- challengeFailed
- sessionTimeout
- faceTooSmall
- faceTooLarge
- embeddingFailed
- identityNotMatched
- processingError
Performance and Tuning
- Call warmUp once before first active session.
- Keep one service instance per liveness screen/session.
- Start with short challenge list for lower friction.
- Tune thresholds after testing across real devices and lighting conditions.
- Track failureReason counts to guide configuration improvements.
Security and Privacy
- Treat face embeddings as sensitive biometric data.
- Use encrypted storage for templates in production.
- Avoid logging raw embeddings or full face frame bytes.
- Define clear retention and deletion policies in your app.
- Show consent language where legal requirements apply.
API Map
- FaceLivenessMatchService: orchestration for liveness, enrollment, and verification.
- FaceLivenessChecker: translates face detections into liveness decisions.
- LivenessStateMachine: challenge progression, retries, and timeout logic.
- FaceEmbeddingExtractor: FaceNet embedding extraction through TFLite.
- FaceEnrollmentService: averaged template creation from multiple samples.
- FaceSimilarity: Euclidean distance and cosine similarity helpers.
- FaceTemplateStore: persistence contract for template storage.
- FaceLivenessUi and FaceLivenessUiState: default and custom UI integration.
SEO and Discoverability
This package targets the following search intent:
- Flutter face detection
- Flutter face liveness
- Flutter face verification
- Face recognition Flutter package
- Biometric authentication Flutter
Discoverability checklist:
- Keep README examples up to date with API changes.
- Add architecture image and demo screenshots in doc folder.
- Publish frequent stable updates with clear changelog notes.
- Keep package topics and description focused on core search terms.
Example App
Run the bundled demo:
cd example
flutter run
Validation
flutter analyze
flutter test
License
MIT License. See LICENSE.