JavaScript agent

Fingerprint Pro JavaScript browser SDK. Not supported in Node.js, requires web browser to work.

The client-side agent is a high-performance JavaScript agent that collects multiple device and browser signals and sends them to the Fingerprint Pro API for processing, identification and bot detection.

πŸ“˜

Integrations and SDKs

For a list of supported integrations, please visit this page: https://fingerprint.com/integrations/
For SDKs and framework libraries, go to this page: https://fingerprint.com/sdk-libraries/

πŸ“˜

If you want to use Bot Detection, reach our support at [email protected]. Browser Identification is available by default. Bot Detection works only with JS agent version 3.7.0 or newer. Check your version and update if needed.

Installing the agent + quick usage examples

There are various ways to install the agent. No matter what you choose, the API will be the same.

CDN

This is the easiest way to start. It's also known as ESM import. Add the following HTML code to your pages:

<script>
  // Initialize the agent once at web application startup.
  // Alternatively initialize as early on the page as possible.
  const fpPromise = import('https://fpjscdn.net/v3/<<browserToken>>')
    .then(FingerprintJS => FingerprintJS.load())

  // Analyze the visitor when necessary.
  fpPromise
    .then(fp => fp.get())
    .then(result => console.log(result.requestId, result.visitorId))
</script>

Put your public API key to the URL (right after /v3/). You can get an API key at dashboard.fingerprint.com. An example script URL where the key is qwerty: https://fpjscdn.net/v3/qwerty.

Alternatively, you can use a synchronous code that pauses the other scripts during loading and therefore is not recommended:

<script src="https://fpjscdn.net/v3/<<browserToken>>/iife.min.js"></script>
<script>
  // Initialize the agent at application startup.
  var fpPromise = FingerprintJS.load()

  // Analyze the visitor when necessary.
  fpPromise
    .then(function (fp) { return fp.get() })
    .then(result => console.log(result.requestId, result.visitorId))
</script>

UMD installation method designed for module loaders like RequireJS is also available:

require(
  ['https://fpjscdn.net/v3/<<browserToken>>/umd.min.js'],
  FingerprintJS => {
    // Initialize an agent.
    const fpPromise = FingerprintJS.load()

    // Analyze the visitor when necessary.
    fpPromise
      .then(fp => fp.get())
      .then(result => console.log(result.requestId, result.visitorId))
  }
)

🚧

We don't recommend copying these JS files from fpjscdn.net to your codebase because you may miss critical updates. If you absolutely must host all JavaScript resources yourself, please reach our support at [email protected] for a solution.

NPM

First install the agent NPM package:

npm install @fingerprintjs/fingerprintjs-pro
yarn add @fingerprintjs/fingerprintjs-pro

Then import the package into your code:

import * as FingerprintJS from '@fingerprintjs/fingerprintjs-pro'

// Initialize an agent at application startup.
const fpPromise = FingerprintJS.load({ apiKey: '<<browserToken>>' })

// Analyze the visitor when necessary.
fpPromise
  .then(fp => fp.get())
  .then(result => console.log(result.requestId, result.visitorId))

We recommend typing import * as FingerprintJS from instead of import FingerprintJS from because the * variant allows excluding the unused code from your application by tree-shaking.

The NPM package comes with a TypeScript declaration for better development experience. The package can be used with various module bundlers such as Webpack, Rollup.js or Browserify. If you have a TypeScript error that occurs in the FingerprintJS file, see the TypeScript support section.

Alternatively, you can use the legacy CommonJS standard:

const FingerprintJS = require('@fingerprintjs/fingerprintjs-pro')

// Initialize an agent at application startup.
const fpPromise = FingerprintJS.load({ apiKey: '<<browserToken>>' })

// Analyze the visitor when necessary.
fpPromise
  .then(fp => fp.get())
  .then(result => console.log(result.requestId, result.visitorId))

Usage in detail: agent initialization

After you install the agent, add the code that creates an agent instance when your page or application starts:

const fpPromise = FingerprintJS.load({ /* ... */ })

// fpPromise will resolve with `fp` object that you can use to call `fp.get()`

load() returns a promise that resolves to an agent instance. See the Analyzing the visitor section to learn how to use the agent instance.

load() options

To configure the agent, pass parameters into the β€œload” function.

apiKey

Required: yes for NPM installation
Type: string
Used by products: all

