First, add face_camera as a dependency in your pubspec.yaml file.
face_camera: ^<latest-version>
- Minimum iOS Deployment Target: 15.5.0
- Follow this link and setup
ML Kitthis is required forface_camerato function properly oniOS
Add two rows to the ios/Runner/Info.plist:
- one with the key
Privacy - Camera Usage Descriptionand a usage description. - and one with the key
Privacy - Microphone Usage Descriptionand a usage description.
If editing Info.plist as text, add:
<key>NSCameraUsageDescription</key>
<string>your usage description here</string>
<key>NSMicrophoneUsageDescription</key>
<string>your usage description here</string>
- Change the minimum Android sdk version to 21 (or higher) in your
android/app/build.gradlefile.
minSdkVersion 21
- The first step is to initialize
face_camerainmain.dart
void main() async{ WidgetsFlutterBinding.ensureInitialized(); //Add this await FaceCamera.initialize(); //Add this runApp(const MyApp()); }
- Create a new
FaceCameraControllercontroller, setting the onCapture callback.
late FaceCameraController controller; @override void initState() { controller = FaceCameraController( autoCapture: true, defaultCameraLens: CameraLens.front, onCapture: (File? image) { }, ); super.initState(); }
- Then render the component in your application using the required options.
@override Widget build(BuildContext context) { return Scaffold( body: SmartFaceCamera( controller: controller, message: 'Center your face in the square', ) ); }
Here is a list of properties available to customize your widget:
| Name | Type | Description |
|---|---|---|
| controller | FaceCameraController | The controller for the [SmartFaceCamera] widget |
| showControls | bool | set false to hide all controls |
| showCaptureControl | bool | set false to hide capture control icon |
| showFlashControl | bool | set false to hide flash control control icon |
| showCameraLensControl | bool | set false to hide camera lens control icon |
| message | String | use this pass a message above the camera |
| messageStyle | TextStyle | style applied to the message widget |
| lensControlIcon | Widget | use this to render a custom widget for camera lens control |
| flashControlBuilder | FlashControlBuilder | use this to build custom widgets for flash control based on camera flash mode |
| messageBuilder | MessageBuilder | use this to build custom messages based on face position |
| indicatorShape | IndicatorShape | use this to change the shape of the face indicator (defaultShape, square, circle, triangle, triangleInverted, image, fixedFrame, none) |
| indicatorAssetImage | String | use this to pass an asset image when IndicatorShape is set to image |
| indicatorBuilder | IndicatorBuilder | use this to build custom widgets for the face indicator |
| captureControlBuilder | CaptureControlBuilder | use this to build custom widgets for capture control |
| autoDisableCaptureControl | bool | set true to disable capture control widget when no face is detected |
The IndicatorShape.fixedFrame option displays a centered, fixed-size frame (70% of screen) instead of following the detected face. This provides a better user experience for face capture with real-time positioning guidance:
Frame Colors:
- White/Gray Frame: No face detected
- Red Frame: Face detected but requirements not met
- Green Frame: Face properly positioned, countdown starts
Detection Constraints:
For the frame to turn green and trigger auto-capture, the following conditions must ALL be met:
-
Face Distance
- Eye distance must be between 0.14 - 0.28 (normalized Euclidean distance)
- Too close (> 0.28) β "Move back"
- Too far (< 0.14) β "Move closer"
-
Landmark Positioning
- All 6 facial landmarks (both eyes, nose, 3 mouth points) must be inside the frame bounds (15% - 85% of screen)
- Provides guidance: "Move left", "Move right", "Move up", "Move down"
-
Face Centering
- Nose must be near the center of the frame (40% - 60% range)
- Ensures face is not just inside, but properly centered
-
Head Orientation
- Head rotation Y (left/right): β€ 12 degrees
- Head rotation Z (tilt): β€ 12 degrees
- User must face forward with head straight
Basic Usage:
FaceCameraController( autoCapture: true, captureDelay: 3, defaultCameraLens: CameraLens.front, showDebugLandmarks: false, onCapture: (File? image) { // Handle captured image }, ) SmartFaceCamera( controller: controller, indicatorShape: IndicatorShape.fixedFrame, messageBuilder: (context, face) { if (controller.value.countdown != null) { return _buildMessage('Hold still...'); } final guidance = controller.getFacePositionGuidance(); return _buildMessage(guidance ?? 'Ready'); }, ) Widget _buildMessage(String message) => Padding( padding: EdgeInsets.symmetric(horizontal: 55, vertical: 15), child: Text( message, textAlign: TextAlign.center, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400), ), );
Customizing Guidance Messages:
You can fully customize the positioning guidance messages:
messageBuilder: (context, face) { // Show countdown message if (controller.value.countdown != null) { return _buildMessage('Hold still... ${controller.value.countdown}'); } // Get default guidance final guidance = controller.getFacePositionGuidance(); // Customize messages String message; switch (guidance) { case 'Move closer': message = 'Come closer to the camera'; break; case 'Move back': message = 'Move away from the camera'; break; case 'Move left': message = 'Move to your left'; break; case 'Move right': message = 'Move to your right'; break; case 'Move up': message = 'Lift your phone higher'; break; case 'Move down': message = 'Lower your phone'; break; case 'Center your face': message = 'Almost there, center your face'; break; case 'Place your face in the frame': message = 'Position your face in the frame'; break; default: message = 'Perfect! Capturing...'; } return _buildMessage(message); }
Multi-language Support:
messageBuilder: (context, face) { if (controller.value.countdown != null) { return _buildMessage(AppLocalizations.of(context).holdStill); } final guidance = controller.getFacePositionGuidance(); final translations = { 'Move closer': AppLocalizations.of(context).moveCloser, 'Move back': AppLocalizations.of(context).moveBack, 'Move left': AppLocalizations.of(context).moveLeft, 'Move right': AppLocalizations.of(context).moveRight, // ... more translations }; return _buildMessage( translations[guidance] ?? AppLocalizations.of(context).ready ); }
Debug Mode:
Enable showDebugLandmarks: true in the controller to visualize facial landmarks with colored markers:
- Blue: Eyes
- Green: Nose
- Red: Mouth
- Yellow: Cheeks
- Purple: Ears
- Cyan: Face bounding box
This mode is ideal for KYC, document verification, and any application requiring consistent, high-quality face capture.
When autoCapture is enabled, you can add a countdown delay before the photo is taken. This gives users time to prepare and ensures they're ready:
FaceCameraController( autoCapture: true, captureDelay: 3, // 3-second countdown (default) onCapture: (File? image) { // Handle captured image }, )
The countdown is displayed as a large centered number (3, 2, 1) and only starts when the face is properly positioned. If the face moves out of position during countdown, the timer resets. Set captureDelay: 0 for immediate capture without countdown.
Here is a list of properties available to customize your widget from the controller:
| Name | Type | Description |
|---|---|---|
| onCapture | Function(File?) | callback invoked when camera captures image |
| onFaceDetected | Function(DetectedFace?) | callback invoked when camera detects face |
| imageResolution | ImageResolution | use this to set image resolution |
| defaultCameraLens | CameraLens | use this to set initial camera lens direction |
| defaultFlashMode | CameraFlashMode | use this to set initial flash mode |
| enableAudio | bool | set false to disable capture sound |
| autoCapture | bool | set true to capture image on face detected |
| captureDelay | int | countdown delay in seconds before auto-capture (default: 3, set 0 for immediate) |
| showDebugLandmarks | bool | set true to show colored markers for facial landmarks (eyes, nose, mouth, etc.) |
| ignoreFacePositioning | bool | set true to trigger onCapture even when the face is not well positioned |
| orientation | CameraOrientation | use this to lock camera orientation |
| performanceMode | FaceDetectorMode | use this to set your preferred performance mode |
Contributions of any kind are more than welcome! Feel free to fork and improve face_camera in any way you want, make a pull request, or open an issue.
You can support the library by donating, liking it on Pub, starring it on GitHub, and reporting any bugs you encounter.