Font Fingerprinting: How Installed Fonts Identify Your Browser
How font enumeration and text metric measurement create unique browser fingerprints, and techniques to control font identity at the engine level.
Introduction
Every operating system ships with a different set of fonts. Users install additional fonts for work, design, or personal preference. This combination of installed fonts creates a surprisingly unique identifier. Websites can probe which fonts are available by measuring how text renders at specific sizes, and the resulting list of detected fonts forms a font fingerprint. Beyond the font list itself, text metrics like glyph widths, heights, and bounding boxes vary across platforms and font rendering engines. Together, font enumeration and text metrics give tracking systems a stable, high-entropy signal that persists across sessions. This article explains how font fingerprinting works and how BotBrowser controls font identity at the engine level.
Privacy Impact
Font fingerprinting has been a reliable tracking vector for over a decade. The EFF's Panopticlick study found that the set of installed fonts was one of the highest-entropy browser attributes, capable of uniquely identifying over 80% of browsers in their dataset. A 2016 study from the University of Adelaide confirmed that font lists provide 8 to 10 bits of identifying information on average, and significantly more for users with specialized software (designers, developers, users with CJK language packs).
The problem has grown as operating systems have diversified. Windows, macOS, and Linux each ship different default font sets, and each OS version changes the defaults. Windows 11 includes fonts that Windows 10 does not. macOS Sonoma differs from macOS Ventura. These differences mean that font fingerprinting can often identify your exact operating system version, narrowing the population before any other signal is considered.
Corporate environments add another dimension. Enterprise font licenses (Helvetica Neue, Futura, proprietary brand fonts) create distinctive fingerprints tied to specific organizations. Creative professionals with Adobe Fonts or Google Fonts installed have uniquely large font sets.
Technical Background
Font fingerprinting relies on two primary techniques.
Font Enumeration via Measurement
Browsers do not expose a direct API to list installed fonts (the deprecated document.fonts.check() approach has limited coverage). Instead, tracking scripts use a measurement-based technique:
- Create a hidden HTML element with a known fallback font (monospace, serif, or sans-serif).
- Measure its rendered width and height.
- Change the font-family to a candidate font plus the fallback.
- Measure again. If the dimensions change, the candidate font is installed.
By testing hundreds of font names, a script can build a binary vector of installed/not-installed fonts. This vector is the font fingerprint.
Text Metrics Fingerprinting
Beyond the font list, the precise measurements of text rendering vary by platform. These include:
- Canvas text metrics. Using
measureText()on a Canvas 2D context returns properties likewidth,actualBoundingBoxAscent,actualBoundingBoxDescent,fontBoundingBoxAscent, andfontBoundingBoxDescent. These values depend on the font rendering engine (DirectWrite on Windows, CoreText on macOS, FreeType on Linux), hinting settings, and subpixel rendering configuration. - Element bounding boxes.
getBoundingClientRect()andgetClientRects()return dimensions that vary based on font shaping, kerning tables, and layout engine behavior. - OffscreenCanvas text rendering. Text drawn to an OffscreenCanvas produces pixel data that varies by platform, providing another measurement vector.
The combination of font list and text metrics creates a compound fingerprint with very high entropy.
Why Output Varies
Font rendering is a complex process involving multiple layers:
- Font file format. TrueType and OpenType fonts contain different hinting instructions that affect rendering at small sizes.
- Rendering engine. DirectWrite (Windows), CoreText (macOS), and FreeType (Linux) each implement text shaping, hinting, and rasterization differently.
- Subpixel rendering. ClearType (Windows), subpixel antialiasing (macOS), and various FreeType configurations produce visibly different output at the sub-pixel level.
- DPI and scaling. High-DPI displays affect text metrics through device pixel ratio scaling.
Common Protection Approaches and Their Limitations
Blocking font enumeration is impractical because the technique uses standard CSS and DOM measurement APIs. You cannot block getBoundingClientRect() without breaking web layout.
Installing more fonts to blend in actually backfires. A system with 500 fonts is more unique than one with the OS defaults. The font fingerprint becomes more distinctive, not less.
Browser extensions that claim to protect font fingerprints typically work by injecting CSS overrides or intercepting measurement APIs. These approaches are fragile. An extension might override measureText() but miss getClientRects(). Or it might report a generic font list while the actual rendering uses the real fonts, creating a detectable inconsistency.
Randomizing text metrics breaks web applications. Many sites rely on accurate text measurements for layout calculations, text editors, and responsive design. Random values cause visual glitches and broken layouts.
Using a minimal font set (like Tor Browser does) reduces uniqueness but creates a distinctive profile of its own. A browser with exactly the Tor Browser font set is identifiable as likely being Tor.
BotBrowser's Engine-Level Approach
BotBrowser controls font fingerprinting at the Chromium engine level through two mechanisms: font list management and text rendering control.
Controlled Font Lists
When a fingerprint profile is loaded, BotBrowser configures the font subsystem to report exactly the fonts that the profiled device would have. This is not a CSS override or JavaScript interception. The browser's internal font enumeration returns the profile's font list. When a website probes for a specific font, the response (installed or not installed) matches the profiled system.
This covers:
- System font enumeration results
- CSS font-family resolution order
document.fontsAPI responses- Font fallback chain behavior
Text Metrics Consistency
BotBrowser's profile system includes text metric data for the target platform. When text is measured through any API, the results are consistent with the profiled device's font rendering engine:
measureText()returns metrics matching the profiled platform's text shaping and hinting.getBoundingClientRect()andgetClientRects()return dimensions consistent with the profiled rendering engine.- Canvas text rendering produces pixel output matching the profiled platform.
- Client rect noise (controlled via
--bot-config-noise-client-rectsand--bot-config-noise-text-rects) adds deterministic variation when enabled.
Cross-Platform Font Emulation
A key strength of BotBrowser's approach is cross-platform font emulation. Running on Linux, you can load a Windows profile and get Windows-typical font lists and text metrics. The font fingerprint matches a real Windows system, not a Linux system pretending to have Windows fonts.
This is possible because BotBrowser controls font rendering at the engine level, not through font file installation. You do not need to install Windows fonts on your Linux system.
Configuration and Usage
Basic Font Protection
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Font Configuration Options
# Use profile's font settings (default, recommended)
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-fonts=profile
# Profile fonts plus system fallback fonts
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-fonts=expand
# Use real system fonts (no font protection)
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-fonts=real
Controlling Text Metric Noise
# Enable client rect noise for measurement variation
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-noise-client-rects=true \
--bot-config-noise-text-rects=true \
--bot-noise-seed=42
Playwright Integration
const { chromium } = require('playwright');
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-config-fonts=profile',
'--bot-noise-seed=42'
]
});
const page = await browser.newPage();
await page.goto('https://example.com');
Puppeteer Integration
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({
executablePath: '/path/to/botbrowser/chrome',
defaultViewport: null,
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-config-fonts=profile',
'--bot-noise-seed=42'
]
});
const page = await browser.newPage();
await page.goto('https://example.com');
Verification
Font list check. Use a fingerprint testing site to see which fonts are detected. The list should match the profile's target OS and configuration, not your actual system.
Text metrics check. Measure a standard string (e.g., "Hello World" in 16px Arial) using measureText() and compare the results across sessions and machines. With the same profile and noise seed, values should be identical.
Platform consistency check. If you are loading a Windows profile on Linux, verify that the detected fonts are Windows-typical (Segoe UI, Calibri, Consolas) rather than Linux-typical (Liberation Sans, DejaVu Sans).
Cross-API check. Compare font detection results from CSS measurement, Canvas measureText(), and getClientRects(). All should be consistent with the same font set.
Best Practices
- Use
--bot-config-fonts=profile(default). This provides the most complete font protection. Theexpandoption adds system fonts as fallbacks, which can introduce local variation. - Combine font protection with canvas noise. Text metrics and canvas rendering are closely related. Enable both for comprehensive protection.
- Use profiles matching your target region. CJK font sets, RTL fonts, and locale-specific defaults vary significantly. Use a profile that matches your expected locale.
- Test with multiple font probe lists. Different tracking systems probe different font lists. Verify your protection against several testing tools.
- Avoid installing distinctive fonts. If using
--bot-config-fonts=expandorreal, unusual fonts on your system will be detectable.
FAQ
Q: How many fonts do tracking scripts typically probe? A: Common fingerprinting libraries test between 50 and 500 font names. Some comprehensive scripts probe over 1,000 fonts targeting specific platforms and software installations.
Q: Does BotBrowser embed actual font files in the profile? A: BotBrowser's profiles contain the information needed to control font enumeration and text metric behavior. The engine produces measurements consistent with the profiled platform without requiring actual font file installation.
Q: Can font fingerprinting identify my specific OS version? A: Yes. Default font sets change between OS versions. Windows 11, Windows 10, macOS Sonoma, and macOS Ventura each have different default fonts. Tracking systems maintain databases mapping font sets to OS versions.
Q: What is the expand font mode for?
A: The expand mode uses the profile's font list as the primary set and adds system fonts as fallbacks. This is useful if your application requires specific system fonts for rendering but you still want profile-based font enumeration.
Q: Does font protection affect web font loading? A: No. Web fonts downloaded from servers (via @font-face) are unaffected by font fingerprint protection. Only local/system font detection is controlled.
Q: Are text metrics consistent between headless and headed mode? A: Yes. BotBrowser controls text metrics at the engine level regardless of display mode.
Summary
Font fingerprinting combines font enumeration and text metric measurements to create a high-entropy tracking signal that varies across operating systems, versions, and individual installations. BotBrowser controls both the reported font list and the text rendering metrics at the engine level, producing results consistent with the loaded profile regardless of your actual system fonts. With --bot-config-fonts=profile and --bot-noise-seed, font fingerprints are stable, consistent, and authentic.
For related topics, see What is Browser Fingerprinting, CSS Signal Consistency, Canvas Fingerprinting, and Screen and Window Protection.