How font enumeration works
The classic technique sets an element’s text in three generic fallbacks (monospace, sans-serif, serif), records the rendered width and height, then re-renders the same string asking for a candidate font with the generic as fallback (e.g. "Calibri", monospace). If the dimensions change, the candidate font exists and was used; if they match the fallback, it is not installed. Repeating this across a list of a few hundred fonts yields the installed set.
Modern variants skip the DOM entirely and measure with CanvasRenderingContext2D.measureText() on an offscreen canvas, which is faster and harder to interfere with. The output is hashed alongside the other signals into the overall browser fingerprint.
Why scrapers get caught
A fresh Linux container running headless Chrome ships with a tiny, well-known font set (often just DejaVu and a couple of Noto families). Real Windows and macOS machines have dozens of system fonts plus whatever applications installed. Anti-bots keep a catalogue of “default server” font sets and flag them. Worse, a mismatch between the claimed OS in the User-Agent and the font set (UA says Windows, fonts say Linux) is a direct contradiction a lie detector will catch.
Spoofing the font list in JavaScript is fragile: the metrics still come from the real renderer, so claiming a font exists while measureText returns fallback dimensions is itself anomalous. Durable fixes install a real font set at the OS/FontConfig level or use a patched browser like Camoufox.
Passing font checks without faking it
Because the metrics come from the real rasteriser, JavaScript-level spoofing of measureText or the font list is brittle — the claimed list and the measured glyph widths drift apart and that contradiction is the tell. The durable fix is to make the font set real: install a font package at the OS / FontConfig level that matches the operating system your User-Agent claims, so a "Windows" identity actually carries Segoe UI, Tahoma and the rest of the expected Windows families.
This is exactly the kind of signal a patched browser like Camoufox handles at the engine layer rather than with a content script, keeping the rendered metrics and the reported font set coherent. If you are scraping through a managed web scraping API, fonts are part of the device profile the provider maintains, so you inherit a consistent set instead of the bare DejaVu-only fingerprint of a fresh Linux container.
