> ## 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 Android SDK from v2 to v4

> This guide covers all breaking changes introduced in version `4.0.0` of the Fingerprint Android SDK and outlines the steps required to migrate an existing v2 integration.

We have released a new major version of the Fingerprint Android SDK (version `4.0.0`), which allowed us to introduce breaking changes and requires you to manually migrate. The new Android SDK aligns with the v4 event format. This includes renamed classes and interfaces, a flattened response format, and a revised set of error types. None of these changes affect the underlying identification and and smart signals accuracy; these are structural/API changes only.

<Warning>
  * Native mobile SDKs v2.x will continue to work after v4.0.0 is released - you won't be forced to upgrade right away.
  * During this period, critical client-side hotfixes will still be issued for v2.x if needed, and backend-side improvements (including smart signals detection logic) can continue to benefit v2.x integrations, as long as the required signals are already collected by that SDK version.
  * However, iOS and Android SDKs v2.x support is tied to our overall API v3 deprecation timeline: once the [one-year deprecation period](https://docs.fingerprint.com/reference/migrating-from-v3-to-v4#client-sdk-compatibility-for-javascript-agent-v4) begins (which starts only after the full ecosystem, including Flutter and React Native SDKs, supports Server API v4), mobile SDKs v2.x will no longer receive client-side hotfixes once that period ends. Backend-side improvements will still apply to v2.x wherever the SDK already collects the necessary signals.
</Warning>

# What's new

* The dependency coordinate changed from `com.fingerprint.android:pro` to `com.fingerprint.android:sdk`, and the public API types moved from the `com.fingerprintjs.android.fpjs_pro` package to `com.fingerprint.android`, dropping the legacy `js`/`pro` naming.
* `FingerprintJSFactory` and the `FingerprintJS` interface are renamed to `FingerprintFactory` and `Fingerprint`, dropping the legacy "JS" naming.
* The response object is renamed from `FingerprintJSProResponse` to `FingerprintResponse`, and several nested/legacy fields (`confidenceScore`, `ipLocation`, `firstSeenAt`, and similar) have been removed in favor of a flat response shape, along with their supporting types (`ConfidenceScore`, `Timestamp`, and `IpLocation`).
* `requestId` is renamed to `eventId` across responses, errors, and exceptions.
* The `extendedResponseFormat` configuration flag has been removed as v4 always returns the flat format.
* Several error classes have been removed or replaced, and new error classes have been added to reflect new server-side error codes.
* Kotlin upgraded from v1.9.25 to v2.3.20.

# Migration steps

The following section outlines the necessary migration steps to complete the transition from v2 to v4.

## Upgrade the MAJOR package version

Update the Fingerprint Android SDK dependency to the latest v4 version in your module's `build.gradle` (or `build.gradle.kts`) `dependencies` block. The artifact coordinate also changed from `com.fingerprint.android:pro` to `com.fingerprint.android:sdk`:

<CodeGroup>
  ```kotlin build.gradle.kts theme={"theme":"github-dark-dimmed"}
  implementation("com.fingerprint.android:sdk:4.0.0")
  ```

  ```groovy build.gradle theme={"theme":"github-dark-dimmed"}
  implementation "com.fingerprint.android:sdk:4.0.0"
  ```
</CodeGroup>

## Update imports

The public API types moved to the `com.fingerprint.android` package. Update every `import com.fingerprintjs.android.fpjs_pro.*` statement to `com.fingerprint.android.*`. A project-wide **Replace All** in your IDE is the quickest way to do this.

<CodeGroup>
  ```kotlin Update imports theme={"theme":"github-dark-dimmed"}
  import com.fingerprintjs.android.fpjs_pro.Configuration // [!code --]
  import com.fingerprintjs.android.fpjs_pro.FingerprintFactory // [!code --]
  import com.fingerprintjs.android.fpjs_pro.FingerprintException // [!code --]
  import com.fingerprint.android.Configuration // [!code ++]
  import com.fingerprint.android.FingerprintFactory // [!code ++]
  import com.fingerprint.android.FingerprintException // [!code ++]
  ```
</CodeGroup>

## Class and interface renames

Several classes and interfaces were renamed to drop the legacy `JS` naming.

| Android SDK v2              | Android SDK v4            |
| --------------------------- | ------------------------- |
| `FingerprintJSFactory`      | `FingerprintFactory`      |
| `FingerprintJS` (interface) | `Fingerprint` (interface) |
| `FingerprintJSProResponse`  | `FingerprintResponse`     |

<CodeGroup>
  ```kotlin Class and interface renames theme={"theme":"github-dark-dimmed"}
  val client: FingerprintJS = FingerprintJSFactory(context).createInstance(config) // [!code --]
  val client: Fingerprint = FingerprintFactory(context).createInstance(config) // [!code ++]

  client.getVisitorId { response: FingerprintJSProResponse -> ... } // [!code --]
  client.getVisitorId { response: FingerprintResponse -> ... } // [!code ++]
  ```
</CodeGroup>

## `FingerprintResponse` field changes

The response object is now flat and no longer exposes the nested fields that came from the old `/products/identification/data/result` response format.

### Renamed

| Android SDK v2       | Android SDK v4     |
| -------------------- | ------------------ |
| `response.requestId` | `response.eventId` |

### Added

| Field          | Type     | Notes                                             |
| -------------- | -------- | ------------------------------------------------- |
| `eventId`      | `String` | Replaces `requestId`                              |
| `suspectScore` | `Int?`   | Risk score from the server; `null` if not present |

### Removed

The following fields are no longer part of the response:

| Removed field     | Type              |
| ----------------- | ----------------- |
| `requestId`       | `String`          |
| `visitorFound`    | `Boolean`         |
| `confidenceScore` | `ConfidenceScore` |
| `ipAddress`       | `String`          |
| `ipLocation`      | `IpLocation?`     |
| `osName`          | `String`          |
| `osVersion`       | `String`          |
| `firstSeenAt`     | `Timestamp`       |
| `lastSeenAt`      | `Timestamp`       |

The data classes `ConfidenceScore`, `Timestamp`, and `IpLocation` (including the nested `City`, `Country`, `Continent`, and `Subdivisions` types) have been removed from the SDK entirely. See [IP Geolocation](https://docs.fingerprint.com/docs/smart-signals-reference#ip-geolocation) for a replacement available in our Smart Signals product.

<CodeGroup>
  ```kotlin FingerprintResponse field changes theme={"theme":"github-dark-dimmed"}
  client.getVisitorId { response ->
      println(response.requestId) // [!code --]
      println(response.visitorFound) // [!code --]
      println(response.confidenceScore) // [!code --]
      println(response.ipAddress) // [!code --]
      println(response.firstSeenAt) // [!code --]
      println(response.eventId) // [!code ++]
      println(response.visitorId) // [!code ++]
      println(response.suspectScore) // [!code ++]
      // ipAddress, confidenceScore, firstSeenAt, and similar fields are no longer available // [!code ++]
  }
  ```
</CodeGroup>

## `Configuration` changes

`extendedResponseFormat: Boolean` has been removed. The v4 API always returns a flat response, so the extended format toggle no longer exists.

<CodeGroup>
  ```kotlin Remove extendedResponseFormat theme={"theme":"github-dark-dimmed"}
  Configuration(
      apiKey = "your_api_key",
      // ...
      extendedResponseFormat = true, // [!code --]
  )
  ```
</CodeGroup>

## Rename `requestId` to `eventId` on `Error` and `FingerprintException`

The `requestId` property on both `Error` and `FingerprintException` has been renamed to `eventId`.

<CodeGroup>
  ```kotlin Listener API theme={"theme":"github-dark-dimmed"}
  client.getVisitorId(
      listener = { response -> ... },
      errorListener = { error ->
          println(error.requestId) // [!code --]
          println(error.eventId) // [!code ++]
      }
  )
  ```

  ```kotlin Coroutine API theme={"theme":"github-dark-dimmed"}
  try {
      val response = client.getVisitorId()
  } catch (e: FingerprintException) {
      println(e.requestId) // [!code --]
      println(e.eventId) // [!code ++]
  }
  ```
</CodeGroup>

## Error class changes

### Removed error classes

These error classes no longer exist in v4. Remove any `when` branches or `isErrorType<T>()` checks that reference them.

* `ApiKeyExpired`
* `UnsupportedVersion`
* `OriginNotAvailable`
* `PackageNotAuthorized`
* `HeaderRestricted`
* `NotAvailableForCrawlBots`
* `NotAvailableWithoutUA`

### New error classes

The following error classes are new in v4 and map to new server-side error codes.

| New class                | When it occurs                                 |
| ------------------------ | ---------------------------------------------- |
| `SecretApiKeyRequired`   | Secret API key header is missing               |
| `SecretApiKeyNotFound`   | No workspace found for the provided secret key |
| `VisitorNotFound`        | Requested visitor does not exist               |
| `ServiceUnavailable`     | Server-side service unavailable                |
| `SubscriptionRestricted` | Subscription is restricted                     |
| `FeatureNotEnabled`      | Feature is not enabled for this workspace      |
| `RequestNotFound`        | Event or request not found                     |
| `StateNotReady`          | Resource is not yet mutable, retry later       |
| `MissingModule`          | A required server module is missing            |
| `PayloadTooLarge`        | Request payload exceeded the size limit        |
| `RulesetNotFound`        | Specified ruleset not found                    |
| `EnvironmentRestricted`  | Environment is restricted                      |
| `SubscriptionNotFound`   | Subscription not found                         |

If you have an exhaustive `when` on `Error` subtypes, add an `else` branch (or handle the new types explicitly) to avoid compile errors.

<CodeGroup>
  ```kotlin Error handling theme={"theme":"github-dark-dimmed"}
  errorListener = { error ->
      when (error) {
          is ApiKeyExpired -> handleExpired() // [!code --]
          is ApiKeyNotFound -> handleNotFound()
          is NetworkError -> handleNetwork()
          is ClientTimeout -> handleTimeout()
          is VisitorNotFound -> handleVisitorNotFound() // [!code ++]
          is ServiceUnavailable -> handleServiceUnavailable() // [!code ++]
          else -> logUnknown(error.requestId) // [!code --]
          else -> logUnknown(error.eventId) // [!code ++]
      }
  }
  ```
</CodeGroup>

### Check out these related resources:

* [Android SDK changelog](/docs/changelog-android-sdk#august-2026)
* [Android SDK reference](/docs/android-sdk)
* [Android Quickstart](/docs/android-quickstart)
* Download our [**Android demo app**](https://play.google.com/store/apps/details?id=com.fingerprintjs.android.fpjs_pro_demo) from
  Google Play to see Fingerprint in action.
