Flutter SDK

verify_ai_flutter provides a Dart VerifyAIClient, a high-level VerifyAI wrapper, and a ScannerOptions builder for the embedded camera UI.

Install

bash
flutter pub add verify_ai_flutter

Platform setup

Add camera permission to ios/Runner/Info.plist:

xml
<key>NSCameraUsageDescription</key>
<string>Camera is used for photo verification</string>

Add camera permission to android/app/src/main/AndroidManifest.xml:

xml
<uses-permission android:name="android.permission.CAMERA" />

Android minSdkVersion 21 or higher is required (Flutter camera plugin baseline).

Quick start

Use the high-level wrapper when you want a one-shot scanner flow:

dart
import 'package:flutter/material.dart';
import 'package:verify_ai_flutter/verify_ai_flutter.dart';
 
final verifyAI = VerifyAI(apiKey: 'vai_your_api_key');
 
Future<void> handleVerify(BuildContext context) async {
  final result = await verifyAI.presentScanner(
    context,
    policy: 'scooter_parking',
    options: const ScannerOptions(
      guidanceText: 'Center the scooter in the frame',
      processingMessage: 'Checking parking compliance...',
      failureMessage: 'Parking issue detected',
      retryMessage: 'Try again. {remaining} attempts left.',
      terminalResultDisplayDuration: Duration(seconds: 3),
      terminalActionLabel: 'Continue',
    ),
  );
 
  if (result == null) return; // user dismissed
 
  if (result.isCompliant) {
    print('Verified: \${result.verificationId}');
  } else {
    print('Issues: \${result.violationReasons}');
  }
}

presentScanner() returns null only if the user dismisses the screen before a terminal result is produced. It uses multipart uploads for live camera captures and does not persist raw image bytes to the offline queue. If full offline replay matters, capture the image yourself and call verify() with a base64-encoded payload instead.

Direct API access

Use VerifyAIClient when you want full control over capture and request flow:

dart
import 'package:verify_ai_flutter/verify_ai_flutter.dart';
 
final client = VerifyAIClient(
  const VerifyAIConfig(apiKey: 'vai_your_api_key'),
);
 
final result = await client.verify(
  const VerificationRequest(
    image: base64ImageData,
    policy: 'scooter_parking',
    metadata: {'device_id': 'dev_123'},
  ),
);

For raw camera bytes, use verifyMultipart():

dart
final result = await client.verifyMultipart(
  imageBytes: bytes,
  policy: 'scooter_parking',
  metadata: const {'device_id': 'dev_123'},
);

Policy-aware scanner copy

For scooter, bike, and forest parking policies, presentScanner() applies policy-aware default copy and guide overlays. Override any copy with ScannerOptions:

| Option | Description | | ------------------------------- | -------------------------------------------- | | guidanceText | Top-of-screen instruction. | | processingMessage | Shown while the API call is in flight. | | successMessage | Shown on a compliant result. | | failureMessage | Shown on a non-compliant result. | | retryMessage | Shown between retries; supports {remaining}.| | exhaustedMessage | Shown after maxAttempts retries. | | terminalActionLabel | Button label on the result screen. | | terminalResultDisplayDuration | How long to hold the result before dismissing.|

On-device inference

The SDK ships hooks for tflite_flutter, but on-device inference is currently disabled on iOS pending a fix for the upstream crash (see pubspec.yaml). When you need it, set VerifyAIConfig(onDeviceEnabled: true) and we'll route eligible verifications through the on-device pipeline.

Versioning

The current published version is 2.4.x (kept in sync with the React Native SDK). The Flutter SDK follows semver and is shipped from the same release process. Check your installed version against pubspec.lock.

Get in Touch

Questions about pricing, integrations, or custom deployments? We'd love to hear from you.