Signal

Font detection

Determines which fonts from a curated 88-entry list are installed at the OS level by comparing rendered span dimensions against a monospace baseline — stable across browser engines on the same machine.

Tier 1 hardware src/signals/fonts.ts

What it measures

The signal tests 88 font names drawn from a curated cross-platform list covering Windows (24), macOS (43), Linux (17), and Android (4). For each font, a hidden span is rendered at 72px with the test string 'mmmmmmmmmmlli' using that font as the primary family and monospace as the fallback. If the rendered dimensions differ from the pure-monospace baseline, the font is considered installed.

The resulting 88-bit presence bitmap is encoded as pipe-delimited '1'/'0' tokens and hashed with xxHash64. Because fonts are installed at the OS level — not the browser level — the same presence set is reported by Chrome, Safari, and Firefox on the same machine, making the signal hardware-bound.

How it's collected

The collector creates a hidden container div positioned at -9999px with visibility hidden and appends it to document.body. A baseline span is rendered with font-family monospace at 72px and the test string 'mmmmmmmmmmlli'; its offsetWidth and offsetHeight are recorded. For each of the 88 test fonts, a new span is rendered with font-family set to the quoted font name followed by monospace fallback; if its dimensions differ from the baseline, the font is marked present.

The collector yields to the main thread after every 10 fonts (using scheduler.yield() on Chrome 115+ or setTimeout 0 as a fallback) to avoid blocking the UI. The hidden container is removed from the DOM in a finally block. If document is undefined, the result is absent immediately.

Confidence rules

ConfidenceTrigger
normaldetectFontsViaMeasurement() returned a non-null boolean array
absentdocument is undefined, or any unhandled exception

Why hardware-bound

Font measurement relies solely on offsetWidth and offsetHeight of DOM spans, which is deterministic across all browser engines for a given installed font set. Chrome, Safari, and Firefox all perform the same comparison: rendered span vs. fallback baseline. Because installed fonts are an OS and hardware property — not a browser property — the presence bitmap is stable across browsers on the same device.

The document.fonts.check() API was considered and rejected. In Chrome it returns true for any syntactically valid font-family name because it silently falls back, causing false positives across the entire list. Dimension measurement is the only reliable installed-font test.

Things worth knowing

  • The hash encodes the full 88-bit presence bitmap, not just the detected font names. Two devices with different installed font sets but the same count of detected fonts will produce different hashes.
  • With 88 fonts and a yield at every 10th iteration (when idx > 0 and idx % 10 === 0), there are 8 yield points per collection run (at idx = 10, 20, 30, 40, 50, 60, 70, 80).
  • Firefox resistFingerprinting does not interfere with offsetWidth/offsetHeight of hidden spans. The signal returns normal even when resistFingerprinting is active.
  • Brave Standard mode does not farble font enumeration because it is dimension-based rather than canvas-based. The signal is unaffected by Brave privacy settings.
  • In SSR or non-browser environments where document is undefined, the signal returns absent immediately without attempting measurement.