YouVerify Liveness SDK for Flutter

A Flutter plugin that integrates YouVerify's KYC Liveness Detection SDK into your Flutter applications. Perform real-time liveness verification on Android and iOS with support for multiple task types, full branding customization, and sandbox/production environment switching.


Table of Contents


Requirements

Flutter & Dart

Requirement Version
Dart SDK >=3.0.0 <4.0.0
Flutter >=3.10.0

Platform Minimum Versions

Platform Minimum Version
Android minSdk 24
iOS 13.0

Device Requirements

  • Physical device recommended: Liveness detection uses the camera and face detection. While the app may run on simulators/emulators, camera-based features require a physical device for full functionality.
  • Camera: Required for all liveness tasks.
  • Microphone: Optional; only needed if allowAudio is enabled for narrated instructions.

Project Overview

The YouVerify Liveness SDK plugin provides:

  • Real-time liveness detection — Verify that a live person is present (not a photo or video replay).
  • Multiple task types — Complete The Circle, Yes or No, Motions, Blink, and combinations.
  • Branding customization — Match the SDK UI to your app’s look and feel.
  • Sandbox & production — Test with sandbox credentials, then switch to live for production.

Installation

Add the plugin to your app's pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  youverify_liveness_sdk: ^0.0.1

If using a local path (e.g. for development):

dependencies:
  youverify_liveness_sdk:
    path: ../youverify_liveness_sdk

Then run:

flutter pub get

Platform Setup

Android

  1. NDK ABI filters — Add the following to your app module's android/app/build.gradle (or build.gradle.kts):
android {
    defaultConfig {
        ndk {
            abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86"))
        }
    }
}
  1. Permissions — Ensure your app requests camera (and optionally microphone) permissions. The plugin uses the camera for liveness detection. If your AndroidManifest.xml does not already include them, add:
<uses-permission android:name="android.permission.CAMERA" />
<!-- Optional: only if allowAudio is true -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />

iOS

  1. Camera & Microphone usage descriptions — Add the following keys to your ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>This app uses the camera for liveness detection to verify your identity.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app may use the microphone for audio instructions during liveness verification.</string>
  1. MediaPipe linker fix — The YouVerify Liveness SDK uses MediaPipe for face detection. CocoaPods can inject duplicate or conflicting MediaPipe framework flags (MediaPipeTasksCommon, MediaPipeTasksVision) into the build, which leads to linker errors or runtime issues such as the camera not showing or the flow getting stuck at "Detecting face...". The script below removes these conflicting flags from the xcconfig files after each pod install, ensuring the camera and face detection work correctly. This step is required for the plugin to function on iOS.

    Add this post-install block to your ios/Podfile (inside the existing post_install do |installer| block, after flutter_additional_ios_build_settings):

  # YouVerify SDK: Fix MediaPipe linker conflicts
  target_name = "Runner"
  debug_xcconfig_path = "#{installer.pods_project.project_dir}/Target Support Files/Pods-#{target_name}/Pods-#{target_name}.debug.xcconfig"
  release_xcconfig_path = "#{installer.pods_project.project_dir}/Target Support Files/Pods-#{target_name}/Pods-#{target_name}.release.xcconfig"

  [debug_xcconfig_path, release_xcconfig_path].each do |xcconfig_path|
    if File.exist?(xcconfig_path)
      xcconfig = File.read(xcconfig_path)
      xcconfig.gsub!(/-framework\s+"MediaPipeTasksCommon"/, '')
      xcconfig.gsub!(/-framework\s+"MediaPipeTasksVision"/, '')
      xcconfig.gsub!(/-force_load\s+"?[^"]*libMediaPipeTasksCommon.*\.a"?/, '')
      File.write(xcconfig_path, xcconfig)
    end
  end
  1. CocoaPods — After adding the plugin and updating the Podfile, run:
cd ios && pod install && cd ..

Getting Your Credentials

You need two credentials from YouVerify to use this plugin:

1. API Token

Your API token is used to authenticate requests to the YouVerify API. Never expose it in frontend code. Obtain it from your secure backend or use it only in trusted environments.

  • How to get it: Getting your API Key
  • Note: API keys created in the Test portal work only in the Sandbox environment. Keys from the Live portal work in Production.

