Signal · signalsVersion 5

font_preferences

The width of one sentence in seven default font settings, including the minimum font size, as a digest.

font_preferences at a glance (from the library code, signalsVersion 5)
Component namefont_preferences
In the visitorIdyes
structuredId groupfonts
Hashingalways a digest (first 128 bits of SHA-256)
Excluded underno browser class
Inner timeout1000 ms
Added insignalsVersion 3
In plain words

Browsers let people choose their default fonts and a minimum text size, and the operating system has its own system font. WhiskerJS writes one sentence in each of these defaults, invisibly, and measures how wide it is. The widths follow the user’s settings and the system, and only a short code of them is kept.

What it reads

Seven hidden <span> elements with the text “Whiskers quietly judge 0123456789”, in one off-screen container (left: -9999px, visibility: hidden) appended to the body and removed in a finally block:

Name Style
default no font family (the browser default)
serif font-family: serif
sans font-family: sans-serif
mono font-family: monospace
system font-family: system-ui
apple font-family: -apple-system
min browser default family at font-size: 1px

Each span’s offsetWidth is read and the seven widths are written as default=…;serif=…;…;min=… and hashed.

How the technique works

Each generic family name maps to a concrete font chosen by the browser settings and the operating system. Measuring the same text in each reveals that mapping without asking for it. -apple-system resolves only on Apple platforms, so its width differs elsewhere. The 1 px span is drawn at the browser’s minimum font size. If every width is zero, nothing was laid out and the result is unavailable / no_layout.

Why it helps

Users rarely change these settings, but when they do the values differ clearly, and operating systems differ in their default and system fonts. It is part of the fonts group of the structuredId.

Stability

It changes when the user changes the default fonts, the default font size or the minimum font size, or when an operating system or browser update changes the system font or the fonts the generic names map to. The page’s own styles do not matter much, because each span sets its own family and the container sits outside the page flow.

Browser support and what blocks it

ok in every browser with a document and layout; not in the exclusion table. unavailable / no_document before document.body exists, no_layout when the body is not laid out. See the browser pages for each family.

Privacy

It reveals font settings, not content. Only a digest leaves the library. The spans are invisible and removed at once. No permission, no prompt, no request.

How WhiskerJS handles noise and failures

Status ruleId When
ok none value is a digest
unavailable no_document no document or body
unavailable no_layout all widths were zero
unavailable no_digest no Web Crypto
blocked security_error, threw the DOM work threw
excluded caller_excluded your exclude list
timed_out timeout, aborted 1000 ms inner timeout, budget, abort

Example value

From a headless Chromium test browser in a container:

"font_preferences": { "status": "ok", "value": "374bafbd56b68b15ac31e242b3cc90f7", "hashed": true }

Questions and answers

What does the 1 px measurement show?

Browsers enforce a minimum font size setting. Text asked for at 1 px is drawn at that minimum, so its width reveals the setting.

Is font_preferences excluded anywhere?

No. It is not in the exclusion table, so it is read in every browser class, including Brave and Firefox resistFingerprinting.