Как браузер определяет установленные шрифты и формирует font fingerprint

Font fingerprint - это набор признаков локальных шрифтов, по которым сайт может отличить одно браузерное окружение или устройство от другого. Сайты используют его для проверки верстки и дополнения browser fingerprint, но результат зависит от разрешений и защиты браузера.
Как и почерк, один и тот же текст имеет разную форму и ширину. Разберемся, как это проверить.
Могут ли сайты определять установленные шрифты
Да, но в основном косвенно. Без явного разрешения сайт не может читать вашу папку со шрифтами и не получает перечень файлов с диска. Он сравнивает, как браузер отрисовывает одну и ту же строку разными гарнитурами, и по разнице ширины, рамки текста или пикселей делает вывод, что конкретный шрифт вероятно доступен. Это эвристика, поэтому возможны ложные результаты: установленный шрифт с метриками, близкими к fallback, может остаться незамеченным, а псевдонимы названий и другие особенности подбора шрифтов усложняют интерпретацию.
Прямой перечень существует только в десктопном Chromium через queryLocalFonts(), и он требует явного разрешения пользователя и временной активации (transient user activation), например клика. У Firefox и Safari этого API нет, а WebKit дополнительно скрывает от сайтов шрифты, которые пользователь установил сам. Поэтому ответ зависит от браузера: в одном случае сайт видит только косвенные признаки, в другом после разрешения получает полный доступный ему список.
Что именно видит сайт при проверке локальных шрифтов
Без разрешения страница не получает доступ к C:\Windows\Fonts или каталогу Font Book. Она видит косвенные признаки данных шрифта по внешнему виду текста.
Источником может быть ОС, локальная установка или @font-face. Общие семейства serif, sans-serif, monospace, cursive, fantasy и system-ui не указывают на конкретный файл. cursive означает рукописный стиль, fantasy - декоративный; конкретную гарнитуру выбирают ОС и браузер.
Это называется font matching. При отсутствии подходящего варианта браузер берет fallback, то есть запасной шрифт. Глиф - это отрисованная форма символа.
Браузер может:
- выбирать шрифт по CSS-имени
- получать метрики: ширину, высоту и положение букв
- загружать веб-шрифт
- возвращать локальные шрифты, открытые этому браузеру и сайту, через
queryLocalFonts()после разрешения
Готовность текста к показу еще не доказывает, что Arial есть на диске.
Как сайты определяют шрифт без запроса разрешения
Скрипт перебирает названия и сравнивает размеры или пиксели текста. Canvas fingerprinting работает похожим образом, но геометрия и пиксели дают разные сигналы.
Как работает сравнение с fallback
Браузер отрисовывает строку с fallback-шрифтом и с кандидатом, затем сравнивает их:
- Возьми широкие и узкие символы, например
mmmmmmmmmmlliWW@@. - Измерь их в
monospace,serifиsans-serif. - Поставь нужное имя перед каждым fallback.
- Сравни ширину и bounding box, то есть рамку вокруг текста.
- Отметь шрифт как вероятно доступный, если изменилась хотя бы одна пара.
Но одинаковые метрики у разных гарнитур могут приводить к ложноотрицательным результатам. Несколько fallback-шрифтов, размеров и проверка высоты снижают число ошибок, но не открывают весь каталог.