2. Public Merchant Key

Your Public Merchant Key (also called publicMerchantID) identifies your merchant account.

Security recommendation

Recommended: Store credentials in a Flutter environment (e.g. flutter_dotenv, --dart-define, or a .env file) and load them at runtime. Credentials must not be checked into version control or exposed in any public or shared location (including hardcoding in source files).

Environment Summary

Portal Environment Use Case
Test Sandbox Development & testing
Live Production Real verification

Usage

1. Initialize the SDK

import 'package:youverify_liveness_sdk/youverify_liveness_sdk.dart';

final sdk = YouverifyLivenessSdk();

await sdk.initialize(
  config: YVLivenessConfig(
    apiToken: 'your_api_token',           // From your backend or secured location
    publicKey: 'your_public_merchant_key', // From your backend or secured location
    deviceCorrelationId: 'device_${DateTime.now().millisecondsSinceEpoch}', // Unique device/session ID for correlation (e.g. device ID or session UUID)
    environment: YVEnvironment.sandbox,    // Use YVEnvironment.live for production
    user: YVUser(
      firstName: 'John',
      lastName: 'Doe',
      email: 'john@example.com',
    ),
    branding: YVBranding(
      name: 'MyApp',
      color: '#0A2463',
      showPoweredBy: true,
      poweredByText: 'Powered by YouVerify',
    ),
    allowAudio: false,
  ),
  onSuccess: (result) {
    // Handle success — result contains faceImage, livenessClip, etc.
  },
  onFailure: (result) {
    // Handle failure — consider retrying on session errors
  },
  onClose: () {
    // Handle closing — 
  },
);

2. Start Liveness

// Use default tasks from config (or SDK defaults)
await sdk.startLiveness();

// Or pass specific tasks
await sdk.startLiveness(tasks: [
  YVTask.motions(difficulty: YVTaskDifficulty.medium, maxNods: 3, maxBlinks: 3),
  YVTask.blink(maxBlinks: 3),
]);

3. Dispose When Done

@override
void dispose() {
  sdk.dispose();
  super.dispose();
}

Configuration Reference

YVLivenessConfig

Parameter Type Required Description
apiToken String Yes Your YouVerify API token. Obtain from your backend.
publicKey String Yes Your Public Merchant Key.
deviceCorrelationId String Yes Unique device/session identifier (e.g. device_${timestamp}).
environment YVEnvironment No YVEnvironment.sandbox or YVEnvironment.live. Default: sandbox.
user YVUser? No User details (firstName required, lastName/email optional).
branding YVBranding? No UI branding (color, logo, poweredBy, etc.).
tasks List<YVTask>? No Default tasks when startLiveness is called without tasks.
allowAudio bool No Narrate instructions during tasks. Default: false.
metadata Map<String, dynamic>? No Additional metadata for the session.

YVUser

Parameter Type Required Description
firstName String Yes User's first name.
lastName String? No User's last name.
email String? No User's email.

YVBranding

