The world's easiest, smallest and powerful visitor identifier for browsers.
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.
⚠️ 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.mdfor the breaking changes in v3.0.0.
npm i @rajesh896/broprint.js
# or
yarn add @rajesh896/broprint.js
# or
pnpm add @rajesh896/broprint.js
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>
import { getCurrentBrowserFingerPrint } from '@rajesh896/broprint.js';
const fingerprint = await getCurrentBrowserFingerPrint();
// → "1234567890123456" — a stable numeric string for this browser
// 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 });
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)
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:
useAudio and useCanvas are false (no signals selected).useCanvas: false on a browser that blocks OfflineAudioContext).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.
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. ┌────────────────────────────────┐
│ 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
| 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.
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.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.
MIT © Rajesh Royal
$ claude mcp add Broprint.js \
-- python -m otcore.mcp_server <graph>