Что делает этот код: невидимо отрисовывает одну и ту же строку разными шрифтами и сравнивает их размеры. Для понимания принципа запускать код не обязательно.
const ctx = document.createElement("canvas").getContext("2d");
const sample = "mmmmmmmmmmlliWW@@";
const fallbacks = ["monospace", "serif", "sans-serif"];
function metrics(fontStack) {
ctx.font = `72px ${fontStack}`;
const m = ctx.measureText(sample);
return [m.width, m.actualBoundingBoxAscent, m.actualBoundingBoxDescent].join("|");
}
function fontLooksAvailable(family) {
return fallbacks.some((fallback) => {
const baseline = metrics(fallback);
const candidate = metrics(`"${family}", ${fallback}`);
return candidate !== baseline;
});
}
console.log(fontLooksAvailable("Arial"));
Canvas API дает браузеру холст для рисования, а measureText() возвращает размер отрисованного текста. Так сайт незаметно проверяет сотни названий.
Чем font metrics отличаются от пиксельного Canvas hash
Метрики показывают размер. Canvas fingerprint считывает отрисованные пиксели через getImageData() или toDataURL() и создает на их основе hash.
Пиксели зависят от сглаживания, графической системы, файла и hinting, то есть подгонки букв под пиксельную сетку экрана. Одинаковая ширина не гарантирует одинакового изображения. Браузер может менять Canvas readback, то есть чтение готового изображения, и пользователь ничего не заметит. А вот ограничение видимости шрифтов заметно: страница может взять fallback вместо установленной гарнитуры.
Можно ли проверить локальный шрифт через CSS local()
src: local() ищет начертание по полному имени или PostScript name, например HelveticaNeueLTPro-Roman. При отсутствии совпадения браузер переходит к следующему источнику.
Когда веб-разработчик хочет подключить шрифт, установленный на компьютере пользователя, он добавляет такое CSS-правило прямо в файл стилей сайта с расширением .css. В этом примере браузер сначала ищет Helvetica Neue на устройстве, а если не находит, загружает запасной файл с сайта.
@font-face {
font-family: "ProbeFont";
src:
local("Helvetica Neue"),
local("HelveticaNeue"),
url("fallback.woff2") format("woff2");
}
Из-за риска fingerprinting WebKit скрывает пользовательские шрифты, а Firefox делает то же самое в усиленных режимах защиты.
Почему document.fonts.check() не доказывает, что шрифт установлен
document.fonts.check() проверяет готовность к показу без ожидания, а не наличие файла на компьютере. Это помогает избежать font swap - заметной замены fallback веб-шрифтом после его загрузки.
Что делает этот код: спрашивает у браузера, готов ли текст Arial к показу без ожидания. Значение true не доказывает, что Arial установлен локально.
const available = document.fonts.check('16px "Arial"');
console.log(available);
Вымышленное название тоже вернет true, если браузер сразу берет fallback. Это означает «ждать не нужно», а не «файл существует».
Для веб-шрифта, объявленного через @font-face, проверку запускают после загрузки шрифтов.
Что делает этот код: ждет, пока страница завершит работу со шрифтами, а затем проверяет, можно ли показать конкретный образец без внезапной замены гарнитуры.
Если во время самостоятельного тестирования консоль показывает ошибку paused in the debugger, выполнение страницы приостановлено. Обрати внимание на желтую плашку вверху окна браузера и нажми синюю кнопку Play (Resume script execution), чтобы снять страницу с паузы, а затем запусти код снова.
const fontSpec = '16px "MyWebFont"';
const sample = "BESbswy";
await document.fonts.ready;
const readyWithoutSwap = document.fonts.check(fontSpec, sample);
console.log({ readyWithoutSwap });
Добавь нужные символы: кириллицу, латиницу, китайские иероглифы или emoji. Иначе через fallback проверятся другие глифы.
Когда стоит использовать queryLocalFonts()
window.queryLocalFonts() возвращает веб-редакторам семейство, полное имя, PostScript name и стиль. Требуются разрешение и transient user activation - кратковременная активация кликом или другим действием. Фоновый запрос невозможен.
Что делает этот код: после вставки в Console ждет первого клика по самой веб-странице, запрашивает доступ к локальным шрифтам и выводит разрешенные названия. Отдельная кнопка на сайте для этого не нужна.
// Код ждет клика по всей странице
document.body.addEventListener("click", async () => {
if (!("queryLocalFonts" in window)) {
console.log("Local Font Access API не поддерживается");
return;
}
try {
const fonts = await window.queryLocalFonts();
for (const font of fonts) {
console.log(font.family, font.fullName, font.postscriptName, font.style);
}
console.log(`Успешно найдено шрифтов: ${fonts.length}`);
} catch (error) {
console.error(error.name, error.message);
}
}, { once: true }); // Код сработает только на первый клик
console.log("Код успешно загружен! Теперь просто кликни левой кнопкой мыши в любом месте самой веб-страницы (не в консоли), чтобы увидеть список шрифтов.");
Как проверить код самостоятельно:
- Скопируй весь код из блока выше, вставь его во вкладку Console в DevTools и нажми Enter.
- Убедись, что в консоли появилось сообщение «Код успешно загружен! Теперь просто кликни...».
- Кликни мышью по пустому месту на самой веб-странице или рядом с текстом, а не в окне DevTools.
- Нажми «Разрешить» / Allow в запросе разрешения браузера.
- Вернись во вкладку Console: там сразу появится полный список локальных шрифтов, доступных этому браузеру, и итоговое сообщение с их количеством.
Запрос требует HTTPS; сайт или браузер может его заблокировать. Результат не обязательно охватывает весь каталог. В десктопном Chromium проверь поддержку через 'queryLocalFonts' in window. У Firefox, Safari и мобильного Chromium этого API нет. Возможности:
queryLocalFonts({ postscriptNames: [...] })запрашивает конкретные внутренние названияFontData.blob()после разрешения возвращает SFNT-данные - содержимое контейнера.ttf/.otf, а не только название
Без разрешения доступны только косвенные признаки; с Local Font Access API - метаданные шрифтов, а через FontData.blob() еще и сами SFNT-данные шрифта.
Чем отличается определение шрифтов в Chromium, Firefox и Safari
Chromium предлагает API с разрешением, Firefox усиливает защиту в специальных режимах, а WebKit скрывает шрифты, установленные пользователем.
| Поверхность | Chromium desktop | Firefox | Safari и WebKit |
|---|---|---|---|
| fallback metrics и Canvas | доступны без отдельной защиты | защита может скрыть локальные шрифты или изменить Canvas | доступны для разрешенного набора; пользовательские шрифты скрыты |
document.fonts.check() | готовность, а не установка | та же логика | та же логика |
queryLocalFonts() | десктопные версии, после разрешения | нет | нет |
| режим приватности | Incognito меняет не все сигналы | Private Browsing и ETP Strict усиливают защиту | пользовательские шрифты скрыты по умолчанию, а не только в приватном режиме; Private Browsing дополнительно добавляет шум в чтение 2D Canvas и WebGL |
Защита Firefox от fingerprinting может ограничивать видимость нестандартных шрифтов, добавлять шум при считывании изображений Canvas и блокировать известные fingerprinting-скрипты, в зависимости от включенного режима защиты.

