Skip to content

Rajesh-Royal/Broprint.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Broprint.js

The world's easiest, smallest and powerful visitor identifier for browsers.

npm version CI status Coverage Minzipped size License Tweet

Generate a stable per-browser identifier from canvas + audio fingerprints, hashed with a fast, zero-dependency 53-bit hash. No tracking pixels, no third-party services, no runtime dependencies.

CodeSandbox · Live Demo

⚠️ Not a security primitive. The hash (cyrb53) is a fast, non-cryptographic checksum. Use it for visitor identification, analytics, and fraud-signal heuristics — not for authentication, password storage, or anything that requires collision resistance.

📦 Migrating from v2? See MIGRATION.md for the breaking changes in v3.0.0.


Install

npm i @rajesh896/broprint.js
# or
yarn add @rajesh896/broprint.js
# or
pnpm add @rajesh896/broprint.js

CDN (no install)

ESM (modern browsers):

<script type="module">
    import { getCurrentBrowserFingerPrint } from 'https://cdn.jsdelivr.net/npm/@rajesh896/broprint.js@latest/lib/index.mjs';
    getCurrentBrowserFingerPrint().then((fp) => console.log('Fingerprint:', fp));
</script>

Classic global build (no module support needed):

<script src="https://cdn.jsdelivr.net/npm/@rajesh896/broprint.js@latest/lib/index.global.js"></script>
<script>
    Broprint.getCurrentBrowserFingerPrint().then((fp) => console.log('Fingerprint:', fp));
</script>

Quick start

import { getCurrentBrowserFingerPrint } from '@rajesh896/broprint.js';

const fingerprint = await getCurrentBrowserFingerPrint();
// → "1234567890123456" — a stable numeric string for this browser

Disable a signal

// canvas-only (skip audio entirely)
await getCurrentBrowserFingerPrint({ useAudio: false });

// audio-only
await getCurrentBrowserFingerPrint({ useCanvas: false });

// custom seed (e.g. to namespace fingerprints per-app)
await getCurrentBrowserFingerPrint({ seed: 42 });

Use the building blocks directly

The individual signal generators and the hash function are also exported, so you can compose your own pipeline:

import {
    getCanvasFingerprint,
    getAudioFingerprint,
    cyrb53,
    isCanvasSupported
} from '@rajesh896/broprint.js';

const canvas = getCanvasFingerprint(); // sync, returns canvas dataURL
const audio = await getAudioFingerprint(); // async, returns numeric string
const hash = cyrb53(canvas + audio); // → number in [0, 2^53)

API

getCurrentBrowserFingerPrint(options?)

Option Type Default Description
useAudio boolean true Include the audio fingerprint signal.
useCanvas boolean true Include the canvas fingerprint signal.
seed number 0 Custom seed for the cyrb53 hash. Use to namespace fingerprints per-app.

Returns: Promise<string> — a stable numeric string (53-bit hash, base-10).

Throws:

  • If both useAudio and useCanvas are false (no signals selected).
  • If the only enabled signal fails (e.g. useCanvas: false on a browser that blocks OfflineAudioContext).
  • If audio fails and canvas also fails.

If audio is enabled but fails (e.g. privacy mode blocks OfflineAudioContext) and canvas is also enabled, the function automatically falls back to a canvas-only fingerprint.

Named exports

  • getCanvasFingerprint(): string — render the canvas + return its toDataURL().
  • isCanvasSupported(): boolean — feature-detects HTML5 canvas with a 2D context.
  • getAudioFingerprint(): Promise<string> — render an OfflineAudioContext graph + return the float sum as a string.
  • cyrb53(str: string, seed?: number): number — fast, non-cryptographic 53-bit hash.
  • BroprintOptions — TypeScript type for the options object.

How it works

                    ┌────────────────────────────────┐
                    │         getAudioFingerprint    │
  Audio entropy ──▶ │  OfflineAudioContext renders   │ ──▶ float sum (string)
                    │  500 frames through a          │
                    │  DynamicsCompressor.           │
                    └────────────────────────────────┘
                                     │
                                     ▼  base64-encode
                    ┌────────────────────────────────┐
                    │       getCanvasFingerprint     │
  Canvas entropy ──▶│  Draw layered text + shapes    │ ──▶ canvas.toDataURL()
                    │  and read back the data URI    │
                    │  (varies by GPU / font stack). │
                    └────────────────────────────────┘
                                     │
                                     ▼  concat
                    ┌────────────────────────────────┐
                    │              cyrb53            │ ──▶ 53-bit numeric hash
                    │  (custom, no deps, ~10 lines)  │     coerced to string
                    └────────────────────────────────┘
                                     │
                                     ▼
                              fingerprint

Browser compatibility

API Required for Support
HTMLCanvasElement canvas signal All modern browsers
OfflineAudioContext audio signal All modern browsers (webkitOfflineAudioContext fallback for older Safari)
Promise / async always All modern browsers (ES2017+)

Tested on the latest stable Chrome, Firefox, Safari, and Edge. Node ≥ 18 is required for the build/test toolchain.

Caveats

  • Not unique forever. A browser update, GPU driver change, OS upgrade, or "ungoogled" build can change the output. Treat the fingerprint as a stable signal for a session/install, not a permanent identity.
  • Privacy modes can block signals. Some privacy-focused browsers (Brave Strict, Tor, Firefox RFP) randomize or block the underlying APIs. The library falls back gracefully to the available signal, but the output will differ from the same user's "normal" browsing.
  • Not for security. The 53-bit cyrb53 hash is fast and well-distributed but not cryptographically secure — collisions exist and the algorithm is reversible with effort. Don't use the output as a session token or password salt.

Contributing

See CONTRIBUTING.md for the dev setup, test/lint loop, and PR process. Bug reports and feature requests are welcome via GitHub Issues; security-sensitive reports should follow SECURITY.md.

License

MIT © Rajesh Royal


Stargazers repo roster for @Rajesh-Royal/Broprint.js Forkers repo roster for @Rajesh-Royal/Broprint.js

Back to top