Library / SDK
fingerprintjs/fingerprintjs avatar
fingerprintjs/fingerprintjs

FingerprintJS: a client-side visitor identifier, and what it cannot do

The most advanced free and open-source browser fingerprinting library

28,528 stars2,629 forksTypeScriptMIT

At a glance

What is it?
FingerprintJS computes a hashed visitor ID from browser attributes in the page itself. It is MIT licensed and free, but the README states its accuracy and spoofing resistance are lower than the commercial server-side version.
Who is it for?
Adopt FingerprintJS when you need a free client-side visitor identifier and can accept that the README itself calls its accuracy significantly lower and its signals spoofable, because everything runs in the browser. Do not adopt it as a fraud-prevention control on its own, and do not expect it to deduplicate visitors whose devices are identical, which the README lists as a job for server-side processing.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem FingerprintJS solves, and who it is actually for

A cookie can be deleted. Local storage can be purged. Private browsing starts empty every time. FingerprintJS exists because a class of applications wants to recognize a returning browser anyway, without asking the visitor to log in and without storing anything on their machine. It queries browser attributes, computes a hash from them, and hands back a string called visitorId. The README makes the central claim plainly: unlike cookies and local storage, the fingerprint stays the same in incognito or private mode and even when browser data is purged.

That makes it useful to two groups. The first is developers who want a lightweight identifier for analytics deduplication, abuse heuristics, or device-bound preferences. The second is teams prototyping fraud logic before they pay for anything. The library is client-side, MIT licensed, and published on npm as @fingerprintjs/fingerprintjs, so the cost of trying it is one dependency and a few lines of code.

The word to hold onto is identifier, not verdict. FingerprintJS returns an ID. It does not tell you whether that ID is suspicious, and it does not tell you whether the browser lied about itself. Those are separate products and separate decisions.

How the visitor identifier is computed in the browser

The architecture is deliberately thin. There is no server component in this package. The agent loads in the page, collects browser attributes, and derives a hash locally. The README describes this as querying browser attributes and computing a hashed visitor identifier from them, which is why the result is available without a network round trip to a Fingerprint endpoint.

The repository layout matches that description. Source lives in src/, the build is produced by rollup.config.ts into dist/, and package.json points main at dist/fp.cjs.js, module at dist/fp.esm.js and types at dist/fp.d.ts. The package declares sideEffects: false and ships only the dist directory, so bundlers can tree-shake it and the published artifact is just build output.

The cost of this design is stated by the project itself. Because fingerprints are generated and processed in the browser, the README says they are vulnerable to spoofing and reverse engineering, and that accuracy is significantly lower than the commercial version. That is not a bug report. It is the direct consequence of running the whole pipeline on infrastructure the visitor controls.

Installing FingerprintJS from npm and reading your first visitorId

The README gives npm as the primary path. Install the package, then load the agent once at application startup and call get() when you actually need the identifier. Keeping the promise at module scope avoids paying the collection cost on every call.

bash
npm install @fingerprintjs/fingerprintjs

The usage example from the README creates the agent promise first and awaits it later inside an async function. The value printed is result.visitorId, the hashed identifier.

js
import FingerprintJS from '@fingerprintjs/fingerprintjs'

// Initialize the agent at application startup.
const fpPromise = FingerprintJS.load();

(async () => {
  // Get the visitor identifier when you need it.
  const fp = await fpPromise
  const result = await fp.get()
  console.log(result.visitorId)
})()

If you prefer not to bundle it, the README shows a CDN import from openfpcdn.io/fingerprintjs/v5, with an explicit warning attached: if you are using an ad blocker or Brave or Firefox, this import will not work, and the README points you to the npm package instead. That warning is the most practical line in the installation section. A CDN-loaded fingerprinting script is exactly the kind of request that privacy tooling blocks, and a blocked script means no identifier at all.

The README also links a live demo at fingerprintjs.github.io/fingerprintjs, where you can open the same page in private mode and observe that the identifier does not change. That is the fastest way to confirm the library behaves as described on your own browser before you write any integration code.

Where FingerprintJS fails: spoofing, identical devices and CDN blocking

Three limitations deserve to be read before the feature list.

First, spoofing. The README states that because fingerprints are generated and processed in the browser, they are vulnerable to spoofing and reverse engineering. Anyone willing to modify the attributes their browser reports can influence the hash. If your threat model includes a motivated attacker with a patched browser, a client-only fingerprint is a weak signal.

Second, identical devices. The README says the commercial platform collects over 100 browser and device signals analyzed server-side alongside network-level data, allowing it to reliably deduplicate visitors with identical devices. The implication for the open source library is direct: two users behind the same hardware and software profile can collapse into one identifier, and the README does not claim otherwise for this package.

