Skip to main content
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.
Support for JavaScript agent v4 in SDKs and proxy integrations coming soonWe are actively working on adding support for agent v4 to our client libraries (React, Vue, Angular, etc) and proxy integrations. If you are using a library or a proxy integration that does not yet support agent v4, please postpone your migration until support is available.

What’s new

  • The new agent matches our recently released Server API v4 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 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 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/fingerprint-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 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 specific in the CacheConfig type.
  • 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/fingerprint-pro to @fingerprint/agent
npm remove @fingerprintjs/fingerprintjs-pro
npm install @fingerprint/agent
And then change the import statements in the code
import * as Fingerprint from '@fingerprintjs/fingerprintjs-pro'
import * as Fingerprint from '@fingerprint/agent'

const fpPromise = FingerprintJS.load({...}) 
const fp = Fingerprint.start({...}) 

// ...

ESM

If you used the ESM installation method, you need to update the URL string from v3 to v4
import('https://fpjscdn.net/v3/your-public-api-key').then(FingerprintJS => { 
}) 
const fp = await import('https://fpjscdn.net/v4/your-public-api-key') 
const agent = fp.start({ 
}) 
  // ...

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.
<script type="module">
import * as FingerprintJS from 'https://fpjscdn.net/v3/your-public-api-key'
import * as Fingerprint from 'https://fpjscdn.net/v4/your-public-api-key'
  
FingerprintJS. ...
Fingerprint. ...
</script>

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).
script-src <your custom subdomain>;
connect-src <your custom subdomain>;
worker-src blob:;

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.
<script src="https://fpjscdn.net/v3/your-public-api-key/iife.min.js"></script> 
<script type="module"> 
import * as Fingerprint from 'https://fpjscdn.net/v4/your-public-api-key'

FingerprintJS. ...
Fingerprint. ...
</script>

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.
FingerprintJS.load({ 
Fingerprint.start({ 
    // other start/load options
	storageKey: '__fp',
	storageKeyPrefix: '__fp_', // An underscore has to be added to prevent negative accuracy impact losing cookies
})

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.
FingerprintJS.load({
  tlsEndpoint: 'https://mytls.fp.mydomain.com'
})

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.
const fpPromise = Fingerprint.load({ 
const fp = Fingerprint.start({ 
    // other start/load options
  scriptUrlPattern: ['/proxy_v3/cdn/v<version>/<apiKey>/loader_v<loaderVersion>.js', FingerprintJS.defaultScriptUrlPattern],
  endpoints: [ 
     'https://proxy1.mydomain.com', // default proxy
     'https://proxy2.mydomain.com', // fallback proxy
  ],
})

Use sealed_result instead of extendedResult option

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.
const result = await fp.get({ 
  extendedResult: true
})

console.log(result) // contains extended information

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.
import * as Fingerprint from '@fingerprintjs/fingerprint-pro'
import * as Fingerprint from '@fingerprint/agent'

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

  const result = await fp.get({ 
   products: [],
   extendedResult: true
})

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.
import * as Fingerprint from '@fingerprintjs/fingerprintjs-pro'
import * as Fingerprint from '@fingerprint/agent'

const fpPromise = FingerprintJS.load({ // load options })
const fp = Fingerprint.start({ // start options })
fpPromise.then(fp => { 
    const result = await fp.get()
})

// ...

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.
  try {
  	// The general code above...
  } catch (error) {
	if (error.message === FingerprintJS.ERROR_RATE_LIMIT) { 
	if (error.code === 'too_many_requests') { 
  		console.error('Too many requests, try again later')
		// The error may contain a detailed message with possible resolution steps in error.message
  	} else {
		console.error('Unexpected error. Id for debugging:', error.requestId) 
		console.error('Unexpected error. Id for debugging:', error.event_id) 
  	}
  }