Skip to main content

liveness_flutter 0.5.0 copy "liveness_flutter: ^0.5.0" to clipboard
liveness_flutter: ^0.5.0 copied to clipboard

Beta: Plug-and-play liveness detection for Flutter. Configure action sequences like blink and smile, capture images or video, and send verification results to your backend.

๐Ÿ›ก๏ธ liveness_flutter #

Face liveness checks for Flutter โ€” free, on-device, and built for your backend.

pub package License: MIT Platform No ML models Status: beta

Blink. Smile. Turn left. Verified. โœ…


You give it a list of actions (blink, smile, turn leftโ€ฆ). It shows the camera, guides the user through each action, and checks a real live person performed them. When it's done you get one result object โ€” optionally with photos and/or video โ€” and you send it wherever you want.

Everything runs on the phone. No cloud service. No license fees. No model downloads. No account.

๐Ÿงช Status: beta #

liveness_flutter is in beta. It's tested on real Android and iOS devices, but it's still evolving and the API may change before 1.0. Until then, a minor release (0.5 โ†’ 0.6) can include breaking changes; each one is listed under Breaking in the CHANGELOG. Depend on ^0.5.0 and you'll only get compatible updates.

Anyone can open an issue โ€” bugs, a phone where detection misbehaves, confusing docs, or ideas. For detection problems, include your phone model, OS version, and what showDebugOverlay: true shows.

โœจ Why this package? #

๐ŸŽฏ 13 challenge actions blink, smile, fullTeethSmile, nod, look left/right/up/down, tilt left/right, eyes closed, open mouth, draw-a-circle-with-your-nose
๐ŸŽฒ Anti-replay random action order (and optionally a random pick of actions) per session, so a pre-recorded video can't follow the script
๐Ÿ•ต๏ธ Anti-spoof, zero ML static-feed guard (catches frozen or injected camera feeds), micro-motion analysis, frame-quality gates, opt-in color-flash challenge, plus hooks for server challenges, attestation and your own anti-spoof model
๐Ÿ“ธ Evidence capture a photo at the peak of each action, full video, or a works-everywhere frame sequence โ€” your server verifies, not just the phone
๐Ÿ”Œ Any backend onResult hands you everything; built-in multipart uploader with progress, errors and retries, or bring dio/S3/Firebase/anything
๐ŸŽจ Fully yours theme every color and string (localizable), or replace whole UI layers with your own widgets โ€” see the branded fintech example
๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ Assisted mode agent points the back camera at the customer โ€” torch lighting, auto-flipped left/right
๐Ÿชถ Featherlight pure Dart + Google ML Kit. No TensorFlow, no 20 MB downloads, minSdk 24

๐Ÿ—บ๏ธ Pick your path #

You want toโ€ฆ Go to
Add a working liveness check to your app Simple setup โ€” about 10 minutes
See every example, or run one Examples
Make it look like your app (colours, text, your own screens) Make it look like your app and the fintech example
Use it for KYC or anything with real consequences Bind sessions to your server
Have an agent verify someone else Assisted mode
Know the limits before shipping Honest notes

๐Ÿš€ Simple setup #

Four steps to a working check. Everything here uses defaults; the advanced sections cover the rest.

1. Install and set up the platforms #

dependencies:
  liveness_flutter: ^0.5.0

Needs Flutter 3.38+ (Dart 3.10+), the minimum for package:camera 0.12.

Android โ€” set minSdkVersion 24 in your app.

iOS โ€” add to ios/Runner/Info.plist (without it the app crashes on camera use):

<key>NSCameraUsageDescription</key>
<string>Camera is used for liveness verification.</string>

Also set platform :ios, '15.5' in ios/Podfile (the face detection library needs iOS 15.5+).

You don't need a permissions package: the camera plugin asks for access the first time. If the user says no, the session ends with failureReason == LivenessFailureReason.permissionDenied.

2. Show the liveness screen #

import 'package:liveness_flutter/liveness_flutter.dart';

class LivenessPage extends StatelessWidget {
  const LivenessPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: LivenessDetector(
        config: const LivenessConfig(
          actions: [
            LivenessAction.blink,
            LivenessAction.smile,
            LivenessAction.lookLeft,
          ],
          shuffleActions: true,          // a new order every time
          capture: {CaptureType.images}, // photos your server can check
        ),
        onResult: (result) {
          // If the user pressed back, this screen is gone or animating
          // out, and popping would close the *previous* screen. Check first.
          if (!context.mounted) return;
          if (ModalRoute.of(context)?.isCurrent ?? false) {
            Navigator.pop(context, result);
          }
        },
      ),
    );
  }
}

