Fingerprint

What Is Font Fingerprinting? How Websites Detect Your Installed Fonts

Websites can detect installed fonts and text metrics to identify your browser and operating system. Learn what font fingerprinting reveals and how to reduce font-based tracking.

Documentation

Prefer the maintained product doc?

This article has a matching page in the docs center. Use the docs for the canonical setup flow, current flags, and long-term reference.

Introduction

Font fingerprinting lets websites infer your operating system, software stack, and even parts of your work environment without asking for permission. By checking which fonts are installed and how text measures on the page, a tracker can build a surprisingly stable picture of the browser behind the session.

This guide explains the two practical parts of font fingerprinting: installed font detection and text-metric measurement. It also shows why superficial JavaScript overrides usually fail and what it takes to keep font-related output consistent.

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:

  1. Create a hidden HTML element with a known fallback font (monospace, serif, or sans-serif).
  2. Measure its rendered width and height.
  3. Change the font-family to a candidate font plus the fallback.
  4. 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 like width, actualBoundingBoxAscent, actualBoundingBoxDescent, fontBoundingBoxAscent, and fontBoundingBoxDescent. 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() and getClientRects() 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.fonts API 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() and getClientRects() 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-rects and --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. The expand option 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=expand or real, 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. See the full feature list for all rendering controls, or verify font consistency in the Proof Center.

For related topics, see What is Browser Fingerprinting, CSS Signal Consistency, Canvas Fingerprinting, and Screen and Window Protection.

#Fonts#Fingerprinting#Text-Metrics#Privacy#Font Enumeration#Browser Fingerprint#Tracking Prevention

Take BotBrowser from research to production

The guides cover the model first, then move into cross-platform validation, isolated contexts, and scale-ready browser deployment.