Docs · WhiskerJS 0.1.0 · signalsVersion 5 · idVersion 2

Overview

What WhiskerJS is, what it returns, and how to read the live demo.

In plain words

WhiskerJS is an open-source (Apache-2.0) script for web pages. It reads technical characteristics of the visitor’s browser and device, such as screen size, fonts and how a test image is drawn, and returns them as one JSON object. Your own server then decides what to do with it: recognise a device it has seen before, or notice that something looks automated. WhiskerJS itself never decides, never sends anything and never stores anything.

What you get from one call

import { load } from 'whiskerjs';

const agent = await load();
const result = await agent.collect();
Field What it is
components 46 measurements, each with a status (ok, unavailable, blocked, noisy, excluded, timed_out) and, when not ok, a reason code
visitorId a 32-character hash of the 37 stable components: equal ids mean the same browser setup
structuredId seven 12-character hashes, one per signal group, so two results can be compared group by group
integrityFlags names of the 14 checks for automation and tampering that fired
binding your server’s nonce and timestamp, bound to the result with a digest (only if you pass them)
version, signalsVersion, idVersion 0.1.0, 5, 2: store them with every id
durationMs how long the collection took

What it is and is not

WhiskerJS is WhiskerJS is not
a collector of device and browser signals a bot verdict or a risk score
a library that runs in your page a hosted service or an API
stateless: every call starts from nothing a tracker: it stores no cookie or id
silent on the network telemetry: it never phones home
open source under Apache-2.0 on npm yet (build it from source)

The pages

Reading the live demo

The live demo runs the real library (the build of commit 1100e48, signalsVersion 5, idVersion 2) in your browser and shows exactly what it returns. Nothing is sent anywhere; the demo page keeps a history of your runs in your own browser so it can compare them.

  • visitorId (top left): the id for this browser setup. The chip under it says whether it matches your previous run on this device.
  • Version tiles: version, signalsVersion and idVersion of the library, the run’s duration, how many components are ok, and how many times you have loaded the page.
  • structuredId: the full value and one tile per group. After a second run, a group whose part changed is highlighted, which tells you what moved (for example gpu after a graphics driver update).
  • Integrity flags: usually empty on a normal browser. “What every flag means” explains each one; see Integrity checks for the false positives (privacy extensions often set native_tampering).
  • Components table: every component with its status, the reason code when it is not ok, whether it counts in the visitorId, and its value. Values that are 32 hex characters are digests, not raw data. Common non-ok rows are normal: device_memory and heap_limit are unavailable outside Chromium-based browsers, audio_latency is unavailable with skipped outside Safari and Android, and under Brave several components are excluded with brave_farbling.
  • History: newest first, with the groups and components that changed since the run before. Runs from different library versions are never compared; the list marks the boundary.
  • Lab testing mode: label the device, load the page a few times, and copy one tab-separated line per run into a sheet to measure stability on your own devices. “Copy full JSON” includes the anti-replay binding (the demo makes its own nonce; a real site gets it from its server).

What to try: run it twice (the id should hold), open a private window (some browsers add canvas noise there, and canvas or webgl_image turn noisy), or change the browser language (usually only the locale part of the structuredId changes).