The Local Font Access API permission is called local-fonts, and it keeps your font list behind a prompt. A page calls window.queryLocalFonts(), the browser asks you, and only a yes returns the fonts. The older trick, measuring text in each font a script wants to test, needs no permission at all. So the prompt changes what a polite page has to do far more than what a tracker can learn.
What queryLocalFonts() hands over
The call returns a promise of FontData objects, one per installed font face. Each carries four names: postscriptName, fullName, family and style. Each also has a blob() method that returns the font file's raw bytes, the SFNT data a design tool needs to render or edit it. A page that only wants a few faces can pass { postscriptNames: [...] } and get just those back.
That is a different kind of answer from what fingerprinting scripts usually collect. A measuring script can only test names it already has on a list, so a font you installed from a small foundry, or one that came with some audio software, goes unseen unless the script happens to guess it. The API has no list to guess from. It returns everything the operating system reports, including the faces nobody would think to test.
The three gates on the Local Font Access API
The WICG specification and Chromium put three checks in front of that list, and a page has to pass all of them.
- A user gesture. The call has to come from a real click or key press. A script that runs on page load and calls it gets nothing.
- The
local-fontspermission. The browser asks the person. Chrome remembers the answer for that site, so the next visit does not ask again. - Permissions-Policy. The
local-fontsdirective defaults toself. A cross-origin iframe, such as an embedded ad or a third-party widget, cannot call it unless the page that embeds it grants access withallow="local-fonts". Where the policy blocks it, the promise rejects with aSecurityError.
Each gate makes sense for the use the API was written for: a web design tool that wants your real fonts in its menu. You click "Use my fonts", you see the prompt, you say yes.
Every profile is drawn from one real computer, not from separate listsIn Mosaic: Machines that exist. GPU, screen, CPU and fonts from one real device. Free holds 3 profiles. Pro is $49 a month for any number.
Mosaic is a desktop app
Email yourself the link and open it on your computer.
How it works: Machines that exist
The bit a site can read without asking
One thing leaks without any prompt. navigator.permissions.query({ name: 'local-fonts' }) returns granted, prompt or denied, and calling it shows nothing to the user. It only reports the decision for the site that asks, so it says nothing about what you told anyone else. A fresh browser answers prompt.
That default matters more than it looks. We learnt it on a different permission: Notification.permission read denied on all 344 profiles on our build Mac, because one content setting was forced for every launch, while an unconfigured Chrome says default. Nothing about the host leaked out. One value was pinned across every profile, and a site reads that as well as a leak (the notification story has the details). So Mosaic leaves local-fonts exactly where stock Chrome leaves it, and a new profile answers prompt.
Why the prompt does not stop font fingerprinting
A tracker never needs the prompt. It draws a test string in a generic family, records the width and height, then draws it again with the candidate font first and the generic family as fallback. A different size means the font is installed. It runs in a hidden element, on page load, in every browser, and asks nobody. How websites list your fonts without a font API walks through the script line by line.
So the permission blocks the honest route and leaves the quiet one open. A script that calls queryLocalFonts() is announcing itself with a dialog, which is the last thing a tracker wants. What the gate really protects is the long tail: the faces that are not on any candidate list, and the font files themselves.
What a profile's fonts are in Mosaic
In Tesseract Chrome, the font list a page finds is this computer's own. That was not always so. Our engine used to hide about 2% of font families per profile, so two profiles on one machine would report different lists. Pixelscan read that as masking. We bisected it on one profile with controls at both ends, and only the font hiding flipped the verdict, so patch 0131 removed it. Pixelscan's masking verdict, bisected has the run. The per-profile jitter on glyph widths stayed, because it changes the exact sizes a page measures without changing which fonts exist.
That changes what granting local-fonts means. In a profile it hands the site the real list of this computer, the same list every other profile here would return. If a site needs it, a font picker in a design tool for example, grant it in that profile and nowhere else. The grant is remembered per site and per profile, and permissions.query will report it on every later visit. What tells two profiles apart is the rest of the browser fingerprint and above all their separate cookie jars.