Your public API key to authenticate the agent with the server API. You can get one at dashboard.fingerprint.com. If you login into this documentation portal via dashboard, you will be able to see your personal API key in the example below.

Example usage:

const fpPromise = FingerprintJS.load({ apiKey: "<<browserToken>>" })

The parameter is required for the NPM installation method and optional for the CDN (where the key is a part of the URL).

region

Required: no
Default: (depends on the API key)
Available values: us, eu and ap
Used by products: all

The region of your application. The parameter is fully optional because JS agent detects the regions automatically using the provided API key. Nevertheless, we recommend always specifying the parameter. Otherwise the default region us.

The parameter is ignored when both the endpoint and tlsEndpoint parameters are used.

Example:

const fpPromise = FingerprintJS.load({ region: 'eu' })

endpoint

Required: no
Default: (depends on the region)
Type: string | string[]
Used by products: all

This parameter should only be used with the Custom subdomain or Cloudflare Integration. Specify your custom endpoint URL here.

Multiple endpoints can be set with an array. JavaScript agent will try to send the request with the first endpoint, and if the request fails, retry the request with the second endpoint and so on. Use FingerprintJS.defaultEndpoint to fallback to the default endpoint.

import * as FingerprintJS from '@fingerprintjs/fingerprintjs-pro'

const fpPromise = FingerprintJS.load({
  apiKey: 'your-public-api-key',
  endpoint: [
    'https://fp.example.com', // This endpoint will be used primarily
    FingerprintJS.defaultEndpoint, // The default endpoint will be used if the primary fails
  ],
})

JS agent will throw an error if an empty array is given.

tlsEndpoint

Required: no
Default: (depends on the region)
Type: string | string[]
Since: v3.1.0
Used by products: identification

Your custom TLS endpoint URL address.

Multiple endpoints can be set with an array. JavaScript agent will try to send the request with the first endpoint, and if the request fails, retry the request with the second endpoint and so on. Use FingerprintJS.defaultTlsEndpoint to fallback to the default endpoint.

disableTls

Required: no
Default: false
Type: string
Since: v3.4.0
Used by products: identification

Set it to true to disable the extra TLS request. This is not recommended as it will negatively affect your identification accuracy.

storageKey

Required: no
Default: '_vid'
Type: string
Used by products: identification

Name of key to store data in visitor browsers. The data is stored in cookies and local storage. You shouldn't change this parameter once your code runs in production because a change will cause the data in visitor browsers to be purged which will decrease the identification accuracy.

scriptUrlPattern

Only for NPM installation
Required: no
Default: 'https://fpnpmcdn.net/v<version>/<apiKey>/loader_v<loaderVersion>.js'
Type: string | string[]
Since: v3.6.0
Used by products: all

This parameter should only be used with the Cloudflare Integration. Pattern of the URL from where JS agent downloads the up-to-date self JS code in runtime. By default JS agent downloads the code from our CDN. JS agent replaces the following substrings:

  • <version> β€” the major version of JS agent;
  • <apiKey> β€” the public key set via the apiKey parameter;
  • <loaderVersion> β€” the exact version of the @fingerprintjs/fingerprintjs-pro package.

Multiple endpoints can be set with an array. JavaScript agent will try to download the code from the first URL, and if it fails, retry to download with the second URL and so on. Use FingerprintJS.defaultScriptUrlPattern to fallback to the default URL.

import * as FingerprintJS from '@fingerprintjs/fingerprintjs-pro'

const fpPromise = FingerprintJS.load({
  apiKey: 'your-public-api-key',
  scriptUrlPattern: [
    // This endpoint will be used primarily
    '/myproxy/v<version>/<apiKey>/loader_v<loaderVersion>.js',

    // The default endpoint will be used if the primary fails
    FingerprintJS.defaultScriptUrlPattern,
  ],
})

Analyzing the visitor

Once an agent instance is initialized, you can start analyzing the visitor. The analysis can involve identification or bot detection, or both depending on your application settings. You are free to analyze at any moment of time. You can configure Fingerprint Pro to receive the visitor data in the browser, on the server (via a webhook), or both.

Below are a few examples of different approaches for analyzing.

Automatic mode

In many cases you will use the automatic mode, because it's the simplest way to get started. The agent will get the data on every page load. You don't need to do anything else. Just add the call fp.get() as soon as the agent is loaded:

const fpPromise = FingerprintJS.load(/* ... */)
const fp = await fpPromise
const result = await fp.get()
console.log(result.requestId)

You can use both async/await and promises to get the visitor data. Example of using promises:

const fpPromise = FingerprintJS.load(/* ... */)
fpPromise
  .then(fp => fp.get())
  .then(result => console.log(result.requestId))

When get() is called, a FingerprintJS server will send a webhook request to your server. Also you can query the Server API to retrieve the visitor data using the requestId value.

Manual mode

Manual mode provides more granular control over when the analyses are performed. When you actually need to get visitor data (on a sign up event for example), call the .get() method to get the data.

const fpPromise = FingerprintJS.load(/* ... */)

document.querySelector('#ad').addEventListener('click', async () => {
  const fp = await fpPromise
  const result = await fp.get()
  console.log(result.requestId)
})
const fpPromise = FingerprintJS.load(/* ... */)

document.querySelector('#ad').addEventListener('click', () => {
  fpPromise
    .then(fp => fp.get())
    .then(result => console.log(result.visitorId))
})

Search bots

The PRO API recognizes most well-known search bots (Google, Bing, Yahoo, Baidu, DuckDuckGo, and others) and treats them differently. Whenever a page is loaded by a search bot, an analysis event is processed server-side, but search bot requests are not billed by us.

get() options

tag

Required: no
Default: undefined
Type: any JSON-encodeable value
Constraint: the size must not exceed 16KB
Used by products: all

tag is a customer-provided value or an object that will be saved together with the analysis event and will be returned back to you in a webhook message or when you search for the visit in the server API. You may want to use the tag value to be able to associate a visit event with information from your current visitor's web request context or add any other information that is convenient for you.

What values can be used as a tag?
Any value that you need when processing a webhook event or that is useful when searching for visits in our server API. Scalar, string or object values can be sent. For example you can pass a myCustomId as a tag and then get this myCustomId back in the webhook, associated with a visitorId.

Examples of using the tag option:

// simple, scalar values
const myCustomId = 2718281828
fp.get({ tag: myCustomId })
// or a string value
const requestType = "signup"
fp.get({ tag: requestType })

// Example of sending and receiving the tag value
fp.get({ tag: myCustomId })
// Webhook request
{
  "visitorId": "nTxJ28Gt4CegeAwdWELL",
  "tag": { "tag": 2718281828 },
  // ...
}
// Note that tags are always objects, even when you use
// a regular scalar value. 
// If you provide a scalar value, it will be converted to an object
// with `tag` attribute.
// You can also use a JavaScript object as a tag value 
// and it will be returned back to you in a webhook.
// 
// NOTE: nested objects are not supported in tag objects.
const requestMetadata = {
  myCustomId: 2718281828, 
  requestType: "signup"
}
// Making an API call and receiving a response via a webhook request
fp.get({ tag: requestMetadata })
// Webhook request
{
  "visitorId": "nTxJ28Gt4CegeAwdWELL", 
  "tag": { "myCustomId": 2718281828, "requestType": "signup" },
  // ...
}

linkedId

Required: no
Default: undefined
Type: string
Constraint: the number of characters must not exceed 256
Used by products: identification

linkedId is a way of linking current analysis event with a custom identifier. This will allow you to filter visit information when using the Server API

Some examples of how you can use the linkedId:

  1. Link your website userId with a FingerprintJS visitorId to be able to analyze this data.
  2. Link your e-commerce orderId with a FingerprintJS visitorId to be able to see the orders a visitor made.
  3. Link a survey ID with a visitorId to ensure that the same visitor does not participate in a single survey multiple times.
  4. Limit one visitor per item or one visitor per discount coupon.
// Making an API call
// Sending a linkedId value is helpful to filter by this value via server API
var orderId = 3936532456
fp.get({ linkedId: orderId })
// linkedId will be saved with this event and will be available to be queried later.

A linkedId looks similar to tag. When should you use each?
A tag is an object that is "passed-through" and sent back to your webhook endpoint. A tag can contain an arbitrary number of attributes of any type (except for nested objects). You can use tags to store them in your database and use for any purpose. Tag objects are meant to be consumed and processed by you eventually. You can think of a tag object as metadata.
A linkedId is a scalar, string identifier that gets indexed by the Fingerprint platform and can be used to filter visits efficiently. It's a way to create a custom index on your data and use that index to efficiently filter visits when querying them through the Server API. Objects or non-string values are not supported.