WebKit ограничивает шрифты, добавленные пользователем, но разрешает системные и веб-шрифты. Поэтому Chrome и Safari на Mac различаются.
Как узнать, какой шрифт браузер реально отрисовал
DevTools показывает шрифт фрагмента и fallback.
| Браузер | Где искать | Что показывает |
|---|---|---|
| Chrome, Afina и другие Chromium-браузеры | Elements → Computed → Rendered Fonts | фактически использованные шрифты и количество глифов |
| Firefox | Inspector → Fonts → Fonts used | шрифты элемента и страницы |
| Safari | Elements → Fonts sidebar | основной шрифт, начертание и вариации |
font-family: Inter, Arial, sans-serif задает очередь кандидатов. Rendered Fonts показывает фактический выбор.
Чтобы найти Rendered Fonts в Chrome или открытом профиле Afina:
- Открой DevTools через F12 или Ctrl+Shift+I в Windows, Cmd+Opt+I на Mac. Или кликни по тексту правой кнопкой и выбери «Просмотреть код» / Inspect.
- Открой Elements, обычно это первая вкладка.
- Кликни по HTML-элементу текста. Другой способ: нажми стрелку с квадратиком в левом верхнем углу, наведи ее на текст и кликни.
- Открой справа Computed рядом со Styles. Если панели нет, расширь DevTools.
- Прокрути Computed вниз и разверни Rendered Fonts. Там видно фактический шрифт и количество его глифов.
Одна строка может сочетать Inter для латиницы, системный emoji-шрифт и fallback для отсутствующей кириллической буквы. На шаге 3 выбирай проблемный фрагмент.

