From Fingerprint v2

Update from Fingerprint version 2 to version 3

The JS agent has several changes compared to the previous version. Server API, webhooks and other integrations have not changed.

Browser support

Internet Explorer 10 is no longer supported in v3. Some old browsers like Internet Explorer 11 and Android Browser 4.1 require a Promise polyfill. See the browser support guide to get a list of the supported browsers and learn how to use Fingerprint in old browsers.



Skip this section if you installed the v2 of the JS agent via NPM.
The is no longer supported, use instead.
Here is the new CDN URL:<<browserToken>>/iife.min.js.

The global variables fp and fpLayer were replaced with FingerprintJS which provides the same API as the NPM version. Instead of passing configuration parameters to fp('config', ...), you should pass them to FingerprintJS.load({ ... }).
Example before:

    window.fpLayer = window.fpLayer || [];
    function fp() { fpLayer.push(arguments); }
    fp('config', 'client', '<<browserToken>>');
    fp('config', 'endpoint', 'your-endpoint'); // If you have a custom subdomain
    fp('config', 'loaded', function (fpAgent) {
      // Your code that uses the agent
  <script async src=""></script>

Example after:

    // Initialize the agent at application startup.
    const fpPromise = import('<<browserToken>>')
      .then(FingerprintJS => FingerprintJS.load({
        endpoint: 'your-endpoint' // If you have a custom subdomain

    // Get the visitor identifier when you need it.
    fpPromise.then(fpAgent => {
      // Your code that uses the agent

You aren't required to pass the public API key to the load function because the key is a part of the URL.


Skip this section if you installed the v2 of the JavaScript agent via CDN. Replace the old NPM package with the new one:

npm remove @fp-pro/client
npm install @fingerprintjs/fingerprintjs-pro
yarn remove @fp-pro/client
yarn add @fingerprintjs/fingerprintjs-pro

Then update the import code. Change the package name and import FP as a default export. Example:

- import { FP } from '@fp-pro/client'
+ import FP from '@fingerprintjs/fingerprintjs-pro'

The exported constants are available as default export properties and as individual exports:

import FP, { ERROR_CLIENT_TIMEOUT } from '@fingerprintjs/fingerprintjs-pro'


This section describes what was changed in the configuration parameters that are passed to the FP.load() method or to fp('config', ...).


Rename the client parameter to apiKey.

const fp = await FP.load({
- client: '<<browserToken>>'
+ apiKey: '<<browserToken>>'

You may remove the parameter completely if you use the CDN installation method because the key is a part of the CDN URL.


In v3, the parameter is optional for NPM, so you can remove region: 'us'.


Remove this parameter, it is not used anymore. The best cookie domain is detected automatically.


The parameter is removed. Send explicitly when the agent loads. Call fp.get() right after the agent loads:

  const fpPromise = import('<<browserToken>>')
    .then(FingerprintJS => FingerprintJS.load())
	  .then(fp => fp.get()); // Automatic sending when the agent is ready


The parameter is removed. Put your "loaded" handling code right after the agent loads.

  // Initialize the agent at application startup.
  const fpPromise = import('<<browserToken>>')
    .then(FingerprintJS => FingerprintJS.load())

  fpPromise.then(fp => {
    // Put the code that handles "loaded" event here


Rename the parameter to storageKey. It affects local storage too.


Rename the parameter to delayFallback.

Sending data

Rename the .send() method to .get().

const fp = await FP.load()
- await fp.send(options)
+ await fp.get(options)


Rename the parameter to extendedResult.

await fp.get({
- callbackData: true
+ extendedResult: true


Remove the parameter because it is not supported.

await fp.get({
- ip: 'city'

Receiving data

Some results that were resolved in v2 are rejected in v3 and vice-versa. The shift has been done to simplify resolved and rejected value types. See the expected errors table to learn the cases that lead to errors. Generally speaking, error are thrown only when your attention is required.

The .get() method returns a promise that is resolved with an object of a single predictable format. The format is similar to the visitor data format from v2. The differences are described below.


If a visitor can't be identified, the visitorId field value is an empty string instead of 'n/a'. The rest of the result object will have the same type (as for an identified visitor) in this case.

- import { NotAvailable } from '@fp-pro/client'
- if (result.visitorId === NotAvailable) {
+ if (!result.visitorId) {
    console.log('The visitor can not be identified')


The tag field was removed from the .get() method’s response for simplicity. Previously, this value was sent and received without ever changing.

const optionsTag = { userId: 123, coupon: 'FOOBAR' }
const result = await fp.get({ tag: optionsTag })
- const resultTag = result.tag
+ const resultTag = optionsTag


The property is replaced with the bot field that has the probability subfield.

// Visitor data example:
    visitorId: 'qwerty12345',
-   botProbability: 1,
+   bot: {
+     probability: 1
+   },
    // ...

When the visitor isn't suspected to be a bot, the bot field is undefined.

The bot detection feature of JS agent is deprecated, we're working on a new product for bot detection. Please contact support for more details.

Error handling

The JavaScript agent .get() method returns a promise which will be rejected in the case of an error. The JavaScript agent provides constants for every expected error. To see a list of common error messages, click here.

    .then(FingerprintJS => {
      // And many more
import FingerprintJS from '@fingerprintjs/fingerprintjs-pro'
// or
import * as FingerprintJS from '@fingerprintjs/fingerprintjs-pro'

// And many more

When you catch an error, check the message:

try {
  await fp.get()
} catch (error) {
  if (error.message === FingerprintJS.ERROR_CLIENT_TIMEOUT) {
    // ...
  // ...

Search bots

In v2 the .send() method promise was rejected in case of a search bot. In v3 the promise is resolved with a full featured result object. Also the result has the field equal to true. Change your search bot checking code:

- try {
-   const result = await fp.get()
+   const result = await fp.get({ extendedResult: true })
- } catch (error) {
-   if (error.reason === 'Not available for crawl bots') {
+   if (!result.visitorId && && {
      console.log("It's a crawl bot")
- }

Missing User-Agent header

V3 rejects the .get() (ex .send()) method promise when a visitor accesses a site without a user-agent header because a missing user-agent header is a strong sign of a bot.