extendedResult

Required: no
Default: false
Type: boolean
Used by products: identification

Two types of responses are supported: "default" and "extended". You don't need to pass any parameters to get the "default" response. "Extended" is an extended result format that includes geolocation, incognito mode and other information. It can be requested using the extendedResult: true parameter. See more details about the responses here.

timeout

Required: no
Default: 10000
Type: number
Used by products: all

Controls client-side timeout. Client timeout controls total time (both client-side and server-side) that any analysis event is allowed to run. It doesn't include time when the page is in background (not visible) because browser may suspend the analysis process in background. By default it's 10 seconds. You can control the client-side timeout using timeout configuration key. The timeout option is in milliseconds. Example usage:

// A timeout of 20 seconds
// An example of the client-side timeout handling
try {
  const result = await fp.get({ timeout: 20000 })
  // ...
} catch (error) {
  if (error.message === FingerprintJS.ERROR_CLIENT_TIMEOUT) {
    console.log("A timeout of 20 seconds exceeded")
  }
}

products

Required: no
Default: (depends on the API key)
Type: string[]
Since: v3.7.0
Used by products: all

You can enable or disable Fingerprint products that will handle this request. You won't be billed for the disabled products. An example of enabling only identification:

await fp.get({ products: ['identification'] })

The possible array items:

  • 'identification' β€” Browser Identification
  • 'botd' β€” Bot Detection

Enabled products are configured on your application via our support. Once a product is enabled, you can decide if you want to run it on a specific page or in a certain situation.
For example, you can contact support so that two products are enabled: "identification" and "botd".
Then you can run only identification on the "submit order" page, run only botd on the "add comment" page and run both identification and botd on "create account" page. Application configuration of enabled products takes precedence over the client-side products parameter, which can be used to disable certain products in some situations.

If the option is not set, all the products enabled for your application will be run.

get() response

fp.get() returns a promise that resolves to an object. The object format depends on the extendedResult option. The format summary:

await fp.get()
// response:
{
  "requestId": "8nbmT18x79m54PQ0GvPq",
  "visitorId": "2JGu1Z4d2J4IqiyzO3i4",
  "visitorFound": true,
  "confidence": { "score": 0.995 }
}
await fp.get({ extendedResult: true })
// response:
{
  "requestId": "8nbmT18x79m54PQ0GvPq",
  "visitorId": "2JGu1Z4d2J4IqiyzO3i4",
  "visitorFound": true,
  "confidence": { "score": 0.995 },
  "ip": "185.230.125.20",
  "ipLocation": {
    "accuracyRadius": 10,
    "latitude": 47.3925,
    "longitude": 8.4546,
    "postalCode": "8010",
    "timezone": "Europe/Zurich",
    "city": {
      "name": "Zurich"
    },
    "continent": {
      "code": "EU",
      "name": "Europe"
    },
    "country": {
      "code": "CH",
      "name": "Switzerland"
    },
    "subdivisions": [
      {
        "isoCode": "ZH",
        "name": "Zurich"
      }
    ]
  },
  "browserName": "Chrome",
  "browserVersion": "75.0.3770",
  "os": "Mac OS X",
  "osVersion": "10.14.5",
  "device": "Other",
  "incognito": false,
  "firstSeenAt": {
    "global": "2022-03-16T11:26:45.362Z",
    "subscription": "2022-03-16T11:31:01.101Z"
  },
  "lastSeenAt": {
    "global": "2022-03-16T11:28:34.023Z",
    "subscription": null
  }
}

When the identification product is disabled, all the fields except requestId are replaced with default values.

Response fields:

requestId

Required: yes
Type: string

The request identifier which is different for every request. It is available in API to query later. It is a convenient way to get specific identification events in the Server API.

visitorId

Required: yes
Type: string

The browser identifier.

The field will contain an empty string when the visitor can't be identified, for example when it's a search bot. If the identification product is disabled, the value is a dummy value.

visitorFound

Required: yes
Type: boolean

If true, this visitor was found and visited before. If false, this visitor wasn't found and probably didn't visit before.

If the identification product is disabled, the value is a dummy value.

confidence

Required: yes
Type: { score: number, comment?: string }

Represents the probability of accurate identification. The number is between 0 and 1. The higher the number, the higher the chance of the visitor identifier to be true. To learn more about how Fingerprint calculates this value, please go to Understanding your confidence score.

