Отказ от third‑party кук уже не за горами. Однако в попытке уберечь пользователя от «слежки» браузеры рискуют по дороге отправить в могилу индустрию персонализированной рекламы (и не только, но сегодня про нее). Могу только представить, что испытывает Google, разрываясь между желанием сохранить лояльность пользователей Chrome и стремлением продолжить зарабатывать на рекламе сотни миллионов долларов ежедневно. В качестве решения проблемы, в рамках инициативы Privacy Sandbox, Google предлагает использовать Topics Api, как инструмент доступа к «интересам» пользователя без возможности его отслеживания.
Необходимо сначала разобраться, чем «персонализированная» реклама отличается от «контекстной». Контекстная реклама — та, что показывается в контексте запроса, статьи или сайта. Например, ты видишь рекламу холодильника, пока читаешь статью про холодильники на сайте холодильников. Персонализированная реклама — та, что подобрана индивидуально для пользователя по его интересам. Google запоминает, что тебе интересны холодильники и будет показывать для тебя рекламу холодильников и на других сайтах (уже вне контекста). Так вот, Topics API предоставляет API для получения данных именно об интересах пользователей, которые можно использовать для показа персонализированной рекламы. Эти интересы мы и будем называть топиками.
Топики
Топики (интересы) пользователей классифицированы по категориям. Они хранятся в специальном словарике и версионируются. На данные момент доступны первая и вторая версия таксономии. Каждая категория имеет уникальный целочисленный и соответствующий ему человекочитаемый строковый идентификатор. Топики иерархичны и эта иерархия представлена в строковом идентификаторе. Например, /Finance/Insurance
(158 топик) является дочерним для /Finance
(149 топик).
Таксономия организована так, чтобы избегать излишней специфичности топиков в целях защиты от отслеживания. С другой стороны, без достаточной гранулярности интересов, они могут оказаться бесполезными. Поэтому вопрос наполнения словарика с топиками является дискуссионным и обсуждается специальным комитетом.
Предлагается не отчаиваться из‑за бедноты категорий, а вместо этого пытаться «обучаться» на основе их сочетаний. Например, о пристрастии пользователя к подводной ловле можно догадаться по сочетанию категорий «Beaches & Islands» и «Fishing».
В списке также отсутствуют «чувствительные» категории.
Как получить топики из браузера
Браузер отдает топики по запросу await document.browsingTopics()
. Результатом резолва промиса будет массив объектов с данными о топиках типа такого. В каждом объекте присутствует идентификатор топика, который можно использовать по своему усмотрению.
Как браузер узнает об интересах пользователей
На данный момент единственный способ определения топиков, имплементированный в Topics API, работает на основе доменов сайтов, которые пользователь посетил.
Для 10,000 самых популярных сайтов есть готовый словарик топиков, для остальных сайтов — алгоритм на основе machine learning. Изначально модельку (на основе TensorFlow Lite) обучает Google, но вносить в нее изменения смогут все, поскольку она лежит в опен‑сорсе.
В хроме на странице chrome://topics‑internals/ на вкладке «Classifier» есть возможность подебажить эту модель. Там же представлен путь до файлика с текущей моделью. При желании модель можно переобучить и подебажить.
Эпохи
Внутри браузера встроен планировщик, который обновляет данные по топикам раз в определенный интервал времени. Этот интервал времени называется эпохой и длится неделю.
После того как пользователь посетил сайт с котиками, информация о его «кошачьих пристрастиях» прорастет в Topics API в виде топика /Pets & Animals/Pets/Cats
. Но это произойдет только после того, как наступит следующая эпоха.
Каждый раз, при наступлении новой эпохи, браузер смотрит в историю пользователя, превращает домены в топики, ранжирует топики по частоте визитов (но не только) и подсчитывает топ 5 для каждой из 3 последних эпох. Топиков в эпохе может оказаться меньше 5 (или вообще не быть), если их не удается определить. Например, при отсутствии истории браузера для конкретной эпохи.
Когда скрипт вызывает метод document.browsingTopics()
, браузер отдает по одному случайному топику из 5 для каждой эпохи. Поскольку эпох всего 3, браузер может отдать максимум 3 топика за раз. При последующих вызовах в течение одной эпохи скрипт продолжит получать те же топики. Список обновится только после пересчета в начале новой эпохи.
Все представленные выше числа (длительность эпохи, количество эпох и прочие) можно найти на странице chrome://topics‑internals/ на вкладке «Features and Parameters». Изменить их можно, передав параметр --enable-features
с новыми значениями при запуске Chrome (пример ниже).
Ограничения
Выше уже было сказано, что скрипт при последующих вызовах document.browsingTopics()
в течение одной эпохи получит тот же ответ. Стоит уточнить, что это справедливо только для скриптов с одного site «потребителя» в рамках одного top-frame site. Подробнее про терминологию site можно почитать тут, в нашем случае это eTLD+1. Topics API запомнит в качестве «потребителя» его eTLD+1, с которого происходит вызов document.browsingTopics()
. Если вызов метода происходит из айфрейма с адресом https://ad.tech, то браузер запомнит ad.tech
как site потребителя. В качестве site будет взято значение из адресной строки браузера. Если айфрейм находится на сайте https://cats.example, то в качестве site будет взято значение cats.example
Для каждой уникальной пары site потребителя
/top-frame site
будет сгенерирован разный набор топиков, который не поменяется в течение всей эпохи.
«Чекин» — это способ добавить в «копилочку» потребителя домен сайта. Когда потребитель запрашивает топики, браузер отдает ему топики только с тех сайтов, на которых потребитель «зачекинился». Одним из способов чекина является сам факт вызова метода document.browsingTopics()
(про другие поговорим ниже). Если пользователь зашел на сайт https://cats.example, на сайте был вставлен айфрейм https://ad.tech, а в этом айфрейме был вызван метод document.browsingTopics()
, то чекин произошел. С наступлением следующей эпохи при вызове document.browsingTopics()
с домена https://ad.tech появляется шанс получить в качестве одного из топиков /Pets & Animals/Pets/Cats
. Это ограничение обосновано нежеланием давать потребителю, запрашивающему Topics API, больше информации, чем он имел при использовании third‑party cookies (только ограничения, никаких послаблений). При сборе топиков убедитесь, что вы собираете их в одном месте (чекините на один site), иначе вы не получите к ним доступ.
В выдачу подмешивается 5% фальшивых топиков. Это необходимо для того, чтобы не было возможность идентифицировать пользователя по «отсутствующим» интересам. У каждого топика появляется шанс оказаться в выдаче.
Браузер при подборе также исключает из иерархии избыточные родительские узлы. Это значит, что если в выдаче уже есть /Shopping/Apparel/Eyewear
, то /Shopping
будет отфильтрован и заменен чем‑то более полезным.
Кастомизировать или запретить Topics API может как сайт (через заголовок Permissions-Policy
), так и пользователь (через настройки браузера).
Topics API стираются при чистке истории браузера и недоступны в режиме инкогнито.
Чекин
Чекин на сайте происходит при вызове метода document.browsingTopics()
. Впрочем, вы можете передать параметр skipObservation=true
, чтобы получить топики, но избежать чекина. Браузер просто не будет добавлять этот сайт в следующую эпоху.
Еще одним способом является чекин через заголовки запроса. В этом случае сайт должен сам зачекинить потребителя, который позже получит доступ к топикам сайта. Происходит это через вызов метода fetch с параметром browsingTopics=true
либо через вставку айфрейма с атрибутом browsingtopics
.
Топики передадутся на сервер в заголовке Sec-Browsing-Topics
в формате (299 328);v=chrome.1:1:1, ();p=P00000
. Последний параметр p=P00000
используется как паддинг (чтобы количество символов в заголовке всегда было одинаковым). Это нужно, чтобы по размеру запроса нельзя было понять, есть в нем топики или нет. При отсутствии топиков будет передано что‑то типа ();p=P0000000000000000000000000000000
.
На запрос необходимо ответить заголовком Observe-Browsing-Topics: ?1
, чтобы зачекиниться. В противном случае (как и при использовании skipObservation
), топики просто не будут добавлены в следующую эпоху.
Чекин происходит в рамках сайта (eTLD+1), а значит можно зачекиниться на сайте https://topics.ad.tech, а запрашивать топики с сайта https://ad.tech.
Дебаг
Самая главная проблема при дебаге — дождаться следующей эпохи. Чтобы облегчить свои страдания, можно изменить дефолт длительности эпохи (и не только его) при запуске Chrome.
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --enable-features=BrowsingTopics,BrowsingTopicsParameters:time_period_per_epoch/15s/browsing_topics_max_epoch_introduction_delay/3s,PrivacySandboxAdsAPIsOverride,PrivacySandboxSettings3,OverridePrivacySandboxSettingsLocalTesting
Рекомендую посмотреть видео, в котором показано, как можно подебажить Topics API с чекином через вызов JS метода. Подебажить Topics API с чекином через заголовки можно тут https://topics‑fetch‑demo.glitch.me.
Примечания автора статьи
С моей колокольни конкретно эта реализация шаринга пользовательских интересов выглядит не очень элегантно. Слишком много странных решений и ограничений собрались в один клубок. Но, за неимением лучшего, смотрим, что будет дальше. По крайней мере Topics API проработан и уже фактически работает в Chrome.
Очень сомневаюсь, то Topics API будет использоваться так, как он спроектирован сейчас. Точно будет дорабатываться таксономия, механизмы ранжирования. Как показывает практика других инициатив Privacy Sandbox, может поменяться и архитектура и название. Поэтому следим. Последние апдейты тут, подписаться на анонсы можно тут.
Также нужно учесть что Google тянет на себе Topics API практически в одиночку и пока не понятно, как к этому отнесутся другие вендоры браузеров. Пока выглядит так, что они смотрят на Topics API искоса, но свои варианты не предлагают.
Интересно, что прямо в документации создатели пишут об интеграции с Prebid. Несмотря на то, что Google, мягко говоря, не особо охотно эту интеграцию поддерживает. Возможно, это попытка сделать заявление а‑ля: «мы всеми силами пытаемся сохранить индустрию независимых рекламных сетей» (ага).