Font fingerprinting: how your installed fonts give you away

The set of fonts installed on your machine is one of the most identifying things about your browser, and almost nobody thinks about it. Install Microsoft Office and you gain dozens of fonts. Install Adobe Creative Cloud and you gain dozens more. Add a language pack, a design tool, or a game, and your font list drifts further from everyone else's. This article explains exactly how websites read that list, why it carries so much entropy, the measurement techniques old and new, and the defences that work.

Why your font list is so revealing

Fonts arrive on your system from many sources, and the combination is rarely shared. Out of the box, Windows, macOS, and the major Linux distributions each ship a different base set. On top of that, applications install their own: Microsoft Office adds families like Calibri, Cambria, and a long tail of others; Adobe applications bundle source and commercial faces; LibreOffice, design suites, and even some browsers add more. Language and region packs add scripts for Chinese, Japanese, Korean, Arabic, and others.

The result is that two people with the same operating system and browser can still have completely different font lists because one installed Office and a CJK pack while the other installed Adobe tools and a coding font. Studies of real-world fingerprints have repeatedly found the font list among the highest-entropy attributes available, frequently contributing more than ten bits of identifying information on a machine with productivity or creative software. privacyscore.dev flags a long or unusual font list as one of the heaviest contributors to a high uniqueness score, precisely because it tends to encode your software history.

The old way: the Flash enumeration era

Before browsers locked things down, the easiest attack was through plugins. Adobe Flash and, on some platforms, Java exposed an API that returned the full list of installed system fonts directly, names and all, with no measurement trickery required. A script could call it and receive a complete, ordered inventory in one step. This was devastating for privacy and trivial to implement.

Flash reached end of life at the end of 2020 and Java applets are long gone from the web, so this direct route is closed. But its disappearance pushed fingerprinters toward indirect measurement techniques that work entirely within standard web APIs, which is what they use today.

The modern way: measuring text dimensions in JavaScript

The dominant technique no longer asks for the font list. It infers it by measuring how text is rendered. The method exploits a simple fact: if you ask the browser to render text in a font that is not installed, it silently falls back to a default font, and the rendered text has different dimensions than it would in the real font.

The fallback-comparison trick

The classic implementation works like this:

  • Render a string in each of the three generic CSS font families — monospace, sans-serif, and serif — and record the width and height of the resulting text. These are your baselines.
  • For each candidate font you want to test, render the same string requesting that font with a generic fallback, for example font-family: 'Calibri', monospace.
  • If the measured dimensions differ from the monospace baseline, the browser actually used Calibri, so it is installed. If the dimensions match the baseline exactly, the browser fell back, so Calibri is absent.

Dimensions are read with the DOM, by placing text in an off-screen element and reading offsetWidth and offsetHeight, or with the Canvas API, by drawing text and reading measureText().width. A script can test a list of several hundred well-known fonts in a few milliseconds, building a present/absent vector that becomes a stable fingerprint.

Font-face probing and unicode-range

A subtler variant uses CSS @font-face with the local() source to ask for a specific named font, combined with the unicode-range descriptor and load events, to detect whether a named local font exists. Because these checks can be driven by the CSS Font Loading API, which exposes load success or failure, a script can confirm specific fonts without rendering visible text. Either way, the outcome is the same: a list of which named fonts your system has.

It is not only which fonts, but how they render

Font fingerprinting overlaps with canvas fingerprinting because the same font can render with slightly different pixel metrics across operating systems, versions, and rendering engines. Anti-aliasing, hinting, and subpixel rendering differ between Windows DirectWrite, macOS Core Text, and Linux FreeType. So even two users who both have a given font can be distinguished by the exact width their browser reports for a string in it. This is why font and canvas signals are often collected together and why simply hiding the font list is not a complete defence.

How to test your own exposure

You do not have to take this on faith. Open your browser's developer console and you can reproduce the measurement: create a hidden span, set its text, switch its font-family between a generic family and a target font, and compare offsetWidth. If the width changes, the font is installed. Running a few dozen common names by hand will quickly show how many distinctive fonts your machine carries. A privacy testing tool such as privacyscore.dev automates this against a large candidate list and reports the resulting entropy, so you can see whether your font list alone makes you identifiable.

Defences that work

Use a browser with a standardised font set

The Tor Browser takes the strongest approach: it ships with its own bundled set of fonts and prevents pages from using any locally installed fonts at all. Every Tor Browser user therefore presents the same font list regardless of what is installed on their machine, collapsing this entire signal to near-zero entropy. This is the single most effective defence, because it makes you identical to everyone else running the same configuration.

Browsers that limit or standardise enumeration

Some browsers restrict font visibility. Recent versions of Safari and WebKit limit pages to a curated set of system fonts plus web fonts, so locally installed extras are not detectable. Firefox's fingerprinting-resistance mode (privacy.resistFingerprinting) and its newer fingerprinting protection restrict font enumeration and normalise text-metric measurements. Brave applies randomisation and limits font visibility on some platforms. Choosing one of these and leaving the protection enabled removes most of the risk without manual effort.

Font allowlisting

An allowlist approach limits which fonts web pages may access to a small, common base set, hiding everything your applications installed. Some privacy browsers implement this internally; on a managed system an administrator can restrict the fonts exposed to the rendering engine. The principle is to present only fonts that nearly everyone has, so your list carries little entropy.

Practical habits

  • Do not install fonts you do not need. Every decorative font you add to admire in a document is a bit of entropy a tracker can read.
  • Keep a privacy browser separate from your work browser. Do your sensitive browsing in Tor Browser or a hardened configuration, and keep the font-heavy work machine for tasks where you are already identified anyway.
  • Re-test after changes. Installing Office or a design suite can noticeably raise your uniqueness. Measure before and after so you know what a new application cost you.

Font fingerprinting is quiet, fast, and persistent, and it survives clearing cookies because it reflects your software rather than stored data. The good news is that it is also one of the few high-entropy signals that a well-chosen browser can almost completely neutralise. If you only fix one thing, fixing your font exposure is among the highest-value moves available.