If the identification product is disabled, the value is a dummy value.

zeroTrust

Required: no
Type: { hiddenFields: string[], comment?: string }

See more details in the Zero Trust Mode guide.

incognito

Only when extendedResult is true
Required: yes
Type: boolean

Whether the visitor is in incognito/private mode.

If the identification product is disabled, the value is a dummy value.

browserName

Only when extendedResult is true
Required: yes
Type: string

Browser name. Examples: 'Safari', 'Chrome'.

If the identification product is disabled, the value is a dummy value.

browserVersion

Only when extendedResult is true
Required: yes
Type: string

Browser version. Example: '78.0.3904'.

If the identification product is disabled, the value is a dummy value.

device

Only when extendedResult is true
Required: yes
Type: string

Device. For desktop/laptop devices, the value will be "Other". Example: 'Samsung SM-J330F'.

If the identification product is disabled, the value is a dummy value.

ip

Only when extendedResult is true
Required: yes
Type: string

IP address. Only IPv4 are returned.

If the identification product is disabled, the value is a dummy value.

ipLocation

Only when extendedResult is true
Required: no
Type: object

IP address location. Can be empty for anonymous proxies. The value type:

{
  accuracyRadius?: number
  latitude?: number
  longitude?: number
  timezone?: string
  postalCode?: string
  city?: {
    name: string
  }
  subdivisions?: [
    {
      isoCode: string
      name: string
    }
  ]
  country?: {
    code: string
    name: string
  }
  continent?: {
    code: string
    name: string
  }
}

If the identification product is disabled, the value is absent.

os

Only when extendedResult is true
Required: yes
Type: string

Operating system name. Examples: 'Mac OS X', 'Android'.

If the identification product is disabled, the value is a dummy value.

osVersion

Only when extendedResult is true
Required: yes
Type: string

Operating system version. Examples: '10.13.6'.

firstSeenAt

Only when extendedResult is true
Required: yes
Type: { subscription: string | null, global: string | null }

When the visitor was seen for the first time. See more information here.

If the identification product is disabled, the value is a dummy value.

lastSeenAt

Only when extendedResult is true
Required: yes
Type: { subscription: string | null, global: string | null }

When the visitor was seen previous time. See more information here.

If the identification product is disabled, the value is a dummy value.

Error handling

JavaScript agent's load and get methods return a promise which will be rejected in case of an error. Below table summarizes possible types of errors that can lead to result promise rejections. See detailed information about the errors below the table.

ErrorShort description
FingerprintJS.ERROR_NETWORK_CONNECTIONFingerprintJS server connection error
FingerprintJS.ERROR_NETWORK_ABORTFingerprintJS server request is aborted
FingerprintJS.ERROR_API_KEY_MISSINGPublic API key is missing
FingerprintJS.ERROR_API_KEY_INVALIDPublic API key is invalid
FingerprintJS.ERROR_API_KEY_EXPIREDPublic API key is expired
FingerprintJS.ERROR_BAD_REQUEST_FORMATBad FingerprintJS server request data. Can be caused by wrong TLS endpoint.
FingerprintJS.ERROR_BAD_RESPONSE_FORMATBad FingerprintJS server response data. Can be caused by wrong endpoint.
FingerprintJS.ERROR_GENERAL_SERVER_FAILUREGeneral request server side failure
FingerprintJS.ERROR_CLIENT_TIMEOUTClient side timeout
FingerprintJS.ERROR_SERVER_TIMEOUTServer request times out
FingerprintJS.ERROR_RATE_LIMITRequest rate limit is exceeded
FingerprintJS.ERROR_FORBIDDEN_ORIGINAnalysis request is blocked due to forbidden origin (see request filtering)
FingerprintJS.ERROR_FORBIDDEN_HEADERAnalysis request is blocked due to forbidden HTTP header (see request filtering)
FingerprintJS.ERROR_FORBIDDEN_ENDPOINTAnalysis request is blocked due to forbidden endpoint. Probably because the default endpoint is used instead of the custom subdomain.
FingerprintJS.ERROR_WRONG_REGIONThe region set in the agent options doesn't match the region that was used to create your application
FingerprintJS.ERROR_SUBSCRIPTION_NOT_ACTIVEYour application hasn't been activated in the dashboard or you've reached your free plan limit
FingerprintJS.ERROR_UNSUPPORTED_VERSIONThe JS agent version is not supported
FingerprintJS.ERROR_SCRIPT_LOAD_FAILFailed to load the JS agent code. The error is available only for NPM installation.
FingerprintJS.​ERROR_INSTALLATION_METHOD_RESTRICTEDThe JS agent installation method is not allowed
FingerprintJS.ERROR_CSP_BLOCKBlocked by the Content Security Policy of the page
FingerprintJS.ERROR_INTEGRATION_FAILUREFailure on the integration side