Почему имя файла не равно CSS font-family
У одного файла может быть несколько названий:
File: HelveticaNeueLTPro-Roman.otf
Family: Helvetica Neue LT Pro
Full name: Helvetica Neue LT Pro Roman
PostScript name: HelveticaNeueLTPro-Roman
font-family использует семейство, src: local() - полное имя или PostScript name, а queryLocalFonts({ postscriptNames }) - точный PostScript name. Имя файла .otf или .ttf может с ними не совпадать.
Почему браузер не видит только что установленный шрифт
Основные причины: браузер не перезапущен, название указано неверно или работает защита от fingerprinting.
| Симптом | Вероятная причина | Что сделать |
|---|---|---|
| ОС видит шрифт, сайт - нет | браузер был открыт до установки | закрой все окна и процессы, запусти заново |
| в другом аккаунте шрифта нет | Current User, а не All Users | проверь этот аккаунт или установи для всех при наличии прав и лицензии |
| regular есть, bold нет | bold отсутствует или имитируется | проверь менеджер шрифтов и Rendered Fonts |
| имя файла не работает | filename не совпадает с family/PostScript name | проверь внутренние названия |
| гарнитуры нет в программах | формат не поддерживается | найди .ttf/.otf; для веба конвертируй лицензированный шрифт в WOFF2, не ограничивайся простым переименованием расширения файла |
| ошибки или исчезновение | файл поврежден | проверь менеджером шрифтов и переустанови из надежного источника |
| Chrome видит, Safari - нет | WebKit скрывает пользовательские шрифты | подключи лицензированный веб-шрифт через @font-face или fallback |
| Firefox Strict показывает меньше | усиленная защита | отключи ее только для диагностики и включи обратно |
| отдельные символы отличаются | не хватает нужных глифов | проверь этот текст в Rendered Fonts |
Проверка в Windows:
- Нажми Win+I и открой Персонализация → Шрифты.
- Найди название и открой карточку с начертаниями.
Альтернативный путь:
- Открой Проводник через Win+E.
- Введи
C:\Windows\Fontsв адресной строке и нажми Enter. - Воспользуйся поиском в правом верхнем углу.
На macOS используй системное приложение Font Book:
- Нажми Command+Space, введи
Font Bookи открой приложение. - Включи View → Show Sidebar и выбери коллекцию.
- Найди гарнитуру, начертание, символы и внутренние данные.
- Активируй отключенный шрифт через Edit → Activate.
- Проверь файл через File → Validate Selection: зеленый цвет означает успех, желтый - предупреждение, красный - ошибку.
- Устрани дубликаты через File → Resolve Duplicates. Current User или All Users указано в Font Book → Settings → Installation.
В Linux fc-list показывает список, а fc-match "Arial" - подставленный файл. Затем проверь реальный выбор в Rendered Fonts.
Как локальные шрифты превращаются в font fingerprint
Скрипт объединяет карту шрифтов с Canvas, WebGL, экраном и другими признаками. Чекеры браузерных отпечатков используют разные списки и алгоритмы.
Важна редкость комбинации: редкий шрифт может добавить значительно больше идентифицирующей энтропии, чем обычные системные шрифты.