// Somewhere in your app:
final result = await Navigator.push<LivenessResult>(
  context,
  MaterialPageRoute(builder: (_) => const LivenessPage()),
);

โš ๏ธ onResult is called exactly once per session โ€” even if the screen is closed before the check finishes (system back, route popped). In that case the result is cancelled with metadata['cancelledBy'] == 'dispose' and arrives just after the screen is gone, which is why the guard above matters. cancelledBy is 'user' for the close button and 'lifecycle' when the app goes to the background.

๐Ÿ’ก Why shuffle? If actions always come in the same order, someone could record a video of a person doing that exact sequence and play it to the camera. Random order means yesterday's recording won't match today's.

๐Ÿ›ก๏ธ Include at least one motion action (blink, nod, openMouth, drawCircleWithNose). Pose-only actions (smile, tiltLeft/tiltRight, lookUp/lookDown) can be faked with a photo tilted or swapped at the right moment.

3. Read the result #

The essentials of LivenessResult:

  • success โ€” did the person complete all actions in time?
  • failureReason โ€” why not (took too long, face left the screen, more than one face, static/injected input suspected, camera access denied, user cancelledโ€ฆ)
  • confidenceScore โ€” 0 to 1. A clean run on a real camera scores 0.9+.
  • images โ€” the photos, each labelled with its action and kind (reference, or peak: the moment the action was clearest, e.g. eyes shut for a blink)
  • sessionId โ€” a unique audit ID (e.g. LV-018F3A2B9C4E-D7E31F08)

debugPrint(result.toString()) prints a readable summary, and result.toJson() gives a JSON-safe one (no image bytes). The full list of fields is further down.

4. Send it to your server #

try {
  await HttpLivenessUploader(
    endpoint: Uri.parse('https://api.example.com/liveness'),
    headers: {'Authorization': 'Bearer โ€ฆ'},
    onProgress: (sent, total) => progress.value = sent / total,
  ).upload(result);
} on LivenessUploadException catch (e) {
  // Your server answered with an error (e.statusCode, e.body).
}

It sends a metadata field with result.toJson() (session ID, confidence, actions, a SHA-256 of every photoโ€ฆ), one file per photo named like blink_peak_812ms.jpg, and an X-Liveness-Session header. Any transport works instead: LivenessUploader.custom((result) async { ... }) wraps dio, S3, Firebase or anything else.

โณ Show a progress bar. With photos an upload can be several MB. A common pattern: close the camera screen straight away and upload from the previous screen with a LinearProgressIndicator driven by onProgress.

That's it โ€” you have a working liveness check. The complete runnable version of these steps is example/lib/main.dart. Before using it for anything with real consequences, read Bind sessions to your server and the honest notes.


๐Ÿ“š Examples #

Each file in example/ runs on its own on a physical device (simulators have no usable front camera):

Example Shows Run from example/
Minimal The simple setup above, in ~90 lines flutter run
Branded fintech KYC flow A complete, fully custom-designed verification flow (more below) flutter run -t lib/recipes/fintech/main.dart
Custom UI Your own overlay and instructions, with detection following your window flutter run -t lib/recipes/custom_ui.dart
Controller Your own Cancel / Try again buttons and live state flutter run -t lib/recipes/controller.dart
Server-bound A challenge from your backend, then upload with error handling flutter run -t lib/recipes/server_bound.dart --dart-define=BACKEND_URL=https://โ€ฆ
Test bench Every option behind a settings screen, for trying the package on a device flutter run -t lib/test_bench/main.dart

Clone the repository to get the example with its Android and iOS folders ready: git clone https://github.com/maykhid/liveness_flutter && cd liveness_flutter/example. (The copy on pub.dev leaves the platform folders out; the example README explains how to generate them.)

๐Ÿฆ Example: a fully branded KYC flow #

example/lib/recipes/fintech/ shows how far customisation goes: a complete "upgrade your account" verification flow, the way a mobile bank or fintech app would ship it, built for a fictional brand ("AcmePay"). None of the package's default UI is visible โ€” only its detection.

  1. Account home โ€” balance card, current tier, "Upgrade to Tier 2".
  2. Intro โ€” where the user is in the upgrade (phone โœ“, BVN โœ“, face check), tips for passing first time, and what the photos are used for.
  3. Face check โ€” a light screen with a circular window, a progress ring split into one segment per action, and a card with an icon, the current step, a hint that turns red when something needs fixing, and a countdown. The circle is passed as targetRegion, so the face must be inside what's drawn. A branded page handles denied camera access.
  4. Verifying โ†’ success or failure โ€” success unlocks Tier 2; failure explains what went wrong for each LivenessFailureReason and offers Try again.