With the exception of ERROR_CLIENT_TIMEOUT, ERROR_NETWORK_CONNECTION ERROR_NETWORK_ABORT, ERROR_SCRIPT_LOAD_FAIL and ERROR_CSP_BLOCK, all the errors described above will include the requestId field. The methods can also throw other unexpected errors, they should be treated as agent bugs.

Error handling example:

const fpPromise = FingerprintJS.load({ /* ... */ })

try {
  const fp = await fpPromise
  const result = await fp.get()
} catch (error) {
  switch (error.message) {
    case FingerprintJS.ERROR_GENERAL_SERVER_FAILURE:
      console.log('Unknown server error. Request id:', error.requestId)
      break
    case FingerprintJS.ERROR_CLIENT_TIMEOUT:
      console.log('Analysis time limit of 10 seconds is exceeded')
      break
    default:
      console.log('Other error')
  }
}
const fpPromise = FingerprintJS.load({ /* ... */ })

fpPromise
  .then(fp => fp.get())
  .then(result => console.log(result.visitorId))
  .catch(error => {
    switch (error.message) {
      case FingerprintJS.ERROR_GENERAL_SERVER_FAILURE:
        console.log('Unknown server error. Request id:', error.requestId)
        break
      case FingerprintJS.ERROR_CLIENT_TIMEOUT:
        console.log('Identification time limit of 10 seconds is exceeded')
        break
      default:
        console.log('Other error')
    }
  })

The connection error occurs when the agent fails to connect to the server API. This can happen during a network outage or if a browser plugin blocks networking requests (e.g. AdBlock).

Timeouts

Two types of timeouts are possible: a server timeout and a client timeout.

Server timeout

The server timeout is fixed at 10 seconds of server-side processing time. If server-side processing exceeds 10 seconds for any reason, the promise will be rejected.

Client timeout

Client timeout controls total time (both client-side and server-side) that any analysis event is allowed to run. By default it's 10 seconds. Note that even if the client-side timeout is exceeded, the server-side request can still be running, its results will be sent you via a webhook if enabled.

Rate limiting

Every application API key has a rate limit. It means that you cannot make more requests per second than your rate limit allows. Free application API keys have a limit of 3 requests/second (with 1 request/s being the default). You cannot increase that rate limit, unless you upgrade to a paid plan.

Paid applications have a limit of 5 requests/second, which you can increase by emailing [email protected]. Whenever that rate limit is exceeded, a request is throttled and a ERROR_RATE_LIMIT error is thrown.

Retrying after an error

JS agent retries automatically in case of failure. If you want agent to make more attempts, increase the timeout. If you want to retry with another endpoint, set an array of endpoints in the JS agent option (see options: scriptUrlPattern, endpoint and tlsEndpoint).

We recommend not to make your own retry mechanism around JS agent because it can introduce a risk of excessive paid API call consumption.

Supported browsers

The JS agent supports all popular browsers. See more details and learn how to run the agent in old browsers in the browser support guide.

TypeScript support

JS agent officially supports TypeScript version 4.0, but may work with newer and older versions of TypeScript. If you face a TypeScript error that occurs in a .d.ts file provided by FingerprintJS (example 1, example 2), consider any of these solutions:

  • Update the TypeScript package in your project to version 4.0 or newer
    npm i [email protected]^4.0
    # or
    yarn add [email protected]^4.0
    
  • Prevent TypeScript from using the library types. To do it, replace
    import ... from '@fingerprintjs/fingerprintjs-pro'
    
    with
    import ... from '@fingerprintjs/fingerprintjs-pro/dist/fp.esm.min'
    
    in your .ts files, and add the following line to a .d.ts file (if there is no such file, create one anywhere with any name):
    declare module '@fingerprintjs/fingerprintjs-pro/dist/fp.esm.min'
    

What’s Next