Signals · WhiskerJS 0.1.0

Signals

All 46 components of signalsVersion 5, sorted by the identifier group they belong to, each with its own page.

In plain words

A signal (WhiskerJS calls it a component) is one small measurement of the browser and device, such as the screen size, the time zone or how a test image is drawn. One signal alone says little; together they tell browser setups apart. WhiskerJS reads 46 of them, sorts the 37 that rarely change into seven groups, and keeps the 9 that change easily out of the identifiers. It never decides what a signal means: your server does.

How to read a signal page

Every signal page has the same parts, so you can compare them:

  • Facts box (at the top): the group, whether the signal is in the visitorId, how it is hashed, whether a browser class excludes it, and the signalsVersion that added it. It is generated from the library’s code.
  • What it reads: the exact browser API and what is taken from it.
  • How the technique works: the method, step by step.
  • Why it helps: what makes it differ between devices.
  • Stability: what makes it change on the same device.
  • Browser support and what blocks it: where it is usually ok, and what it reports elsewhere.
  • Privacy: what the value can reveal and how WhiskerJS limits that.
  • How WhiskerJS handles noise and failures: the statuses and ruleIds this component can really report.
  • Example value: the shape of a real value.

If you would rather read everything on one page, use the signals reference.

The groups at a glance

The structuredId has one part per signal group. When two results differ, the group that moved tells you what kind of change happened. Columns: In visitorId says whether the component joins both ids; Always hashed says whether the value always leaves the library as a digest (other values are hashed only when longer than 128 characters or not printable ASCII).

gpu: graphics

Graphics output depends on the GPU, its driver, the operating system and the browser’s rendering engine together. It is the most distinguishing group and also the one most likely to move after a driver or browser update.

Component Group In visitorId Always hashed
canvas gpu yes yes
webgl_image gpu yes yes
webgl_params gpu yes yes
webgl_renderer gpu yes no
webgl_vendor gpu yes no
webgpu gpu yes yes

audio

One offline audio render. Nothing is played and no audio device is opened.

Component Group In visitorId Always hashed
audio audio yes yes

fonts

Installed fonts and default font settings, which follow the operating system, its language packs and installed software.

Component Group In visitorId Always hashed
font_preferences fonts yes yes
fonts fonts yes yes (none plain)
fonts_canvas fonts yes yes (none plain)

device: screen, memory and CPU

Hardware facts the browser reports: screen size, colour depth, CPU threads and family, memory buckets and touch support.

Component Group In visitorId Always hashed
color_depth device yes no
cpu_architecture device yes no
device_memory device yes no
hardware_concurrency device yes no
heap_limit device yes no
screen_resolution device yes no
touch_support device yes no

browser: engine and build

What the browser is and how it was built: its class, its maths and codec support, plugins, Client Hints and browser-specific globals. This group usually moves after a browser update.

Component Group In visitorId Always hashed
apple_pay browser yes no
browser_class browser yes no
math browser yes yes
media_codecs browser yes yes
pdf_viewer browser yes no
platform browser yes no
plugins browser yes yes (none plain)
private_click browser yes no
storage browser yes no
ua_client_hints browser yes no
vendor browser yes no
vendor_flavors browser yes no

locale

Language, locale and time zone settings. They move when a user changes them or travels.

Component Group In visitorId Always hashed
intl_locale locale yes no
languages locale yes no
time_zone locale yes no

prefs: display and accessibility preferences

Five CSS media queries about the screen and the user’s accessibility settings. Each reports the first option that matches.

Component Group In visitorId Always hashed
color_gamut prefs yes no
dynamic_range prefs yes no
forced_colors prefs yes no
prefers_contrast prefs yes no
reduced_motion prefs yes no

Not in either id

These nine are reported so your server can use them, but they change too easily (zoom, taskbar, permission grants, keyboard layout, late-loading voices, browser versions, audio output, content blockers) to be part of an identifier. Changing them never changes the visitorId or the structuredId.

Component Group In visitorId Always hashed
audio_latency none no no
canvas_readback none no no
content_blockers none no no
keyboard_layout none no no
permissions none no yes
pixel_ratio none no no
screen_frame none no no
speech_voices none no yes (none plain)
ua_versions none no no

What every signal has in common

  • Always present. Every one of the 46 components is in every result with exactly one status: ok, unavailable, blocked, noisy, excluded or timed_out. A non-ok status carries a short ruleId saying why. See Statuses and reason codes.
  • Its own clock. Each component has an inner timeout of 1000 ms, and the whole call has a budget (timeoutMs, 5000 ms by default).
  • No prompts, no network, no storage. No signal asks for a permission, makes a request or writes anything. See Privacy.
  • Excluded where a browser randomises it on purpose. Brave’s farbling and Firefox resistFingerprinting remove some components through the exclusion table, instead of WhiskerJS working around them.

Left out on purpose

WebRTC (even without addresses), media device lists, network information, battery, geolocation, storage quota and user-agent parsing are not collected, because they need a network-capable API, a permission-coupled API or console output, or because they change too easily. See the Signals reference.

Questions and answers

How many signals does WhiskerJS read?

46 components at signalsVersion 5. 37 of them are stable and make up the visitorId and the seven parts of the structuredId; the other 9 are reported but kept out of both ids.

Can I turn a signal off?

Yes. Pass its name in collect({ exclude: [...] }). It then reports status excluded with ruleId caller_excluded, and a stable component counts as missing in both ids, so a different exclude list gives different ids.

Are the uniqueness or entropy of each signal measured?

Not yet. No per-signal entropy or uniqueness figure for WhiskerJS has been measured, so these pages describe why a signal tends to differ between devices without giving numbers.