Run it:

cd example
flutter run -t lib/recipes/fintech/main.dart

Make it yours: everything brand-specific โ€” name, colours, wording, which actions it asks for โ€” is in brand.dart. Change primary to your colour and hot reload. The "Verifying" step simulates your backend's approval: replace _serverApproves in outcome_screens.dart with your upload and your server's decision.


๐Ÿงฐ Advanced #

Independent topics โ€” read the ones you need.

๐ŸŽจ Make it look like your app #

You need this if the default dark oval and white text don't match your design.

Theme and text (no custom widgets): LivenessTheme sets colours, borders, text styles, the target's size, position and shape (oval, circle or rounded rectangle โ€” this is also where the face must be), the close button, and every piece of text through LivenessStrings:

LivenessDetector(
  theme: LivenessTheme(
    ovalShape: TargetShape.circle,
    progressColor: Colors.teal,
    strings: LivenessStrings(
      actionInstructions: {LivenessAction.blink: 'Clignez des yeux'},
      stepCounter: (current, total) => 'ร‰tape $current sur $total',
    ),
  ),
  ...
)

Text maps (actionInstructions, guidanceMessages, failureMessages) are merged over the English defaults, so you can override just a few entries. Both LivenessTheme and LivenessStrings have copyWith. For layout: instructionAlignment, closeButtonBuilder, and theme fields like closeIconColor and resultHoldDuration.

Your own widgets: overlayBuilder replaces the dimmed overlay and instructionBuilder the instruction area. Both receive the live LivenessSessionState and rebuild on every change. Useful fields:

Field What it is
phase searching, centering, performing an action, completed, failedโ€ฆ
currentAction, actionPlan the action now, and every action in this session's order (known from the first frame)
actionProgress, overallProgress 0โ€“1 for the current action and for the whole session
remaining, actionTimeout, sessionRemaining countdowns
faceInPosition, guidance whether the face is in place, and what's wrong if not (tooFar, lowLightโ€ฆ)
failureReason why it failed

If you draw your own window, tell detection where it is with targetRegion (normalised to the widget, e.g. Rect.fromLTWH(0.15, 0.2, 0.7, 0.5)); otherwise the theme's oval still decides where the face must be. Working code: custom UI recipe and the fintech example.

DetectorTuning sets how strict each action is (how big a smile counts, how far to turn, how long to holdโ€ฆ). Tested defaults, all adjustable.

๐ŸŽฎ Control it from outside: LivenessController #

You need this if you hide the built-in close button, want a Try again without leaving the screen, or need the state outside the widget.

final controller = LivenessController(); // create in initState, dispose in dispose

LivenessDetector(
  controller: controller,
  showCloseButton: false,
  config: ...,
  onResult: ...,
);

controller.cancel();         // onResult gets a cancelled result (cancelledBy: 'user')
await controller.restart();  // fresh session: new sessionId, new shuffle
controller.state;            // live LivenessSessionState (it's a ChangeNotifier)
controller.actionPlan;       // the actions in the order this session runs them

Every session still gets exactly one onResult: restarting a session that's still running delivers it as cancelled with cancelledBy: 'restart'. See the controller recipe.

