ThumbmarkJS is a free, popular JavaScript fingerprint library that generates browser fingerprints by combining canvas, WebGL, audio, font, and many other signals entirely on the client.
You can use it to recognize returning visitors, distinguish human users from bots, and strengthen fraud detection workflows on your web apps.
Features:
- Generates a visitor fingerprint hash from over 15 browser signals.
- Operates entirely client-side with no backend requirement.
- Collects audio, canvas, WebGL, font list, hardware, locale, math, permissions, plugins, screen, system, WebRTC, and speech synthesis data.
- Exposes configuration to exclude or include specific signal components.
- Supports setting a component timeout to avoid slow hangs.
- Includes experimental components like MathML and media device enumeration.
- Provides built-in stabilization rules for private browsing and iframes.
- Accepts an API key for server-side TLS, HTTP header, IP analysis, and bot scoring.
- Available as UMD, ESM, and CommonJS bundles for any module system.
- Integrates with React, Vue, Angular, and Preact via official plugins.
- MIT-licensed for commercial use.
Use Cases:
- Submit a browser hash with account-creation data for repeated-registration review.
- Compare fingerprint results across checkout attempts during fraud investigations.
- Store a visitor identifier alongside rate-limit records after obtaining appropriate consent.
How To Use It
Install & download
Install ThumbmarkJS with npm.
npm install @thumbmarkjs/thumbmarkjs
Or load the UMD bundle from a CDN.
<script src="https://cdn.jsdelivr.net/npm/@thumbmarkjs/thumbmarkjs/dist/thumbmark.umd.js"></script>
Basic Usage
Create a Thumbmark instance in browser code, then call get() to collect the fingerprint result.
import { Thumbmark } from '@thumbmarkjs/thumbmarkjs';
const fingerprintClient = new Thumbmark();
const result = await fingerprintClient.get();
console.log(result.thumbmark);
console.log(result.components);
The returned object includes the fingerprint hash, collected components, the package version, and any structured errors. API-backed configurations may also return visitorId, info, requestId, and echoed metadata.
Browser Usage
A plain HTML page can access the constructor through the ThumbmarkJS global.
<script>
async function collectFingerprint() {
const fingerprintClient = new ThumbmarkJS.Thumbmark();
const result = await fingerprintClient.get();
console.log('Browser fingerprint:', result.thumbmark);
}
collectFingerprint();
</script>
Handle Partial Results
Component timeouts and API failures appear in the error array instead of rejecting the request. Keep the valid hash when your workflow can tolerate missing components.
import { Thumbmark } from '@thumbmarkjs/thumbmarkjs';
const fingerprintClient = new Thumbmark({
timeout: 3000
});
const result = await fingerprintClient.get();
if (result.error?.length) {
console.warn('Fingerprint warnings:', result.error);
}
console.log(result.thumbmark);
Advanced Usages
Restrict the Client-Side Signal Set
A privacy-sensitive analytics feature may only require a limited group of browser signals. The include option limits client-side components, while exclude removes components from the final fingerprint.
import { Thumbmark } from '@thumbmarkjs/thumbmarkjs';
const fingerprintClient = new Thumbmark({
include: ['canvas', 'audio', 'webgl'],
exclude: ['permissions'],
logging: false
});
const result = await fingerprintClient.get();
console.log(result.thumbmark);
Add an API-Backed Visitor Identifier
Account recovery, fraud review, and abuse controls might need a more stable identifier than a local browser hash. The core JavaScript constructor uses the snake_case api_key option.
import { Thumbmark } from '@thumbmarkjs/thumbmarkjs';
const fingerprintClient = new Thumbmark({
api_key: 'YOUR_PUBLIC_API_KEY',
metadata: () => ({
flow: 'signup',
page: location.pathname
})
});
const result = await fingerprintClient.get();
console.log(result.visitorId);
console.log(result.info);
Register an Application-Specific Component
This can be useful in some apps that need to include a non-sensitive signal that exists only in their own UI.
import { Thumbmark } from '@thumbmarkjs/thumbmarkjs';
const fingerprintClient = new Thumbmark();
fingerprintClient.includeComponent('display-settings', async () => ({
colorDepth: screen.colorDepth,
pixelRatio: window.devicePixelRatio
}));
const result = await fingerprintClient.get();
console.log(result.components.displaySettings);
Use ThumbmarkJS in a React Client Component
The React package provides ThumbmarkProvider and useThumbmark, while the provider uses a camelCase apiKey prop.
npm install @thumbmarkjs/thumbmarkjs @thumbmarkjs/react
'use client';
import { ThumbmarkProvider, useThumbmark } from '@thumbmarkjs/react';
function BrowserFingerprintField() {
const { thumbmark, isLoading, error } = useThumbmark();
if (isLoading || error) {
return null;
}
return (
<input
type="hidden"
name="browserFingerprint"
value={thumbmark || ''}
/>
);
}
export default function SignupForm() {
return (
<ThumbmarkProvider options={{ exclude: ['permissions'] }}>
<form>
<BrowserFingerprintField />
<button type="submit">Create account</button>
</form>
</ThumbmarkProvider>
);
}
All configuration options
api_key(string): Adds API-backed fingerprinting data and an optionalvisitorId.api_endpoint(string): Overrides the hosted API endpoint. This option only applies whenapi_keyis present.include(string[]): Limits collection to selected client-side components or nested component paths.exclude(string[]): Removes selected client-side components or nested paths from the fingerprint.permissions_to_check(PermissionName[]): Replaces the default Permission API checks.timeout(number): Sets the component and API timeout in milliseconds. The default is5000.stabilize(string[]): Applies browser-specific exclusions forprivate,iframe,vpn, andalwaysstability rules.logging(boolean): Controls sampled anonymous component logging. The default istrue.property_name_factory((name: string) => string): Changes the local storage key naming pattern.cache_lifetime_in_ms(number): Caches API responses in local storage. The default is0, which disables caching.performance(boolean): Adds per-component timing information to theelapsedproperty.experimental(boolean): Collects experimentalintl,mathml, andmediadevicescomponents outside the fingerprint hash.metadata(JSON value | function): Sends application metadata with API requests. It does not change the resulting fingerprint.cache_api_call(boolean): Deprecated. Usecache_lifetime_in_msfor new implementations.storage_property_name(string): Deprecated. Useproperty_name_factoryfor new implementations.
API Methods
import { Thumbmark } from '@thumbmarkjs/thumbmarkjs';
// Create a reusable client with default options.
const fingerprintClient = new Thumbmark({
timeout: 3000
});
// Generate a fingerprint with optional one-time overrides.
const result = await fingerprintClient.get({
exclude: ['permissions']
});
// Return the installed ThumbmarkJS version.
const version = fingerprintClient.getVersion();
// Register a custom component for this instance.
fingerprintClient.includeComponent('viewport', async () => ({
width: window.innerWidth,
height: window.innerHeight
}));
Alternatives:
- Browser Fingerprint Generator with Fraud Detection & Bot Detection
- Lightweight Device Detection and UUID Generation Library
- Generate Device-Specific Fingerprints with hashed-device-fingerprint-js
- Simplify Device and Browser Detection With The brewser JavaScript Library
FAQs:
Q: Can ThumbmarkJS run in Node.js or during SSR?
A: No. ThumbmarkJS depends on browser APIs such as window, document, Canvas, WebGL, and navigator. Use it in a client-side lifecycle hook or browser-only component.
Q: What is the difference between thumbmark and visitorId?
A: thumbmark is the local browser fingerprint hash. visitorId requires an API key and adds hosted server-side analysis to the result.
Q: Should a browser fingerprint replace authentication or CAPTCHA checks?
A: No. Use it as one risk or correlation signal alongside server-side validation, authentication controls, rate limits, and audit data.
Q: Which option should I use for faster collection?
A: Exclude components your application does not need, especially permission checks. Enable performance: true during development to inspect per-component timing data.






