# Glossary

> Short, plain definitions of every term the WhiskerJS documentation uses, each with a note on how the library applies it.

Source: https://whiskerjs.com/glossary/ (last updated 2026-10-26)

> **In plain words:**
>
> Browser fingerprinting has its own vocabulary. This page explains each word the WhiskerJS docs use, in one to three sentences first, then how WhiskerJS applies it. Each term has its own anchor, so you can link straight to it, for example [/glossary/#farbling](https://whiskerjs.com/glossary/#farbling).

## Advanced Fingerprinting Protection

Advanced Fingerprinting Protection (AFP) is Safari’s fingerprinting defence. It adds noise to canvas, WebGL and Web Audio readback and reports the window size as the screen size. It is on in private browsing, and in all browsing where the Safari setting (or a newer Safari’s default) says so.

WhiskerJS recognises it when Safari’s canvas or WebGL known-answer probe comes back altered, classes the browser `safari_afp`, and does not collect `audio`, `canvas`, `screen_frame`, `screen_resolution` and `webgl_image` (ruleId `safari_afp`). Stock Safari reads the known answers back exactly and stays `safari`.

See: [Safari on macOS](https://whiskerjs.com/browsers/safari-macos/), [Known-answer probe](https://whiskerjs.com/glossary/#known-answer-probe), [Exclusion table](https://whiskerjs.com/glossary/#exclusion-table).

## Anti-replay

Anti-replay is any measure that stops a recorded message from being accepted a second time. For device signals it means a result made once cannot be sent again later, or from another machine, and still pass.

WhiskerJS supports it with the optional binding: your server issues a single-use nonce and a timestamp, `collect({ binding })` copies them into the result and adds a digest over the whole result. Your server checks that the nonce is its own, unused and recent, and that the digest matches.

See: [Anti-replay binding](https://whiskerjs.com/docs/integration/#anti-replay-binding), [Nonce](https://whiskerjs.com/glossary/#nonce), [Binding digest](https://whiskerjs.com/glossary/#binding-digest).

## Automation globals

Automation globals are variables that browser automation tools leave on the page’s `window` or `document`, such as properties added by Selenium, PhantomJS or ChromeDriver. Their presence suggests the page is driven by a tool rather than a person.

WhiskerJS checks a list of 32 known global names, `document` properties starting with `$cdc_`, `$wdc_` or `cdc_`, and `webdriver`, `selenium` or `driver` attributes on `<html>`. A hit sets the `automation_globals` flag.

See: [automation_globals](https://whiskerjs.com/docs/integrity/#automation_globals), [WebDriver](https://whiskerjs.com/glossary/#webdriver).

## Binding digest

The binding digest is a 128-bit hash that WhiskerJS computes over a whole result, including the nonce and timestamp your server passed in. It lets your server notice whether the result was changed after it was made.

It is the first 128 bits of SHA-256 over the text that the exported `bindingInput(result)` returns. It is not a signature: code running in the page can compute it too, so it stops replay and accidental edits, not a forged result.

See: [The digest](https://whiskerjs.com/docs/integration/#the-digest), [Anti-replay](https://whiskerjs.com/glossary/#anti-replay).

## Browser class

A browser class is WhiskerJS’s own coarse label for the browser family: `brave`, `chromium_webview`, `firefox_fpp`, `firefox_rfp`, `rfp_hardened`, `firefox`, `safari_afp`, `safari`, `chromium` or `other`. It is worked out from cheap, prompt-free hints such as `navigator.brave`, the user agent, `navigator.vendor`, the userAgentData brands and the canvas and WebGL known-answer probes.

The class picks the row of the exclusion table and is reported as the `browser_class` component. It is a guess from values the client controls, so treat it as a hint.

See: [browser_class](https://whiskerjs.com/signals/browser-class/), [Browsers](https://whiskerjs.com/browsers/), [Exclusion table](https://whiskerjs.com/glossary/#exclusion-table).

## Canvas fingerprinting

Canvas fingerprinting draws a fixed picture (text, shapes, colours) on an HTML canvas and reads the pixels back. Small differences in fonts, anti-aliasing and graphics stacks make the result differ between devices.

WhiskerJS’s `canvas` component draws a 260x80 scene with text, a cat emoji, blended circles and an even-odd ring, reads the pixels back with `getImageData()` (since signalsVersion 9; Firefox randomises `toDataURL()` per session) and reports only a digest.

See: [canvas](https://whiskerjs.com/signals/canvas/), [Canvas noise](https://whiskerjs.com/glossary/#canvas-noise), [Double render](https://whiskerjs.com/glossary/#double-render).

## Canvas noise

Canvas noise is small random change that a browser or extension adds to canvas or WebGL readback on purpose, so that the picture differs a little on every read or in every session. It defeats fingerprints that rely on an exact image.

WhiskerJS does not try to undo it. It detects noise on every read with the double render (`render_mismatch`) and noise seeded per session with the known-answer probes (`seeded_noise`), and reports the component as `noisy`. The `canvas_readback` and `noise_profile` components report what the probes saw.

See: [Noise handling](https://whiskerjs.com/docs/how-it-works/#noise-handling-the-double-render-and-the-known-answers), [canvas_readback](https://whiskerjs.com/signals/canvas-readback/).

## Clean iframe realm

A clean iframe realm is a fresh, untouched copy of the browser’s built-in objects, taken from a new `about:blank` iframe. Scripts that override functions usually do so only in the page, so the fresh copy shows the original behaviour.

WhiskerJS creates one hidden iframe with no `src` after the collectors finish, compares against it for the `iframe_mismatch` and `prototype_lie` checks, and removes it straight away. After an abort no iframe is made.

See: [The clean iframe realm](https://whiskerjs.com/docs/how-it-works/#the-clean-iframe-realm), [Lie detection](https://whiskerjs.com/glossary/#lie-detection).

## Client Hints

User-Agent Client Hints are a browser API (`navigator.userAgentData`) that reports the browser brands, platform and whether the device is mobile, with more detail available on request. It is offered by Chromium-based browsers.

WhiskerJS reads them into two components: `ua_client_hints` (brands without versions, platform, architecture and similar, in the visitorId) and `ua_versions` (full versions, outside both ids). Safari and Firefox do not offer the API, so both are `unavailable` there.

See: [ua_client_hints](https://whiskerjs.com/signals/ua-client-hints/), [ua_versions](https://whiskerjs.com/signals/ua-versions/), [GREASE](https://whiskerjs.com/glossary/#grease), [High-entropy hints](https://whiskerjs.com/glossary/#high-entropy-hints).

## Collision

A collision is two different devices producing the same identifier. With browser fingerprints it happens when devices share the same hardware, software and settings, such as two identical phones on the same system version.

WhiskerJS’s ids describe a browser setup, not a person, so collisions are expected for identical setups. No collision rate is published yet: the measurement that could give one has not run.

See: [Identifiers](https://whiskerjs.com/docs/identifiers/), [Entropy](https://whiskerjs.com/glossary/#entropy).

## Component

A component (also called a signal) is one measurement in a WhiskerJS result, such as the screen size or a digest of the installed fonts. Each component has a status and, when it was read, a value.

WhiskerJS reports 47 components, always all of them. 37 are stable and make up the ids; 10 are reported but kept out of the ids.

See: [Signals](https://whiskerjs.com/signals/), [Statuses and reason codes](https://whiskerjs.com/docs/how-it-works/#statuses-and-reason-codes).

## Content blocker

A content blocker is a browser feature or extension that hides or blocks page elements and requests, typically ads and trackers. Cosmetic filters hide elements whose class names or ids look like ads.

WhiskerJS’s `content_blockers` component adds eight 1x1 bait elements off screen, waits 50 ms and reports which ones were hidden. It makes no request and is outside both ids, because users switch blockers on and off.

See: [content_blockers](https://whiskerjs.com/signals/content-blockers/).

## Digest

A digest is a short, fixed-length hash computed from a larger value. It stays the same for the same input, but the input cannot be read back from it.

WhiskerJS uses the first 128 bits of SHA-256, written as 32 lowercase hex characters. Large values (images, audio samples, font lists and similar) leave the library only as a digest; a component carries `hashed: true` when its value is one.

See: [Hashing](https://whiskerjs.com/docs/how-it-works/#hashing), [Web Crypto](https://whiskerjs.com/glossary/#web-crypto).

## Double render

The double render is WhiskerJS’s way of noticing canvas and WebGL noise: it draws the same scene twice and compares the two results. Identical drawings should give identical output, so a difference means something adds randomness.

When the two differ, the component is `noisy` with ruleId `render_mismatch` and carries no value, which keeps the id the same from run to run instead of changing every time. It is used by `canvas` and `webgl_image`; `audio` has no double render. Noise that is the same on both reads is caught by the known-answer probes instead.

See: [Noise handling](https://whiskerjs.com/docs/how-it-works/#noise-handling-the-double-render-and-the-known-answers), [Canvas noise](https://whiskerjs.com/glossary/#canvas-noise).

## Entropy

Entropy, in fingerprinting, measures how much a signal tells devices apart, usually in bits: a signal with more possible, evenly spread values has more entropy. It depends on the audience, so the same signal has different entropy on different sites.

WhiskerJS publishes no entropy figures for its signals: none have been measured yet. Expectations in the project roadmap are labelled as expectations.

See: [Collision](https://whiskerjs.com/glossary/#collision), [Stability](https://whiskerjs.com/glossary/#stability).

## Exclusion table

The exclusion table is the fixed list, per browser class, of components WhiskerJS does not collect because that browser randomises or normalises them on purpose. Such components report status `excluded` with the table’s ruleId.

Brave loses twelve components (`brave_farbling`), Firefox with Fingerprinting Protection three (`firefox_fpp`), Firefox with resistFingerprinting nine (`firefox_rfp`), Tor and Mullvad Browser the same nine (`rfp_hardened`) and Safari with Advanced Fingerprinting Protection five (`safari_afp`). Android WebView has its own class (`chromium_webview`) but loses nothing. The table is exported as `EXCLUSION_TABLE` and the class list as `BROWSER_CLASSES`; changing either bumps `signalsVersion`.

See: [The exclusion table](https://whiskerjs.com/docs/how-it-works/#the-exclusion-table), [Farbling](https://whiskerjs.com/glossary/#farbling), [resistFingerprinting](https://whiskerjs.com/glossary/#resistfingerprinting).

## Farbling

Farbling is Brave’s name for its fingerprinting protection: it adds small, per-site and per-session random changes to values such as canvas and audio output. A site sees stable values during a session, while different sites see different values.

WhiskerJS recognises Brave by `navigator.brave.isBrave` being a function and does not collect the farbled components (`audio`, `canvas`, `fonts`, `fonts_canvas`, `hardware_concurrency`, `plugins`, `speech_voices`, `webgl_image`, and, since Brave 1.93 made them generic for every user, `webgl_params`, `webgl_renderer`, `webgl_vendor` and `webgpu`); they report `excluded` with ruleId `brave_farbling`.

See: [Brave](https://whiskerjs.com/browsers/brave/), [Exclusion table](https://whiskerjs.com/glossary/#exclusion-table).

## Fingerprinting Protection

Fingerprinting Protection (FPP) is Firefox’s lighter fingerprinting defence, separate from resistFingerprinting. It randomises canvas and WebGL readback per site and session and collapses the available screen area to the screen. It is on in private windows and, since Firefox 151, is rolling out to normal windows.

WhiskerJS recognises it when a Firefox that is not resistFingerprinting fails its canvas or WebGL known-answer probe, classes it `firefox_fpp`, and does not collect `canvas`, `screen_frame` and `webgl_image` (ruleId `firefox_fpp`).

See: [Firefox](https://whiskerjs.com/browsers/firefox/), [Known-answer probe](https://whiskerjs.com/glossary/#known-answer-probe), [Exclusion table](https://whiskerjs.com/glossary/#exclusion-table).

## Font fingerprinting

Font fingerprinting finds out which fonts are installed by measuring text: a font that exists changes the width or height of text set in it, compared with a generic fallback. Installed fonts vary with the operating system, language packs and software.

WhiskerJS probes 54 families two ways, with hidden spans (`fonts`) and with canvas `measureText()` (`fonts_canvas`), and measures the default font settings (`font_preferences`). Only digests leave the library.

See: [fonts](https://whiskerjs.com/signals/fonts/), [fonts_canvas](https://whiskerjs.com/signals/fonts-canvas/), [font_preferences](https://whiskerjs.com/signals/font-preferences/).

## GREASE

GREASE (Generate Random Extensions And Sustain Extensibility) is a deliberately fake brand that Chromium browsers add to their Client Hints brand list, with a name that changes between versions, such as “Not)A;Brand”. It keeps servers from depending on an exact list.

WhiskerJS removes it before using the brands: any brand that reads “notabrand” once reduced to letters is dropped, so the changing name does not change the id.

See: [ua_client_hints](https://whiskerjs.com/signals/ua-client-hints/), [Client Hints](https://whiskerjs.com/glossary/#client-hints).

## Headless browser

A headless browser runs without a visible window, usually controlled by a script for testing, scraping or automation. Headless builds often differ in small ways from a normal browser.

WhiskerJS has two flags for it: `headless_user_agent` (the user agent contains `HeadlessChrome`, `PhantomJS` or `SlimerJS`) and `headless_markers` (outer window size 0x0, or a desktop Chrome user agent without `window.chrome`). Neither is a verdict.

See: [headless_markers](https://whiskerjs.com/docs/integrity/#headless_markers), [headless_user_agent](https://whiskerjs.com/docs/integrity/#headless_user_agent), [Bot detection](https://whiskerjs.com/use-cases/bot-detection/).

## High-entropy hints

High-entropy hints are the detailed Client Hints values a page must ask for with `navigator.userAgentData.getHighEntropyValues()`, such as the CPU architecture, bitness, device model and full version list. The call does not prompt the user.

WhiskerJS makes one such request per collection. When a Permissions Policy refuses it, the component reports the stable marker `he=blocked` instead (or `he=failed`, `he=none`).

See: [ua_client_hints](https://whiskerjs.com/signals/ua-client-hints/), [Permissions Policy](https://whiskerjs.com/glossary/#permissions-policy).

## idVersion

`idVersion` is the version number of how WhiskerJS derives the visitorId and structuredId from the components: the line encoding, the prefix and the groups. It is in every result.

A new idVersion gives every device a new id, because the prefix line contains it. The current idVersion is 2. Compare ids only within the same idVersion and signalsVersion.

See: [Why versions bump](https://whiskerjs.com/docs/identifiers/#why-versions-bump), [signalsVersion](https://whiskerjs.com/glossary/#signalsversion).

## Integrity flag

An integrity flag is the name of a WhiskerJS check that fired, listed in `result.integrityFlags`. Each one is a sign that the page may be automated or that browser functions were changed.

There are 19 checks at signalsVersion 9. They are read-only, never a verdict, and their absence proves nothing: a client can remove them. Your server decides what they mean.

See: [Integrity checks](https://whiskerjs.com/docs/integrity/), [Lie detection](https://whiskerjs.com/glossary/#lie-detection).

## Known-answer probe

A known-answer probe draws or renders something whose exact output is known in advance, reads it back and compares. Any difference means the browser altered the readback.

WhiskerJS runs three, each read twice: a 16x16 canvas in two known colours, a WebGL buffer cleared to a known colour, and an offline audio render of a constant 0.5. Each gives `exact`, `seeded` (the same wrong answer twice), `per_read` (two different answers) or `na`, reported together as the `noise_profile` component. A failed probe turns the matching component `noisy` with ruleId `seeded_noise` and can pick the `firefox_fpp` or `safari_afp` class.

See: [Noise handling](https://whiskerjs.com/docs/how-it-works/#noise-handling-the-double-render-and-the-known-answers), [noise_profile](https://whiskerjs.com/signals/noise-profile/), [Seeded noise](https://whiskerjs.com/glossary/#seeded-noise).

## Lie detection

Lie detection looks for browser values or functions that were overridden to report something false, for example a spoofed user agent or a patched canvas function. It compares how a function prints and behaves with how a native one does.

WhiskerJS’s checks include `native_tampering`, `navigator_own_property`, `prototype_lie` and `iframe_mismatch`. Privacy extensions trigger them too, so a hit means “changed”, not “fraud”.

See: [native_tampering](https://whiskerjs.com/docs/integrity/#native_tampering), [prototype_lie](https://whiskerjs.com/docs/integrity/#prototype_lie), [Clean iframe realm](https://whiskerjs.com/glossary/#clean-iframe-realm).

## Nonce

A nonce is a value used only once. In anti-replay, the server makes a fresh random nonce for each request and accepts it back only once.

WhiskerJS accepts a nonce of 8 to 128 printable ASCII characters without spaces and recommends at least 128 random bits, for example 32 hex characters from a cryptographic source. It reads no randomness of its own for the binding.

See: [In the page](https://whiskerjs.com/docs/integration/#in-the-page), [Anti-replay](https://whiskerjs.com/glossary/#anti-replay).

## Offline audio rendering

Offline audio rendering asks the browser’s audio engine to compute sound into a buffer without playing it. The exact floating-point samples differ between engines, operating systems and CPUs.

WhiskerJS’s `audio` component renders a 10 kHz triangle wave through a dynamics compressor in an `OfflineAudioContext` (1 channel, 5000 frames at 44100 Hz) and hashes the last 500 samples. Nothing is played and no audio device is opened.

See: [audio](https://whiskerjs.com/signals/audio/).

## Permissions Policy

A Permissions Policy is a set of rules, sent by a site in an HTTP header or an iframe’s `allow` attribute, that decides which browser features a page or frame may use. It can, for example, refuse detailed Client Hints to an embedded frame.

When WhiskerJS’s high-entropy Client Hints request is refused this way, `ua_client_hints` and `ua_versions` end with the marker `he=blocked` instead of failing.

See: [High-entropy hints](https://whiskerjs.com/glossary/#high-entropy-hints), [ua_client_hints](https://whiskerjs.com/signals/ua-client-hints/).

## Previous id

A previous id is the visitorId (or structuredId) that the library version just before the current one would have given the same browser. It lets a server recognise a known device across a version bump instead of seeing a stranger.

For one release after a bump, every WhiskerJS result carries `previousVisitorId` and `previousStructuredId` with the versions they belong to (`previousSignalsVersion`, `previousIdVersion`; today signalsVersion 8 and idVersion 2). Your server looks the previous id up under those versions and stores the new id next to the device it finds. Like every client value it can be forged, so use it only for linking, never to grant access.

See: [Previous ids](https://whiskerjs.com/docs/identifiers/#previous-ids-linking-across-a-version-bump), [Visitor id](https://whiskerjs.com/glossary/#visitor-id), [signalsVersion](https://whiskerjs.com/glossary/#signalsversion).

## Private Click Measurement

Private Click Measurement is a Safari (WebKit) feature for measuring ad clicks without cross-site tracking. Links can carry an `attributionSourceId` attribute for it.

WhiskerJS’s `private_click` component reads `attributionSourceId` from a new `<a>` element that gets no `href` and is never attached. Outside Safari it reports the plain value `none`.

See: [private_click](https://whiskerjs.com/signals/private-click/), [Safari on macOS](https://whiskerjs.com/browsers/safari-macos/).

## Repeat reads

Repeat reads means reading the same browser value many times in a row and checking that every read agrees. Some browsers give a value that changes between reads, so a single read would make the id flap.

WhiskerJS reads `hardware_concurrency` and `device_memory` 16 times. When the reads disagree the component is `noisy` with ruleId `read_varies`, never one of the values. Safari, which alternates between 4 and 8 cores for scripts on its known-fingerprinting list, reports 4 or 8 as the one bucket `4_8`.

See: [hardware_concurrency](https://whiskerjs.com/signals/hardware-concurrency/), [device_memory](https://whiskerjs.com/signals/device-memory/).

## resistFingerprinting

`privacy.resistFingerprinting` is a Firefox setting, also used by Tor Browser and Mullvad Browser, that makes the browser report fixed or normalised values (for example UTC as the time zone and the content area as the screen size) so that users look alike.

WhiskerJS classes Firefox as `firefox_rfp` only when every resistFingerprinting trait holds at once and `navigator.webdriver` is not true, and then does not collect nine components (ruleId `firefox_rfp`). Tor Browser and Mullvad Browser, recognised by letterboxing steps and the spoofed English locale on top, are classed `rfp_hardened` and lose the same nine.

See: [Firefox resistFingerprinting and Tor Browser](https://whiskerjs.com/browsers/firefox-rfp-and-tor/), [Exclusion table](https://whiskerjs.com/glossary/#exclusion-table).

## ruleId

A ruleId is the short reason code that WhiskerJS attaches to every component whose status is not `ok`, such as `no_api`, `timeout` or `brave_farbling`. It says why the value is missing.

A ruleId always matches `^[a-z0-9_]{1,32}$`. The binding uses its own ruleIds (`invalid_binding`, `invalid_nonce`, `invalid_timestamp`, `no_digest`).

See: [Statuses and reason codes](https://whiskerjs.com/docs/how-it-works/#statuses-and-reason-codes).

## Secure context

A secure context is a page the browser trusts to be delivered safely: served over https, or from `http://localhost` during development. Some APIs, including `crypto.subtle`, exist only there.

Without a secure context WhiskerJS cannot hash, so `visitorId` and `structuredId` are `null` and every component that must be hashed reports `unavailable` with ruleId `no_digest`.

See: [Getting started](https://whiskerjs.com/docs/getting-started/), [Web Crypto](https://whiskerjs.com/glossary/#web-crypto).

## Seeded noise

Seeded noise is canvas, WebGL or audio noise that is the same on every read within a session or a site and different in the next one. Brave, Firefox Fingerprinting Protection and Safari Advanced Fingerprinting Protection add this kind.

Because two renders agree, the double render cannot see it; the known-answer probes can. WhiskerJS then reports `canvas`, `webgl_image` or `audio` as `noisy` with ruleId `seeded_noise`, so the id stays the same from session to session instead of changing every time.

See: [Known-answer probe](https://whiskerjs.com/glossary/#known-answer-probe), [Canvas noise](https://whiskerjs.com/glossary/#canvas-noise), [Double render](https://whiskerjs.com/glossary/#double-render).

## Signal group

A signal group is one of the seven sets the stable components are sorted into: `gpu`, `audio`, `fonts`, `device`, `browser`, `locale` and `prefs`. Each stable component belongs to exactly one group.

Each group gives one 12-hex part of the structuredId, so two results can be compared group by group. The groups are exported as `ID_GROUPS` and their order as `ID_GROUP_ORDER`.

See: [structuredId](https://whiskerjs.com/docs/identifiers/#structuredid), [Signals](https://whiskerjs.com/signals/).

## signalsVersion

`signalsVersion` is the version number of what WhiskerJS measures: the collectors, the integrity checks and the exclusion table. It is in every result.

It goes up when a collector changes what it measures, a check changes or the exclusion table changes. A bump can change ids and flags. The current signalsVersion is 9.

See: [What’s new](https://whiskerjs.com/whats-new/), [idVersion](https://whiskerjs.com/glossary/#idversion).

## Software renderer

A software renderer draws graphics on the CPU instead of a GPU, for example SwiftShader, llvmpipe or Mesa’s offscreen renderer. It is common on servers, in containers and in virtual machines.

When the WebGL renderer or vendor names one, WhiskerJS sets the `software_renderer` flag. Real users with hardware acceleration turned off or remote desktops can trigger it too.

See: [software_renderer](https://whiskerjs.com/docs/integrity/#software_renderer), [webgl_renderer](https://whiskerjs.com/signals/webgl-renderer/).

## Stability

Stability is how often a signal or identifier stays the same for the same device over time and across visits. A stable signal changes only with real changes, such as a new GPU driver or an installed font.

WhiskerJS keeps signals it expects to change easily (zoom, taskbar, permissions, keyboard layout, voices, versions and others) out of the ids. No stability figures are published yet; the early lab sample (signalsVersion 1, four device-browser pairs) is not a benchmark.

See: [What changes the id](https://whiskerjs.com/docs/identifiers/#what-changes-the-id), [Stable component](https://whiskerjs.com/glossary/#stable-component).

## Stable component

A stable component is one of the 37 WhiskerJS components that are part of the visitorId and the structuredId. They were chosen because they are expected to change rarely for the same device.

In the code each collector has a `stable` flag. The other 9 components are still reported, but kept out of both ids.

See: [Signals](https://whiskerjs.com/signals/), [Signal group](https://whiskerjs.com/glossary/#signal-group).

## Structured id

The structured id (`structuredId`) is WhiskerJS’s identifier made of seven short hashes, one per signal group, so two results can match in some groups and differ in others. It tells you which part of a device changed.

Its format is `<idVersion>_<gpu>_<audio>_<fonts>_<device>_<browser>_<locale>_<prefs>`, each part the first 48 bits (12 hex characters) of SHA-256. It is `null` without a digest.

See: [structuredId](https://whiskerjs.com/docs/identifiers/#structuredid), [Comparing two results](https://whiskerjs.com/docs/identifiers/#comparing-two-results).

## Visitor id

The visitor id (`visitorId`) is WhiskerJS’s single identifier: one 128-bit hash over the 37 stable components. Two results either have the same visitor id or not.

It describes a browser setup, not a person: two identical devices can share one, and one person with two browsers has two. It is `null` without Web Crypto, and comparable only within the same idVersion and signalsVersion.

See: [visitorId](https://whiskerjs.com/docs/identifiers/#visitorid), [Structured id](https://whiskerjs.com/glossary/#structured-id).

## Web Crypto

Web Crypto is the browser’s built-in cryptography API, `crypto.subtle`. WhiskerJS uses only its `digest` function, for SHA-256.

It exists only in secure contexts. Without it, WhiskerJS never sends a raw large value: such components become `unavailable` with ruleId `no_digest`, and both ids are `null`.

See: [Hashing](https://whiskerjs.com/docs/how-it-works/#hashing), [Secure context](https://whiskerjs.com/glossary/#secure-context).

## WebDriver

WebDriver is the standard protocol that tools such as Selenium use to control a browser. A browser under WebDriver control sets `navigator.webdriver` to `true`; Playwright and Puppeteer set it by default too.

WhiskerJS sets `automation_webdriver` when `navigator.webdriver` is `true`, and `webdriver_writable` when the property was redefined, usually to hide automation. Your own end-to-end tests set the first flag as well.

See: [automation_webdriver](https://whiskerjs.com/docs/integrity/#automation_webdriver), [webdriver_writable](https://whiskerjs.com/docs/integrity/#webdriver_writable).

## WebGPU

WebGPU is a newer browser API for graphics and computation on the GPU, reached through `navigator.gpu`. Its adapter describes the GPU and its features and limits.

WhiskerJS’s `webgpu` component calls `requestAdapter()` (no prompt, no device requested) and hashes the adapter’s info, sorted features and seven limits. Without the API it is `unavailable`.

See: [webgpu](https://whiskerjs.com/signals/webgpu/).