You need this if a passing result unlocks anything valuable. On its own, the phone's verdict is unsigned: your server can't tell which actions it expected or whether the result was edited. Three hooks fix that:

  • LivenessConfig.challenge: your server issues a LivenessChallenge (single-use nonce, the actions in its chosen order, an expiry). The session runs exactly that order and echoes the nonce in result.nonce. An expired challenge fails with challengeExpired.
  • Image hashes: result.toJson() (and so the uploader's metadata) lists the SHA-256 of every photo and frame, so the server can prove the files weren't swapped.
  • LivenessConfig.attestor: plug in Play Integrity or App Attest through the LivenessAttestor interface. It signs a hash of sessionId|nonce|success|actions|image hashes; the token lands in result.attestation. The package doesn't implement the platform APIs.

Without a server challenge, randomActionCount: 3 makes each session pick 3 actions at random from your list and shuffle them โ€” from all 13 actions that's 1,716 possible sequences instead of 6.

Server verification guide โ†’ covers what your backend should check, with a payload-rebuild snippet. Working client code: the server-bound recipe.

Bring your own anti-spoof model (optional). The package bundles no ML model, but LivenessConfig.frameAnalyzers lets you plug one in (a TFLite/ONNX presentation-attack detector, or a cloud call):

class MyPadModel extends LivenessFrameAnalyzer {
  @override
  String get id => 'pad-v2';

  @override
  Future<double?> analyze(LivenessFrame frame) async {
    // frame.jpeg: the upright full frame; frame.faceBox: the face (0..1).
    return myModel.spoofProbability(frame.jpeg, frame.faceBox); // 0โ€“1
  }
}

It runs on the reference frame and on each action's evidence frame. Scores land in metadata['analyzers']['pad-v2'] and lower confidenceScore by analyzerWeight (default 0.5) ร— the mean spoof probability.

Uploads, in more detail: a non-2xx answer throws LivenessUploadException(statusCode, body); each attempt is limited by timeout (default 60 s); set maxRetries to retry network errors, timeouts and 5xx with exponential backoff (4xx is never retried).

๐Ÿ“ธ Photos, video, and "frame sequence" โ€” which do I pick? #

You need this if you want more evidence than one photo per action.

Capturing nothing is the default. With an empty capture, result.images and result.frameSequence come back empty and videoPath is null. Nothing is encoded, kept in memory, or written to disk. You still get the verdict: success, completedActions, confidenceScore, sessionId, and metadata โ€” a few hundred bytes.

The trade-off: with no captured media, your server has nothing to independently verify โ€” you're fully trusting the on-device result. Fine for low-stakes flows (gating a selfie upload); for KYC or anything with real consequences, capture at least {CaptureType.images}.

You want Use Notes
A photo of each completed action CaptureType.images Smallest uploads. Works everywhere. Best default.
A real video file of the session CaptureType.video Great on iPhones. On many Android phones the camera can't record and detect at the same time โ€” see below.
Something video-like that works on every phone CaptureType.frameSequence Several photos per second for the whole session. A list of photos, not a video file โ€” but played back they look like one.
๐Ÿค– The Android video problem, in plain words (click to expand)

Detecting your face and recording a video both need the camera at the same time. iPhones handle that fine. Many Android phones can't โ€” and there's no official way to ask a phone in advance. So this package gives you three tools:

  1. LivenessCapabilities.supportsVideoCapture() โ€” call it once when your app starts (takes 2โ€“3 seconds, remembers the answer). It quietly tries recording and tells you true/false:

    final canRecord = await LivenessCapabilities.supportsVideoCapture();
    final capture = canRecord
        ? {CaptureType.images, CaptureType.video}
        : {CaptureType.images, CaptureType.frameSequence};
    
  2. If you skip that and video fails mid-session anyway, the check doesn't break โ€” it quietly continues without video and marks result.metadata['videoUnavailable'] = true so you know.

  3. Frame sequence as the works-everywhere alternative. If your server wants a real video file from those photos, one command turns them into an MP4:

    ffmpeg -framerate 8 -pattern_type glob -i 'frame_*.jpg' \
      -c:v libx264 -pix_fmt yuv420p session.mp4
    

Media size & cleanup:

  • Photo size: maxImageDimension (default 720 px longest side) and jpegQuality (default 85; lower = smaller files).
  • Video size: cameraResolution on the LivenessDetector widget.
  • Frame rate: frameSequenceFps (default 8, max 15) and frameSequenceMaxFrames (default 300) cap memory. Encoding runs in background isolates โ€” capture never stalls detection.
  • Cleanup: photos live only in memory โ€” gone when you're done with the result. The video is a real file and is not deleted automatically: upload or copy it in onResult, then delete it yourself or set autoDeleteVideo: true to remove it when the camera screen closes.

๐ŸŒˆ Stop video replays: the color-flash challenge #

You need this if you worry about someone playing a video of a real person to the camera โ€” the hardest cheap attack on any action-based check, because the actions in the video were real when recorded.

enableFlashChallenge: true adds a defense: right after the actions succeed, the screen flashes a short color sequence (red/green/blue, in a random order each session, ~2.5 seconds, "Hold stillโ€ฆ"). A real face is lit by the phone's screen, so the camera sees each color reflected on the skin. A replayed video was recorded before this session's random order existed โ€” its "face" doesn't reflect the right colors at the right times.

LivenessConfig(
  actions: [...],
  shuffleActions: true,
  enableFlashChallenge: true,
)

It's a soft signal, on purpose โ€” and lighting is why. The trick depends on the phone screen being a meaningful light source on the face:

Environment What to expect
๐ŸŒ™ Dim / evening indoor Strong signal โ€” reflections clearly measurable
๐Ÿ  Normal indoor lighting Good signal โ€” reliable for most users
๐Ÿข Bright office / large windows Weak โ€” real faces may score 'inconclusive' or 'failed'
โ˜€๏ธ Outdoors in daylight Little to no signal โ€” results not meaningful

How it decides. Only pixels inside the detected face are sampled (background doesn't reflect the screen), the first 150 ms of each colour is skipped while the display and camera catch up, and auto-exposure is locked for the duration where the device allows it. Each colour must raise its own channel clearly above the frame-to-frame noise measured before the flash, both against that baseline and against the other colours. By default all three colours must pass (flashAllowedMisses: 0). In simulation, pure camera noise passes 0 times in 5,000 runs, where the pre-0.5 rule passed about 1 in 20. White balance can't be locked through the camera plugin, so strongly tinted light can still skew it.

Other weakeners: phone held far from the face, very low screen brightness, strongly colored ambient light. To help, the package raises the screen to full brightness automatically during the session and restores it afterward (app window only; opt out with boostScreenBrightness: false).

A failed challenge lowers confidenceScore by 0.35 and sets metadata['flashChallenge'] = 'failed' โ€” it never rejects the user by itself. Treat a failure as "review this one", not "this is fraud." Log the metadata for a few weeks and learn your real users' pass rate before enforcing anything. Bonus: the flash moment is captured in your video and frame sequence โ€” a real face visibly changes color, which your server can check too.

๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ Assisted mode: verifying someone else #

You need this if a bank agent or field officer holds the phone and verifies another person โ€” common in branch onboarding and doorstep KYC:

LivenessConfig(
  actions: [...],
  cameraMode: LivenessCameraMode.assisted,
)

Understand what assisted mode means before using it:

  • The back camera is used, pointed at the subject. The operator watches the screen and must read each instruction out loud ("please blink", "turn your head left") โ€” the subject cannot see the screen.
  • "Left" and "right" always mean the subject's left/right; detection signs are flipped automatically for the unmirrored back camera.
  • The device torch turns on to light the subject's face (the screen, which normally does that job, faces the operator). Opt out with assistedTorchEnabled: false. Skipped on devices without a torch.
  • The color-flash challenge is automatically skipped (the screen's colors can't reach the subject's face): metadata['flashChallenge'] = 'skippedAssistedMode'. Static-feed guard, micro-motion, and quality gates still run.
  • metadata['cameraMode'] tells your backend which mode was used โ€” decide whether assisted sessions need extra review, since the operator (not the subject) controls the device.

๐Ÿ“ฆ Everything in the result #

LivenessResult, in full:

  • success, failureReason โ€” the verdict and why. Cancelled results say who in metadata['cancelledBy'].
  • confidenceScore โ€” 0 to 1. Duplicate frames, a frozen head, many bad-quality frames, a failed flash challenge or anti-spoof model scores pull it down. Raw counters are in metadata under confidence_* and identity_* keys.
  • sessionId โ€” unique audit ID.
  • nonce / attestation โ€” the server challenge's nonce and the attestor's token, when you use them.
  • completedActions โ€” which actions, in the order performed.
  • images โ€” the photos, each with action, kind, timestampMs and a sha256Hex.
  • frameSequence โ€” the steady-stream photos, each with a timestamp.
  • videoPath โ€” where the video file is, if you recorded one.
  • metadata โ€” extras like how long each action took.
  • toJson() / toString() โ€” a JSON-safe summary (no media bytes) and a readable log block.

๐Ÿ”ง Developer tools #

  • Debug overlay โ€” showDebugOverlay: true shows live head angles, eye/smile probabilities, brightness, and static-feed guard counters on screen, and draws a green box where the detector thinks your face is (if it doesn't sit on your face, please open an issue with your device). Perfect for tuning DetectorTuning thresholds on real devices.
  • Per-action callbacks โ€” onActionStarted / onActionCompleted (sync or async; never awaited, so detection never stalls on your code).
  • Feedback & accessibility โ€” onFeedback fires on action started, half-way, completed, and session passed/failed, for your own sounds, haptics or text-to-speech. hapticFeedback: true adds built-in haptics (handy for eyesClosed, which users can't see finish). Instructions are a screen-reader live region, so each new one is announced.
  • Permission handling in the screen โ€” permissionDeniedBuilder: (context, retry) => ... shows your own page when camera access is denied; calling retry starts a fresh session.
  • Test bench โ€” example/lib/test_bench/ puts every option behind a settings screen, logs every callback live, and runs the server-side checks on each result.

๐Ÿ“– Honest notes โ€” read before shipping #

Plain-language notes on the rough edges. Every one has a setting you can change; nothing requires forking the package.

This is not bank-grade security on its own. All checking happens on the phone, and a determined attacker controls their own phone. Treat a passing result as a good first gate, and have your server double-check the photos/video you upload (compare against an ID photo, look for signs of screens or prints). That's exactly why this package captures media during the actions. Server challenges, image hashes and attestation make tampering detectable, but the face itself still has to be judged server-side โ€” see the server verification guide.

Memory adds up if you turn everything up. Photos are kept in memory until the result is delivered. Defaults use roughly 15โ€“35 MB per session. Raising the frame rate and photo size together can OOM cheap Android phones. frameSequenceMaxFrames caps the total as a safety net.

Every face and phone is a little different. How confidently the phone detects a smile or head turn varies with the camera, lighting, glasses, and the person. If one action fails too often for your users, loosen its setting in DetectorTuning. Most sensitive: fullTeethSmile (depends on lip-contour quality) and eyesClosed (brief false "eye open" flickers are ignored; eyesOpenTolerance controls how brief).

drawCircleWithNose is a fun extra, not a workhorse. People must move their whole head in a circle, and small/slow circles don't count. Expect more retries. Test on your users' actual phones before making it mandatory.

Left and right, up and down. lookLeft means the user's left. Calibrated for Android and iPhone; if some device gets it backwards, mirrorYaw: false flips it. invertPitch: true does the same for lookUp, lookDown and nod (the up/down sign hasn't been confirmed on every iPhone yet; showDebugOverlay shows the live pitch).

Give people time โ€” but not forever. Each action has a 15-second limit (actionTimeout), users get 10 seconds to return to a neutral face between actions (neutralTimeout), and the whole session ends after 2 minutes (sessionTimeout, null to disable). For users who find the actions difficult, use fewer/easier actions (blink, smile), longer timeouts, and requireNeutralBetweenActions: false. A second face in the background is ignored if it's small, and only fails the session if it stays for more than half a second (multipleFacesGrace).

It needs light โ€” but it tells the user. Too-dark, overexposed, and blurry frames pause the session with a hint like "Find better lighting". The action's timer keeps running while paused, so a room that stays too dark ends in actionTimeout rather than hanging. Thresholds: brightnessMin, brightnessMax, sharpnessMin; disable with enableQualityChecks: false.

Same person throughout? With ML Kit tracking (on unless an action needs contours), a face ID that changes while a face stays in view lowers the confidence score and shows up in metadata['identity_*'], along with jumps in rough face geometry. Set failOnFaceChange: true to fail such sessions outright. It's off by default because a very fast head turn can make some devices re-assign the ID. This is no substitute for server-side face matching.

The anti-spoof checks are honest heuristics, not magic. The static-feed guard (called the replay guard before 0.5; the setting is still enableReplayGuard) catches input that can't come from a live camera: pixel-identical frames fail the session, and near-identical frames with a frozen face box (a re-encoded still injected as a camera) lower the confidence score. Micro-motion flags unnaturally still sessions the same way. None of it detects a photo, screen or video held up to a real camera: the real camera adds real noise and the hand adds real motion. That's what the actions, the colour flash, and server-side review of the captured media are for. If the guard ever misfires on a device (it shouldn't โ€” real sensors are noisy), enableReplayGuard: false turns it off.


Found a bug? Have an idea? Open an issue โ€” anyone can, and PRs are welcome too. ๐Ÿ™Œ

Made with โค๏ธ for developers who'd rather not pay per verification.

1
likes
160
points
759
downloads

Documentation

API reference

Publisher

verified publisherhenryifebunandu.dev

Weekly Downloads

Beta: Plug-and-play liveness detection for Flutter. Configure action sequences like blink and smile, capture images or video, and send verification results to your backend.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

camera, crypto, flutter, google_mlkit_face_detection, http, image, screen_brightness

More

Packages that depend on liveness_flutter