ThumbmarkJS: Client-Side Browser Fingerprinting in JavaScript

Category: Javascript , Recommended | June 24, 2026
Authorthumbmarkjs
Last UpdateJune 24, 2026
LicenseMIT
Views0 views
ThumbmarkJS: Client-Side Browser Fingerprinting in JavaScript

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 optional visitorId.
  • api_endpoint (string): Overrides the hosted API endpoint. This option only applies when api_key is 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 is 5000.
  • stabilize (string[]): Applies browser-specific exclusions for private, iframe, vpn, and always stability rules.
  • logging (boolean): Controls sampled anonymous component logging. The default is true.
  • 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 is 0, which disables caching.
  • performance (boolean): Adds per-component timing information to the elapsed property.
  • experimental (boolean): Collects experimental intl, mathml, and mediadevices components 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. Use cache_lifetime_in_ms for new implementations.
  • storage_property_name (string): Deprecated. Use property_name_factory for 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:

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.

You Might Be Interested In:


Leave a Reply