Third, delivery. The CDN example carries the project's own warning about ad blockers and Brave or Firefox. If a meaningful share of your traffic runs that tooling, a CDN-based integration silently returns nothing for those visitors, and you will only notice if you instrument the failure.

There is also a category error worth naming. FingerprintJS is the wrong tool if what you need is a fraud decision. It produces an identifier; the README positions bot detection, VPN detection and browser tampering detection under Smart Signals in the commercial platform, not here.

FingerprintJS compared with server-side device intelligence

The obvious alternative is the project's own commercial sibling, Fingerprint Identification, and the README is unusually direct about the split. FingerprintJS is open source, MIT licensed, and client-side. Fingerprint Identification is closed-source and commercial, and it combines client-side signal collection with server-side processing.

That difference in approach changes what each can promise. Server-side processing, per the README, validates that signals have not been tampered with or replayed, and generates a stable visitor identifier that is significantly harder to spoof. It also reaches signals that are entirely invisible to the browser. A purely client-side library has no equivalent mechanism, because there is no trusted component in the pipeline.

The README points to a comparison table in docs/comparison.md for the full breakdown, and notes that upgrading for free unlocks the Fingerprint MCP Server, with a 14-day free trial for Smart Signals. For an engineer choosing between them, the honest framing is: FingerprintJS is the free tier of a commercial product, not an independent competitor to it. If you need tamper validation or device deduplication, the README says the answer lives on the server side, and that code is not in this repository.

Version policy, licence and the cost of staying current

The package is MIT licensed, and the README links docs/licensing.md for the details. MIT is permissive, but the licence covers the library code, not the commercial platform it points to, and nothing in the README suggests the two share terms. That distinction matters if you are evaluating the project for a product where the licence file is reviewed.

Upgrade cost is real here. The README maintains separate migration guides for v4 to v5 and v3 to v5 under docs/migration/, and links a version policy guide covering both the API and visitor identifiers. That second item is the one to read carefully. If a major version is allowed to change how identifiers are computed, a stored visitorId from an older release may not match the same browser after you upgrade, which affects any table where you have persisted those values.

The repository's own scripts show how the maintainers validate releases: test:local runs Karma with a local preset, test:browserstack runs the same suite against BrowserStack, and check:dts type-checks the emitted declaration file. There is also a check:ssr script, and its inline message says the distributive files cannot be used with server-side rendering. If your framework renders on the server, that check exists because someone hit the problem.

On activity: the last push to the repository was on 2026-09-17, and the most recent release in the list is v5.2.0 from 2026-04-07.

Editorial conclusion

Adopt FingerprintJS when you need a free client-side visitor identifier and can accept that the README itself calls its accuracy significantly lower and its signals spoofable, because everything runs in the browser. Do not adopt it as a fraud-prevention control on its own, and do not expect it to deduplicate visitors whose devices are identical, which the README lists as a job for server-side processing. Before you commit, compare the version policy guide against the visitorId you plan to persist, since the README links a compatibility policy for both the API and the identifiers, and check the browser support guide if you still ship to old browsers.

Frequently asked questions

Is FingerprintJS free?

Yes. The README states that FingerprintJS is available under the MIT license, and the package is published on npm as @fingerprintjs/fingerprintjs. The commercial Fingerprint Identification platform it points to is a separate, closed-source product.

What does FingerprintJS actually do?

It is a client-side browser fingerprinting library that queries browser attributes and computes a hashed visitor identifier from them. According to the README, that identifier stays the same in incognito or private mode and even when browser data is purged.

How do I use FingerprintJS?

Install @fingerprintjs/fingerprintjs from npm, call FingerprintJS.load() at application startup, then await fp.get() and read result.visitorId. The README also shows a CDN import from openfpcdn.io/fingerprintjs/v5, but warns it will not work with ad blockers or Brave and Firefox.

What are free alternatives to FingerprintJS?

The README does not name any open source alternative. It only compares FingerprintJS with the company's own commercial Fingerprint Identification platform, which it describes as closed-source and paid, so the material cannot answer this beyond that comparison.

What is the difference between FingerprintJS and Fingerprint Pro?

FingerprintJS runs entirely in the browser and is MIT licensed; the README says its accuracy is significantly lower than the commercial version and that its fingerprints are vulnerable to spoofing. Fingerprint Identification, the commercial platform, combines client-side collection with server-side processing and is closed-source.

Why do I get a fingerprintjs is not defined error?

The README does not document this error, so the material cannot explain it. The documented failure mode is different: the CDN import will not work if an ad blocker or Brave or Firefox is in use, and the README recommends the npm package in that case.

Official sources

  1. fingerprintjs/fingerprintjs on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fingerprintjs-fingerprintjs.svg)](https://hysenlabs.com/projects/fingerprintjs-fingerprintjs)