SDKs

Flutter

Identify devices in Flutter apps through the native iOS and Android SDKs, with a typed Dart API and the same verdicts on both platforms.

fingerly_flutter is a plugin over the native iOS and Android SDKs. Collection happens in native code; Dart gets typed results.

Requirements

  • Flutter 3.10 or newer, Dart 3.
  • iOS 13 and Android 5.0 (API 21) or newer.

Install

flutter pub add fingerly_flutter

The iOS side supports both CocoaPods and Swift Package Manager.

Identify a device

lib/fingerly.dart
import 'package:fingerly_flutter/fingerly.dart';

final fingerly = await Fingerly.load(apiKey: 'fly_pk_us_production_…');

Future<void> signIn(String email, String password) async {
  final result = await fingerly.identify(tag: 'sign-in');
  await api.signIn(email, password, requestId: result.requestId);
}

Send requestId to your backend with the action, and decide there after reading the stored event with a secret key. See server-side verification.

API

MemberReturnsNotes
Fingerly.load({required String apiKey, String endpoint = '', ConsentState consent = ConsentState.granted})Future<Fingerly>An empty endpoint uses the region in the key. The consent state is shared by the whole app, so pass it on every load.
setConsent(ConsentState state)Future<void>Changes the consent state. consent reads it. Until it is granted, identify and collect throw FingerlyConsentException.
identify({String? tag, bool submit = true})Future<IdentifyResult>suspectScore is int? and null when nothing was scored.
collect()Future<SignalReport>Collects without submitting.
Fingerly.nativeVersion()Future<String>The native SDK version.

Verdicts

VerdictPlatformWhat it means
instrumentationBothAn instrumentation toolkit is attached to the app.
mitmBothSomething is intercepting the app's encrypted traffic.
automationBothA debugger or a test runner is driving the app.
tamperingBothThe app's code has been hooked or modified.
farmBothThe device looks mass-provisioned or freshly reset.
jailbreak, simulatoriOSJailbroken device; iOS Simulator.
root, emulator, appClonerAndroidRooted device; emulator; cloning framework.
verdicts.dart
if (result.verdicts.jailbreak.value &&
    result.verdicts.jailbreak.confidence == Confidence.high) {
  // add friction, and let your server make the final decision
}

Errors

errors.dart
try {
  await fingerly.identify();
} on FingerlyException catch (error) {
  if (error.status == 401) { /* the key is wrong */ }
  if (error.status == 402) { /* the organization is not accepting traffic */ }
}