> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fingerprint.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating the Fingerprint Flutter SDK from v4 to v5

> Breaking changes in version `5.0.0` of the Fingerprint Flutter SDK and the steps to migrate an existing v4 integration.

Fingerprint Flutter SDK `5.0.0` is built on the v4 native SDKs: the [Android SDK](/docs/android-sdk) and the [iOS SDK](/docs/ios-sdk). On web, it uses [JavaScript agent v4](/reference/migrating-from-v3-to-v4). All platforms return the v4 event format. It introduces breaking changes, so you must migrate your integration manually. v5 changes the public API and your project's minimum Flutter, Dart, Android, iOS, Xcode, and build-tool versions. It does not change identification or Smart Signals accuracy.

<Warning>
  * Flutter SDK v4 (`fpjs_pro_plugin`) keeps working after v5 is released. You don't have to upgrade right away.
  * Flutter SDK v4 uses API v3. Its support ends with the API v3 [one-year deprecation period](/reference/api-deprecation-policy#one-year-migration-period).
</Warning>

## What's new

* On Android and iOS, the SDK uses native SDK v4 (`4.1.x`) instead of v2. Only native patch releases are picked up automatically.
* The package is renamed from `fpjs_pro_plugin` to `fingerprint_flutter`, and the GitHub repository moved from `fingerprintjs/fingerprintjs-pro-flutter` to `fingerprintjs/flutter`.
* The static `FpjsProPlugin` API is replaced by a `Fingerprint` client instance with a single `get()` method.
* Platform-specific options are grouped under `android`, `ios`, and `web`, and `endpoint` and `endpointFallbacks` are replaced by a single `endpoints` list.
* The result is a flat `FingerprintResult`. `requestId` is renamed to `eventId`, and the extended response fields are removed.
* All error subclasses are replaced by a single `FingerprintError` with a `code` field.
* Timeouts use `Duration` instead of milliseconds.
* On web, the SDK uses JavaScript agent v4, bundled in the package.
* The constructor and `get()` validate their arguments and throw `ArgumentError` for invalid values.
* The minimum versions are Flutter 3.44.0, Dart 3.12.0, Android 7.0 (API level 24), and iOS 15 with Xcode 16 and Swift 6.

## Migration steps

### Update your environment

Make sure your app meets the new minimum versions:

| Requirement | v4 minimum | v5 minimum |
| - | - | - |
| Flutter | 3.19.0 | 3.44.0 |
| Dart | 3.3.0 | 3.12.0 |
| Android | 6.0 (API level 23) | 7.0 (API level 24) |
| iOS | 13 | 15 |
| Swift | 5.9 | 6 |

v5 also requires Xcode 16 or higher.

* On iOS, update the `platform :ios` line in `ios/Podfile` if you use CocoaPods, and the iOS deployment target in Xcode.
* On Android, set `minSdk` to `24` or higher in `android/app/build.gradle` (or `build.gradle.kts`).
* The plugin no longer applies the Kotlin Gradle plugin, so it builds with Android Gradle plugin (AGP) 9. If your app still uses AGP 8, use Kotlin Gradle plugin 2.2.20 or higher.
* The plugin no longer adds the `jitpack.io` Maven repository to your Gradle project. If your app depends on packages from JitPack, add `maven { url 'https://jitpack.io' }` to your repositories yourself.

### Replace the package

In `pubspec.yaml`, replace `fpjs_pro_plugin` with `fingerprint_flutter`:

```yaml pubspec.yaml theme={"theme":"github-dark-dimmed"}
dependencies:
  flutter:
    sdk: flutter
  fpjs_pro_plugin: ^4.13.1 # [!code --]
  fingerprint_flutter: ^5.0.0 # [!code ++]
```

Run `flutter pub get`. Then update your imports. The new package exports all public types from a single library:

```dart Dart theme={"theme":"github-dark-dimmed"}
import 'package:fpjs_pro_plugin/fpjs_pro_plugin.dart'; // [!code --]
import 'package:fpjs_pro_plugin/error.dart'; // [!code --]
import 'package:fpjs_pro_plugin/region.dart'; // [!code --]
import 'package:fpjs_pro_plugin/result.dart'; // [!code --]
import 'package:fingerprint_flutter/fingerprint_flutter.dart'; // [!code ++]
```

Two top-level APIs are also renamed:

| v4 | v5 |
| - | - |
| `pluginVersion` | `fingerprintFlutterVersion` |
| `Region.stringValue` | `Region.name` |

If your app targets web, update the loader script in `web/index.html`:

```html web/index.html theme={"theme":"github-dark-dimmed"}
<!-- [!code --:1] -->
<script src="assets/packages/fpjs_pro_plugin/web/index.js" defer></script>
<!-- [!code ++:1] -->
<script src="assets/packages/fingerprint_flutter/web/index.js" defer></script>
```

### Create a `Fingerprint` client

`FpjsProPlugin.initFpjs()` is replaced by the `Fingerprint` constructor. The constructor is synchronous, so you don't need to `await` it. It starts the client in the background, and errors from starting the client surface when you call `get()`. The constructor itself throws in these cases:

* `ArgumentError` if an `endpoints` entry is not an `http` or `https` URL, or if `android.locationTimeout` is under 1 millisecond.
* `FlutterError` on Android and iOS if the Flutter binding doesn't exist yet. Call `WidgetsFlutterBinding.ensureInitialized()` before you create the client, as you did before `initFpjs()`.

`getVisitorId()` and `getVisitorData()` are replaced by a single `get()` method.

```dart Dart theme={"theme":"github-dark-dimmed"}
WidgetsFlutterBinding.ensureInitialized();
await FpjsProPlugin.initFpjs('PUBLIC_API_KEY', region: Region.eu); // [!code --]
final visitorId = await FpjsProPlugin.getVisitorId(); // [!code --]
final visitorData = await FpjsProPlugin.getVisitorData(); // [!code --]
final fingerprint = Fingerprint(apiKey: 'PUBLIC_API_KEY', region: Region.eu); // [!code ++]
final result = await fingerprint.get(); // [!code ++]
print(result.visitorId); // [!code ++]
print(result.eventId); // [!code ++]
```

Create one client per public API key and configuration, for example when your app starts, and reuse it.

### Update identification options

`get()` accepts `tags` and `linkedId` like `getVisitorData()`. `timeoutMs` is replaced by `timeout`, which takes a `Duration`.

`get()` now validates its arguments and throws `ArgumentError` before identifying if:

* `tags` is not JSON-compatible. Keys must be strings, and values must be strings, finite numbers, booleans, `null`, lists, or nested maps. Typed lists such as `Uint8List` are rejected.
* `timeout` is under 1 millisecond.

In v4, some of these values were silently dropped or failed with a timeout error. Check that your `tags` are JSON-compatible before you upgrade.

```dart Dart theme={"theme":"github-dark-dimmed"}
await FpjsProPlugin.getVisitorData( // [!code --]
await fingerprint.get( // [!code ++]
  tags: {'action': 'login'},
  linkedId: 'user_1234',
  timeoutMs: 5000, // [!code --]
  timeout: const Duration(seconds: 5), // [!code ++]
);
```

### Update client options

Options that apply to one platform only are grouped in `AndroidOptions`, `IosOptions`, and `WebOptions`. `endpoint` and `endpointFallbacks` are replaced by a single `endpoints` list.

| v4 option | v5 option |
| - | - |
| `apiKey` (positional argument) | `apiKey` (named argument) |
| `region` | `region` |
| `endpoint` and `endpointFallbacks` | `endpoints` |
| `allowUseOfLocationData` | `android.allowUseOfLocationData` and `ios.allowUseOfLocationData` |
| `locationTimeoutMillisAndroid` | `android.locationTimeout` (`Duration`) |
| `scriptUrlPattern` and `scriptUrlPatternFallbacks` | Removed, use `endpoints` instead. |
| `extendedResponseFormat` | Removed. v5 only has one response format. |

```dart Dart theme={"theme":"github-dark-dimmed"}
await FpjsProPlugin.initFpjs( // [!code --]
  'PUBLIC_API_KEY', // [!code --]
  region: Region.eu, // [!code --]
  endpoint: 'https://metrics.yourwebsite.com', // [!code --]
  endpointFallbacks: ['https://eu.api.fpjs.io'], // [!code --]
  allowUseOfLocationData: true, // [!code --]
  locationTimeoutMillisAndroid: 5000, // [!code --]
); // [!code --]
final fingerprint = Fingerprint( // [!code ++]
  apiKey: 'PUBLIC_API_KEY', // [!code ++]
  region: Region.eu, // [!code ++]
  endpoints: ['https://metrics.yourwebsite.com', 'https://eu.api.fpjs.io'], // [!code ++]
  android: const AndroidOptions( // [!code ++]
    allowUseOfLocationData: true, // [!code ++]
    locationTimeout: Duration(seconds: 5), // [!code ++]
  ), // [!code ++]
  ios: const IosOptions(allowUseOfLocationData: true), // [!code ++]
); // [!code ++]
```

<Warning>
  With a custom `endpoints` list, the SDK tries only the endpoints you pass. It does not fall back to the default Fingerprint endpoint. Add the default endpoint for your [region](/docs/regions) as the last item.
</Warning>

On web, you can also enable caching of identification results with `WebOptions`. Caching is off by default. See [Web options](https://github.com/fingerprintjs/flutter#web-options) in the Flutter SDK README and the JavaScript agent [`cache` option](/reference/js-agent-start-function#cache).

### Update result fields

The result is now a flat `FingerprintResult`:

| v4 field | v5 field |
| - | - |
| `requestId` | `eventId` |
| `visitorId` (`String`) | `visitorId` (`String?`) |
| `sealedResult` | `sealedResult` |
| `confidenceScore` | Removed |
| Extended fields, such as `ipLocation` and `firstSeenAt` | Removed |

`visitorId` is `null` when the visitor ID is hidden, for example in [Zero Trust Mode](/docs/zero-trust-mode).

v5 also adds these fields:

* `suspectScore`: the [Suspect Score](/docs/suspect-score), if available. It is not a replacement for the confidence score. A higher value means a more suspicious request.
* `cacheHit`: `true` when the result came from the web cache. `null` on web unless `WebOptions.cache` is set, and always `null` on Android and iOS.

The `FingerprintJSProResponse` and `FingerprintJSProExtendedResponse` types are removed. To get the data from the removed fields, send `eventId` to your backend and get the full event with the [Server API](/reference/server-api-get-event).

```dart Dart theme={"theme":"github-dark-dimmed"}
final requestId = visitorData.requestId; // [!code --]
final score = visitorData.confidenceScore.score; // [!code --]
final eventId = result.eventId; // [!code ++]
final suspectScore = result.suspectScore; // [!code ++]
```

### Update error handling

The `FingerprintProError` subclasses, such as `TooManyRequestError` and `ClientTimeoutError`, are replaced by a single `FingerprintError` class. Compare `error.code` with the constants on `FingerprintError` instead of checking the error type.

`FingerprintError` does not extend `PlatformException`. If your code catches SDK errors with `on PlatformException`, it still compiles but no longer catches them. Catch `FingerprintError` instead.

```dart Dart theme={"theme":"github-dark-dimmed"}
try {
  await FpjsProPlugin.getVisitorData(); // [!code --]
  await fingerprint.get(); // [!code ++]
} on FingerprintProError catch (error) { // [!code --]
  if (error is TooManyRequestError) { // [!code --]
} on FingerprintError catch (error) { // [!code ++]
  if (error.code == FingerprintError.tooManyRequests) { // [!code ++]
    // Handle rate limiting
  }
}
```

Common v4 error classes map to these codes:

| v4 error class | v5 `error.code` |
| - | - |
| `ClientTimeoutError` | `client_timeout` (`FingerprintError.clientTimeout`) |
| `NetworkError` | `network_error` (`FingerprintError.networkError`) |
| `TooManyRequestError` | `too_many_requests` (`FingerprintError.tooManyRequests`) |
| `ApiKeyNotFoundError` | `public_api_key_not_found` (`FingerprintError.publicApiKeyNotFound`) |
| `WrongRegionError` | `wrong_region` (`FingerprintError.wrongRegion`) |

Error codes are the same on Android, iOS, and web where the platforms share the error. Network failures report the `network_error` code on all platforms. The list of codes can grow in future versions, so add a generic fallback for codes you don't handle. For the full list, see the [`FingerprintError` constants](https://github.com/fingerprintjs/flutter/blob/main/lib/src/fingerprint_error.dart).

## Related resources

* [Flutter SDK](/docs/flutter)
* [Flutter quickstart](/docs/flutter-quickstart)
* [Flutter SDK changelog](https://github.com/fingerprintjs/flutter/blob/main/CHANGELOG.md)
* [Migrating the JavaScript agent from v3 to v4](/reference/migrating-from-v3-to-v4)
* [Migrating the Server API from v3 to v4](/reference/migrating-from-server-api-v3-to-v4)
