> ## 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 JavaScript agent from v3 to v4

> Comprehensive migration guide with all migration requirements between the v3 (3.x.x) and v4 (4.x.x) JavaScript agent versions.

We have released a new major version of the agent (version `4.x.x`), which allowed us to introduce breaking changes and requires customers to manually migrate. The new agent ensures that we are ready for continuous scaling and that our customers can benefit from reliable features along with latency and accuracy improvements.

<Warning>
  Most [client libraries](/docs/frontend-libraries) and all [proxy
  integrations](/docs/protecting-the-javascript-agent-from-adblockers) support JavaScript agent v4. If you use the [Flutter
  SDK](/docs/flutter) or [React Native SDK](/docs/fingerprintjs-pro-react-native), postpone migration until v4 support
  is available. The [one year deprecation
  period](/reference/api-deprecation-policy#one-year-migration-period) only starts after the entire
  ecosystem supports JavaScript agent v4 and Server API v4.
</Warning>

## Client SDK compatibility for JavaScript agent v4

| Client SDK or integration                                                    | Support status | Minimum version with v4 support                                                                                      |
| ---------------------------------------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------- |
| [React SDK](/docs/react)                                                     | ✅ Supported    | `@fingerprint/react` [v3.0.0](https://github.com/fingerprintjs/react/releases/tag/v3.0.0)                            |
| [Vue SDK](/docs/vuejs)                                                       | ✅ Supported    | `@fingerprint/vue` [v2.0.0](https://github.com/fingerprintjs/vue/releases/tag/%40fingerprint%2Fvue%402.0.0)          |
| [Angular SDK](/docs/angular)                                                 | ✅ Supported    | `@fingerprint/angular` [v3.0.0][angular-v3]                                                                          |
| [Svelte SDK](/docs/svelte)                                                   | ✅ Supported    | `@fingerprint/svelte` [v3.0.0](https://github.com/fingerprintjs/svelte/releases/tag/%40fingerprint%2Fsvelte%403.0.0) |
| [Flutter SDK](/docs/flutter)                                                 | 🚧 In progress | Not available yet                                                                                                    |
| [React Native SDK](/docs/fingerprintjs-pro-react-native)                     | 🚧 In progress | Not available yet                                                                                                    |
| [Google Tag Manager integration](/docs/fingerprintjs-pro-google-tag-manager) | ✅ Supported    | [v2.0.0](https://github.com/fingerprintjs/gtm-integration/releases/tag/v2.0.0)                                       |

## Proxy integration compatibility for JavaScript agent v4

| Proxy integration                                                          | Support status | Minimum version with v4 support                                                                                              |
| -------------------------------------------------------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| [Custom subdomain setup](/docs/custom-subdomain-setup)                     | ✅ Supported    | Not versioned                                                                                                                |
| [Cloudflare Proxy Integration](/docs/cloudflare-integration)               | ✅ Supported    | [1.7.0](https://github.com/fingerprintjs/cloudflare-worker-proxy/releases/tag/v1.7.0)                                        |
| [AWS CloudFront Proxy Integration](/docs/cloudfront-proxy-integration-v2)  | ✅ Supported    | [v2.2.0](https://github.com/fingerprintjs/aws-cloudfront-proxy/releases/tag/%40fingerprint%2Faws-cloudfront-proxy%402.2.0)   |
| [Azure FrontDoor Proxy Integration](/docs/azure-proxy-integration)         | ✅ Supported    | [v2.0.0](https://github.com/fingerprintjs/azure-frontdoor-proxy/releases/tag/%40fingerprint%2Fazure-frontdoor-proxy%402.0.0) |
| [Akamai Proxy Integration](/docs/akamai-proxy-integration)                 | ✅ Supported    | [v1.1.0](https://github.com/fingerprintjs/akamai-proxy/releases/tag/v1.1.0)                                                  |
| [Fastly VCL Proxy Integration](/docs/fastly-vcl-proxy-integration)         | ✅ Supported    | [v2.0.0](https://github.com/fingerprintjs/fastly-vcl-proxy/releases/tag/v2.0.0)                                              |
| [Fastly Compute Proxy Integration](/docs/fastly-compute-proxy-integration) | ✅ Supported    | [v0.4.0](https://github.com/fingerprintjs/fastly-compute-proxy/releases/tag/v0.4.0)                                          |

# What's new

* The new agent matches our recently released [Server API v4](/reference/server-api-v4-get-event) in terminology and the event format. This makes it easier to integrate across frontend and backend implementations, significantly reducing the time required to adopt new features.
* Removed deprecated configuration options:
  * `tlsDisabled` and `tlsEndpoint`, which made it possible to configure the old TLS endpoint. If you used this option, use the `endpoints` option instead, and let us know if you see any missing capabilities.
  * `extendedResult` became redundant as a `get()` option after the introduction of Smart Signals and Sealed Client Results. All information is sent to the client in a secure and encrypted form instead, if configured. **`Use sealed_result instead.`**
  * `scriptUrlPattern` was **removed**. Use the `endpoints` option if you need to configure a specific domain for agent script download.
  * The `sealedResult` response type changed in v4. In v3, `sealedResult` was a base64 string. In v4, `sealed_result` is `BinaryOutput | null` and must be serialized (for example, with `base64()`) before using it or sending it to your server.
  * The `products` field has been **completely removed**, as it had no impact on agent behavior anymore. This field does not have any replacement.
* `storageKey` was renamed to `storageKeyPrefix` and it does not add a leading underscore any more. See [`storageKey migration guide`](/reference/migrating-from-v3-to-v4#migrate-storagekey-to-storagekeyprefix) below for details. **Be careful as this might have negative impact on accuracy if set up incorrectly.**
* The `endpoint` was renamed to `endpoints` and is now a string by default (instead of an array).
  * By default, the `endpoints` option accepts a string but multiple strings can be supplied as an array if fallbacks are required.
  * Fingerprint's default endpoints are included as a default fallback, if you don't want to use the fallback endpoints use the `Fingerprint.withoutDefault()` helper.
* The NPM package name changed from `@fingerprintjs/fingerprintjs-pro` to `@fingerprint/agent`
* The main namespace has changed from `FingerprintJS` to `Fingerprint`.
* Stopped supporting the IIFE installation method (NPM and ESM installation methods remain available).
* Our agent now uses the [Web Workers API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) to improve latency and accuracy. This requires you to set up appropriate CSP rules to enable Web Worker code download and execution.
* Added built-in caching options with the `cache` parameter along with predefined values specified in the `CacheConfig` type. This replaces the need for the [SPA wrapper library](/docs/generic-js-agent-wrapper-for-spas).
* Revamped error handling from a fixed enum to more descriptive error messages that contain the resolution steps to get rid of the error.
* The `load()` method was renamed to `start()` and is now synchronous (does not return a promise).
* The agent code is compiled to the ES2018 standard (JS features like `let`, `const` and `async` work without transpiling). This reduces the code size.

# Migration steps

The following section outlines the necessary migration steps to complete the transition from the previous to the current version. The steps are in no specific order and some of them depend on specific installation methods and utilized configuration options.

## Upgrade the MAJOR package version

### IIFE

IIFE installation method has been completely deprecated in `4.0.0`. See the migration guide from IIFE to other supported installation methods below.

### NPM

If you used the NPM installation method, you have to first change the package name from `@fingerprintjs/fingerprintjs-pro` to `@fingerprint/agent`

<CodeGroup>
  ```bash NPM theme={"theme":"github-dark-dimmed"}
  npm remove @fingerprintjs/fingerprintjs-pro
  npm install @fingerprint/agent
  ```
</CodeGroup>

And then change the import statements in the code

<CodeGroup>
  ```typescript Change imports theme={"theme":"github-dark-dimmed"}
  import * as FingerprintJS from '@fingerprintjs/fingerprintjs-pro' // [!code --]
  import * as Fingerprint from '@fingerprint/agent' // [!code ++]

  const fpPromise = FingerprintJS.load({ ... }) // [!code --]
  const fp = Fingerprint.start({ ... }) // [!code ++]

  // ...
  ```
</CodeGroup>

### ESM

If you used the ESM installation method, you need to update the URL string from `v3` to `v4`

<CodeGroup>
  ```javascript Dynamic import theme={"theme":"github-dark-dimmed"}
  // [!code --:3]
  import('https://fpjscdn.net/v3/PUBLIC_API_KEY').then((FingerprintJS) => {
    FingerprintJS.load({ ... });
  });
  const Fingerprint = await import('https://fpjscdn.net/v4/PUBLIC_API_KEY'); // [!code ++]
  const agent = Fingerprint.start({ ... }); // [!code ++]
  // ...
  ```

  ```html Module theme={"theme":"github-dark-dimmed"}
  <script type="module">
    import * as FingerprintJS from 'https://fpjscdn.net/v3/PUBLIC_API_KEY' // [!code --]
    import * as Fingerprint from 'https://fpjscdn.net/v4/PUBLIC_API_KEY' // [!code ++]

    FingerprintJS. ... // [!code --]
    Fingerprint. ... // [!code ++]
  </script>
  ```
</CodeGroup>

## Change the namespace from `FingerprintJS` to `Fingerprint`

The `FingerprintJS` namespace was renamed to `Fingerprint` to represent our current brand. The `FingerprintJS` name is supposed to exclusively represent the original open-source `@fingerprintjs/fingerprintjs` project and not the paid product this documentation focuses on.

<CodeGroup>
  ```html FingerprintJS to Fingerprint theme={"theme":"github-dark-dimmed"}
  <script type="module">
    import * as FingerprintJS from 'https://fpjscdn.net/v3/PUBLIC_API_KEY' // [!code --]
    import * as Fingerprint from 'https://fpjscdn.net/v4/PUBLIC_API_KEY' // [!code ++]

    FingerprintJS. ... // [!code --]
    Fingerprint. ... // [!code ++]
  </script>
  ```
</CodeGroup>

## Set up new CSP policy rules

If you send the `Content-Security-Policy` header, you have to update it with new rules to support our new implementation that is using WebWorkers under the hood. The following header values should be added in case of using a Custom Subdomain/Proxy or our default endpoint respectively (in case the `endpoints` parameter was not used).

<CodeGroup>
  ```txt Custom Subdomain/Proxy theme={"theme":"github-dark-dimmed"}
  script-src <your custom subdomain>;
  connect-src <your custom subdomain>;
  worker-src blob:;
  ```

  ```txt Default endpoint (CDN/ESM) theme={"theme":"github-dark-dimmed"}
  script-src https://fpjscdn.net;
  connect-src https://api.fpjs.io https://*.api.fpjs.io;
  worker-src blob:;
  ```

  ```txt Default endpoint (NPM) theme={"theme":"github-dark-dimmed"}
  script-src https://fpnpmcdn.net;
  connect-src https://api.fpjs.io https://*.api.fpjs.io;
  worker-src blob:;
  ```
</CodeGroup>

## Migrate from the IIFE installation method to NPM or ESM

The IIFE installation has been completely deprecated and we recommend migrating to the ESM or NPM installation methods.

<CodeGroup>
  ```html IIFE to ESM theme={"theme":"github-dark-dimmed"}
  <!-- [!code --:4] -->
  <script src="https://fpjscdn.net/v3/PUBLIC_API_KEY/iife.min.js"></script>
  <script>
    FingerprintJS. ...
  </script>
  <!-- [!code ++:4] -->
  <script type="module">
    import * as Fingerprint from 'https://fpjscdn.net/v4/PUBLIC_API_KEY'
    Fingerprint. ...
  </script>
  ```

  ```html IIFE to Dynamic Import theme={"theme":"github-dark-dimmed"}
  <!-- [!code --:4] -->
  <script src="https://fpjscdn.net/v3/PUBLIC_API_KEY/iife.min.js"></script>
  <script>
    // FingerprintJS...
  </script>
  <!-- [!code ++:4] -->
  <script type="module">
    const fp = await import('https://fpjscdn.net/v4/PUBLIC_API_KEY'); // [!code ++]
    const agent = fp.start({});
  </script>
  ```

  ```html IIFE to NPM theme={"theme":"github-dark-dimmed"}
  <!-- [!code --:4] -->
  <script src="https://fpjscdn.net/v3/PUBLIC_API_KEY/iife.min.js"></script>
  <script>
    FingerprintJS. ...
  </script>
  <!-- [!code ++:3] -->
  // main.js
  import * as Fingerprint from '@fingerprint/agent'
  Fingerprint. ...
  ```
</CodeGroup>

## Migrate `storageKey` to `storageKeyPrefix`

If you used the `storageKey` option in v3, you have to migrate to the new `storageKeyPrefix` option and add a trailing underscore as that is not added automatically any more.

<CodeGroup>
  ```javascript storageKey to storageKeyPrefix theme={"theme":"github-dark-dimmed"}
  FingerprintJS.load({ // [!code --]
  Fingerprint.start({ // [!code ++]
      // other start/load options
  	storageKey: '__fp', // [!code --]
  	storageKeyPrefix: '__fp_', // An underscore has to be added to prevent negative accuracy impact losing cookies // [!code ++]
  })
  ```
</CodeGroup>

## Use `endpoints` instead of `tlsEndpoint`

The `tlsEndpoint` option (along with `disableTls` were completely deprecated in favor of the new `endpoints` option. If you used the `tlsEndpoint` option to set up a specific domain for the TLS endpoint specifically, you can now use the `endpoints` option instead.

<CodeGroup>
  ```typescript v3 theme={"theme":"github-dark-dimmed"}
  FingerprintJS.load({
    tlsEndpoint: 'https://mytls.fp.mydomain.com',
  });
  ```

  ```typescript v4 theme={"theme":"github-dark-dimmed"}
  Fingerprint.start({
    endpoints: 'https://fp.mydomain.com', // no need for a separate subdomain in v4 as the tlsEndpoint was deprecated completely
  });
  ```
</CodeGroup>

## Use `endpoints` instead of `scriptUrlPattern`

`scriptUrlPattern` was historically used for two different purposes

* To set up a custom subdomain for the agent script download (CDN installation).
* To set up a proxy integration using a first party domain, using special placeholders to tell the agent how to construct the final URL.

Both of those cases fall under the ad blocker protection measures and are now folded over to the `endpoints` option which follows certain path conventions.

<CodeGroup>
  ```typescript scriptUrlPattern to endpoints theme={"theme":"github-dark-dimmed"}
  const fpPromise = Fingerprint.load({ // [!code --]
  const fp = Fingerprint.start({ // [!code ++]
      // other start/load options
    scriptUrlPattern: ['/proxy_v3/cdn/v<version>/<apiKey>/loader_v<loaderVersion>.js', FingerprintJS.defaultScriptUrlPattern], // [!code --]
    endpoints: [ // [!code ++]
       'https://proxy1.mydomain.com', // default proxy // [!code ++]
       'https://proxy2.mydomain.com', // fallback proxy // [!code ++]
    ], // [!code ++]
  })
  ```
</CodeGroup>

## Use `sealed_result` instead of `sealedResult` and serialize it

In v3, `sealedResult` is a base64 string. In v4, `sealed_result` is `BinaryOutput | null`. Before using the result or sending it to your backend, you need to serialize it with one of the `BinaryOutput` methods:

* `base64(): string`
* `byteArray(): Uint8Array`
* `blob(): Blob`

[Sealed results](/docs/sealed-client-results) must be enabled, otherwise `sealed_result` is `null`.

```javascript with sealed_result (v4) theme={"theme":"github-dark-dimmed"}
const result = await fp.get();

console.log(result.sealedResult); // [!code --]
console.log(result.sealed_result?.base64()); // [!code ++]
```

## Remove `products`, `extendedResult`, `tlsEndpoint` and `tlsDisabled` from options

All of `products`, `extendedResult`, `tlsEndpoint` and `tlsDisabled` were removed from the `get()` and `start()` calls completely. The options need to be removed from the code to prevent errors.
The agent `get()` method now returns only a minimal amount of data to ensure tighter security on the client side. Furthermore, all non-essential fields were now removed but still remain available through the encrypted `sealed_result` response field.

<CodeGroup>
  ```javascript Remove deprecated parameters from start() and get() theme={"theme":"github-dark-dimmed"}
  import * as FingerprintJS from '@fingerprintjs/fingerprintjs-pro' // [!code --]
  import * as Fingerprint from '@fingerprint/agent' // [!code ++]

  const fpPromise = FingerprintJS.load({ // [!code --]
  const fp = Fingerprint.start({ // [!code ++]
    apiKey: 'asdfghjkl',
    region: 'eu',
    tlsEndpoint: 'https://tls.fp.mydomain.com', // [!code --]
    tlsDisabled: true // [!code --]
  })

  const result = await fp.get({
    products: [], // [!code --]
    extendedResult: true // [!code --]
  })
  ```
</CodeGroup>

## Make the start() method call synchronous

The `load()` method in the previous (3.x) version returned a Promise that had to be resolved before getting the agent instance. The new `start()` method is now synchronous and returns the agent instance immediately.

<CodeGroup>
  ```typescript Promise to Synchronous theme={"theme":"github-dark-dimmed"}
  import * as FingerprintJS from '@fingerprintjs/fingerprintjs-pro' // [!code --]
  import * as Fingerprint from '@fingerprint/agent' // [!code ++]

  const fpPromise = FingerprintJS.load({ // load options }) // [!code --]
  const fp = Fingerprint.start({ // start options }) // [!code ++]
  fpPromise.then(fp => { // [!code --]
      const result = await fp.get()
  })

  // ...
  ```
</CodeGroup>

## Change the error handling approach

In v3, errors were exposed as named literals (e.g., `FingerprintJS.ERROR_RATE_LIMIT`), and it was necessary to filter specific errors by their respective string values. This made it impossible to change/update the actual message which should be designed to help resolving the errors in the first place.

The current version does not expose any string literals in an enum and the error type is decided by including a `code` field in the `error` JSON response instead.

<CodeGroup>
  ```typescript v3 vs v4 theme={"theme":"github-dark-dimmed"}
    try {
    	// The general code above...
    } catch (error) {
  	if (error.message === FingerprintJS.ERROR_RATE_LIMIT) { // [!code --]
  	if (error.code === 'too_many_requests') { // [!code ++]
    		console.error('Too many requests, try again later')
  		// The error may contain a detailed message with possible resolution steps in error.message // [!code ++]
    	} else {
  		console.error('Unexpected error. Id for debugging:', error.requestId) // [!code --]
  		console.error('Unexpected error. Id for debugging:', error.event_id) // [!code ++]
    	}
    }
  ```
</CodeGroup>

[angular-v3]: https://github.com/fingerprintjs/angular/releases/tag/%40fingerprint%2Fangular%403.0.0
