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';

// consent: granted only once you have consent (or another lawful basis)
final fingerly = await Fingerly.load(apiKey: 'fly_pk_production_…', consent: ConsentState.granted);

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.pending})Future<Fingerly>An empty endpoint uses https://api.fingerly.io. Nothing is collected until consent is granted. 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.deleteStoredIdentity()Future<void>Deletes the install record on the device. See below.
Fingerly.nativeVersion()Future<String>The native SDK version.

Deleting the stored identity

lib/delete_account.dart
await Fingerly.deleteStoredIdentity();

Deletes the install record the native SDK keeps on the device, including the install ID the server recognises it by, for erasure requests and account deletion. It needs no load and no consent, sends nothing, and completes once no record remains, including when there was none. It throws a FingerlyException when the delete fails. The next identification made with consent starts a new install ID; to stop identifying as well, set consent to ConsentState.denied first. On iOS the record survives the app being deleted, so this is the only way to remove it. See account deletion and erasure.

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 */ }
}