Adobe, офисные и CAD-программы добавляют характерные семейства. Они подсказывают возможное ПО, но не доказывают профессию или личность.
Fonts fingerprint помогает опознать браузер, когда стабильный набор согласуется с другими сигналами.
Как правильно сравнивать результаты и снизить fingerprinting
Проверка в BrowserLeaks:
- Введи
browserleaks.com/fontsв адресной строке нужного профиля. - Подожди 5-15 секунд, пока заполнятся Font Metrics и Unicode Glyphs, не переключая вкладку.
- Запиши количество шрифтов из отчета (report) и общий отпечаток. На скриншоте оставь название теста и эти значения.
- Закрой профиль, запусти другой профиль Afina и повтори тест.
- Сравни данные. Разные сайты несопоставимы.
Чтобы сравнение было честным:
- Используй один и тот же checker; запиши браузер, ОС и защиту.
- Не меняй масштаб страницы или экрана.
- Дождись веб-шрифтов через
@font-face- это не локальные шрифты. - Перезапусти профиль и тест. Важна стабильность.
Почему количество найденных шрифтов меняется
Количество может измениться без ручной установки шрифта:
- ОС и программы добавляют, обновляют или удаляют гарнитуры
- языковые пакеты добавляют кириллицу, арабское письмо, CJK и другие знаки
- Adobe Fonts и другие облачные сервисы активируют шрифты до выхода или отключения синхронизации
- корпоративные политики меняют шрифты рабочих устройств
- разрешения браузера:
local-fonts, приватный режим и защита меняют видимый набор - словари тестов: один сайт проверяет 100 названий, другой - 500
Повтори тест на том же сайте и в том же профиле, затем проверь ОС, программы и разрешения.
Как ограничить проверку локальных шрифтов
Снизить объем данных можно так:
- без необходимости отклоняй
local-fontsчерез «Заблокировать» / Block; исключение - инструмент, которому нужен список - включи штатную защиту Firefox, WebKit или другого браузера
- разделяй cookies, cache и другие данные между профилями; они не удаляют системные шрифты, поэтому конфигурация должна оставаться стабильной
- блокируй JavaScript только в крайнем случае: перестанут работать меню, формы, видео, авторизация и онлайн-тесты
Подмена шрифтов или отключение JavaScript может сломать дизайн, символы и читаемость. Меняй защиту постепенно.
Инкогнито изолирует cookies и историю, но не обязательно меняет метрики шрифтов.
Необычный набор шрифтов, который не согласуется с заявленной ОС или другими сигналами отпечатка, делает общий fingerprint более заметным.
Мини-тест: видит ли браузер конкретный шрифт
Такой тест можно разместить прямо в статье, чтобы читателю не пришлось открывать Console. Пользователь вводит название гарнитуры, а страница сравнивает размер одного и того же текста со шрифтом-кандидатом и с запасным шрифтом.
Структура интерактивного блока для верстальщика:
- Поле «Название шрифта». Однострочное поле с примером
ArialилиRobotoи короткой подсказкой вводить именно family name, а не название файла.ttfили.otf. - Кнопка «Проверить». После нажатия запускает измерение одной тестовой строки в нескольких fallback-семействах.
- Блок «Шрифт-кандидат». Показывает тестовую строку и ее ширину в пикселях после добавления введенного названия перед fallback.
- Блок «Fallback-текст». Показывает ту же строку, размер и ширину без шрифта-кандидата.
- Осторожный результат. Если размеры отличаются, показать «Вероятно доступен». Если разницы нет, показать «Не удалось подтвердить». Не использовать категоричные статусы «Найден» или «Не найден».
Под результатом нужно короткое пояснение: тест работает как эвристика, то есть делает предположение по разнице размеров. Он не сканирует диск и не доказывает, что конкретный файл шрифта установлен в системе.
Как контролировать шрифтовой сигнал в изолированных профилях
Сайт сопоставляет шрифты с Canvas, WebGL, cookies и сетью. Профиль должен давать согласованный, стабильный результат.
Для антидетект-профилей согласованность важнее простого уменьшения количества видимых шрифтов. Профиль, который заявляет Windows, должен показывать шрифтовое поведение, правдоподобное именно для Windows, и тот же профиль должен давать стабильный результат между запусками. Редкий, но внутренне непротиворечивый набор шрифтов выглядит менее подозрительно, чем рандомизированный набор, который противоречит заявленной ОС, Canvas или другим сигналам.
Потенциальные несоответствия согласованности отпечатка включают:
- Windows в User-Agent и набор шрифтов, характерный только для macOS
- macOS-отпечаток и специфичные для Windows гарнитуры
- набор шрифтов, который меняется между двумя запусками одного профиля
- Canvas-рендеринг, который расходится с измеренными метриками шрифтов
Afina изолирует fingerprint, proxy, cookies и cache в Chromium-профиле для управления fingerprint. Списка локальных шрифтов в настройках нет: сигнал проверяют после запуска.
Как проверить настройки отпечатка и результат в конкретном профиле Afina:
- Открой Afina и слева выбери «Аккаунты».
- Нажми ⋮ → Изменить для профиля. Для нового выбери «Добавить аккаунт», затем «Новый аккаунт».
- Проверь ОС, User-Agent, CPU, память, Canvas, WebGL, Аудио и Rects в «Основные» → «Браузерный отпечаток». Шрифтовую видимость оценивай в составе полного отпечатка, а не как отдельную настройку.
- Нажми «Отмена» без изменений или «Сохранить» после них. «Сгенерировать новый отпечаток» меняет профиль.
- Отметь профиль в «Аккаунтах», нажми «Запуск» и дождись браузера.
- Введи
browserleaks.com/fontsв адресной строке, подожди 5-15 секунд и запиши количество шрифтов из отчета (report) и общий отпечаток. - Перезапусти тест; повтори в другом профиле Afina и сравни.
- Открой Canvas- и WebGL-тесты сервиса в каждом профиле. Оценивай стабильность и согласованность всех сигналов, а не один «зеленый» показатель.
Заключение
Большинство методов определения шрифтов остаются эвристическими: сайт сравнивает метрики и пиксели и делает вероятностный вывод, а не читает перечень файлов на диске. Local Font Access API дает более точные данные, однако строго контролируется разрешением пользователя и временной активацией и доступен только в десктопном Chromium. Ограничение лишних разрешений вроде local-fonts, штатная защита браузера и изолированные профили помогают уменьшить объем доступных сайту данных, хотя ни один из этих шагов не работает сам по себе. Для надежной защиты от отслеживания определяющей является общая согласованность всего отпечатка браузера, а не только количество видимых шрифтов: один font hash не доказывает ни уникальности, ни анонимности.
FAQ — Часто задаваемые вопросы
Может ли сайт увидеть все шрифты, установленные на компьютере?
Без разрешения сайт не видит весь каталог шрифтов. После разрешения queryLocalFonts() возвращает список, доступный браузеру.
Как сайт определяет, установлен ли конкретный шрифт?
Сайт сравнивает размер текста с fallback или пиксели Canvas. Такая косвенная проверка может ошибаться.
Почему document.fonts.check() возвращает true для несуществующего шрифта?
document.fonts.check() может вернуть true, потому что браузер сразу подставляет fallback и не ждет загрузки.
Какие браузеры поддерживают queryLocalFonts()?
queryLocalFonts() после разрешения работает в десктопном Chromium, но не в Firefox, Safari и мобильном Chromium.
Может ли сайт загрузить мой локальный файл шрифта?
Без разрешения сайт не читает локальный файл. После разрешения FontData.blob() может предоставить данные шрифта.
Защищает ли режим инкогнито от font fingerprinting?
Инкогнито не дает полной защиты от font fingerprinting. Режим изолирует сессию, но может сохранять метрики и другие сигналы.
Как узнать, какой шрифт браузер реально использовал?
Фактический шрифт виден в секции Rendered Fonts. В DevTools выбери текст и открой Elements → Computed → Rendered Fonts.
Как снизить font fingerprinting?
Чтобы снизить font fingerprinting, отклоняй лишние разрешения и включи защиту браузера. Сверяй шрифты с Canvas и WebGL.
Можно ли определить устройство или операционную систему по набору шрифтов?
Набор шрифтов может подсказать ОС или установленные программы. Этот сигнал нужно сверять с Canvas, WebGL, языком и другими данными.
Чем локальный шрифт отличается от веб-шрифта?
Локальный шрифт установлен в ОС. Веб-шрифт сайт загружает через @font-face.