Parameter Type Description
name String? Brand name shown in the UI.
color String? Hex or RGB color (e.g. #0A2463).
logo String? URL to your logo image.
logoAlt String? Alt text for logo.
hideLogo bool? Hide logo.
showPoweredBy bool? Show "Powered By" footer.
poweredByText String? Custom "Powered By" text.
poweredByLogo String? URL for "Powered By" logo.

Task Types

Task Description Key Parameters
Complete The Circle User traces an imaginary circle with head movement. difficulty, timeout
Yes or No User answers yes/no questions by tilting head (right = yes, left = no). questions, difficulty, timeout
Motions User performs nods, blinks, and mouth movements. maxNods, maxBlinks, difficulty, timeout
Blink User blinks a set number of times. maxBlinks, difficulty, timeout

Task Examples

// Complete The Circle
YVTask.completeTheCircle(difficulty: YVTaskDifficulty.medium)

// Yes or No
YVTask.yesOrNo(
  difficulty: YVTaskDifficulty.medium,
  questions: [
    YVQuestion(
      question: 'Is Nigeria a country?',
      answer: true,
      errorMessage: 'Read the question again',
    ),
    YVQuestion(question: 'Is the sky green?', answer: false),
  ],
)

// Motions
YVTask.motions(maxNods: 3, maxBlinks: 3, difficulty: YVTaskDifficulty.medium)

// Blink
YVTask.blink(maxBlinks: 3, difficulty: YVTaskDifficulty.easy)

// Multi-task (run multiple tasks in sequence)
[
  YVTask.blink(maxBlinks: 2),
  YVTask.motions(maxNods: 2, maxBlinks: 2),
]

Difficulty Levels

  • YVTaskDifficulty.easy
  • YVTaskDifficulty.medium (default)
  • YVTaskDifficulty.hard

Callbacks & Results

YVLivenessResult

Property Type Description
passed bool Whether the liveness check passed.
faceImage String? Base64 or URL of captured face image.
livenessClip String? Base64 or URL of liveness video clip.
metadata Map<String, dynamic>? Session metadata.
error YVLivenessError? Error details when passed is false.

YVLivenessError

Property Type Description
key String Error identifier (e.g. invalid_or_expired_session, session_token_error).
message String? Human-readable error message.
isSessionError bool True for session-related errors; consider reinitializing.

Session Error Handling

When result.error?.isSessionError is true, the session may have expired. Reinitialize the SDK and retry:

void _handleFailure(YVLivenessResult result) {
  if (result.error?.isSessionError == true) {
    // Session expired — reinitialize and retry
    _initialize();
    return;
  }
  // Handle other failures
}

Example App

The example folder contains a complete integration sample. To run it:

  1. Clone or open the project containing the plugin and example app.

  2. Add your credentials — In example/lib/screens/home_screen.dart, update the _config getter with your API token and public key (or load them from a secure source):

YVLivenessConfig get _config => YVLivenessConfig(
  apiToken: 'YOUR_API_TOKEN',
  publicKey: 'YOUR_PUBLIC_MERCHANT_KEY',
  deviceCorrelationId: 'device_${DateTime.now().millisecondsSinceEpoch}',
  environment: YVEnvironment.sandbox,
  user: const YVUser(firstName: 'Ada', lastName: 'Lovelace', email: 'ada@example.com'),
  branding: const YVBranding(
    name: 'DemoApp',
    color: '#0A2463',
    showPoweredBy: true,
    poweredByText: 'Powered by YouVerify',
  ),
  allowAudio: false,
);
  1. Install dependencies:
cd example
flutter pub get
  1. iOS: Run pod install in the ios folder:
cd example/ios && pod install && cd ../..
  1. Run on a physical device:
cd example
flutter run

The example app demonstrates:

  • SDK initialization with config
  • Starting different task types (Complete The Circle, Yes or No, Motions, Blink, Multi-Task)
  • Handling success, failure, and close callbacks
  • Session expiry handling and reinitialization
  • Error display and result cards

Troubleshooting

"No view controller available for presentation" (iOS)

Ensure the app has a visible window and that you are not calling startLiveness before the Flutter view is attached. Avoid calling from initState before the first frame; use WidgetsBinding.instance.addPostFrameCallback or a button press.

Camera not showing / "Detecting face..." stuck

  • Use a physical device — The iOS Simulator does not support the camera.
  • Grant camera permission — When prompted, allow camera access. Check Settings → Privacy & Security → Camera for your app.
  • Rebuild — Run flutter clean, then flutter pub get, then cd ios && pod install for iOS.

Session fetch failed

  • Verify your API token and Public Merchant Key are correct.
  • Ensure you are using sandbox credentials with YVEnvironment.sandbox and live credentials with YVEnvironment.live.
  • Check network connectivity.

Build errors after plugin update

flutter clean
flutter pub get
cd ios && pod install && cd ..
flutter run

Support


Credits

This Flutter plugin is an independent, third-party integration of the YouVerify Liveness SDK for Flutter. It is not officially developed, maintained, or endorsed by YouVerify. The underlying native Liveness SDK is developed by YouVerify.

Libraries

youverify_liveness_sdk
YouVerify Liveness SDK for Flutter