Topics API — как персонализированная реклама может работать без cookie

21c1afada1860301a159c9cd8f2e9418

Отказ от 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() в течение одной эпохи получит тот же ответ. Стоит уточнить, что это справедливо только для скриптов с одного origin в рамках одного site. Подробнее про терминологию site и origin можно почитать тут. Topics API запомнит в качестве «потребителя» его origin, с которого происходит вызов document.browsingTopics(). Если вызов метода происходит из айфрейма с адресом https://ad.tech, то браузер запомнит ad.tech как origin потребителя. В качестве site будет взято значение из адресной строки браузера (eTLD+1). Если айфрейм находится на сайте https://cats.example, то в качестве site будет взято значение cats.example Для каждой уникальной пары site/origin будет сгенерирован разный набор топиков, который не поменяется в течение всей эпохи.

«Чекин» — это способ добавить в «копилочку» потребителя домен сайта. Когда потребитель запрашивает топики, браузер отдает ему топики только с тех сайтов, на которых потребитель «зачекинился». Одним из способов чекина является сам факт вызова метода document.browsingTopics() (про другие поговорим ниже). Если пользователь зашел на сайт https://cats.example, на сайте был вставлен айфрейм https://ad.tech, а в этом айфрейме был вызван метод document.browsingTopics(), то чекин произошел. С наступлением следующей эпохи при вызове document.browsingTopics() с домена https://ad.tech появляется шанс получить в качестве одного из топиков /Pets & Animals/Pets/Cats. Это ограничение обосновано нежеланием давать потребителю, запрашивающему Topics API, больше информации, чем он имел при использовании third‑party cookies (только ограничения, никаких послаблений). При сборе топиков убедитесь, что вы собираете их в одном месте (чекините на один origin), иначе вы не получите к ним доступ.

В выдачу подмешивается 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), топики просто не будут добавлены в следующую эпоху.

Дебаг

Самая главная проблема при дебаге — дождаться следующей эпохи. Чтобы облегчить свои страдания, можно изменить дефолт длительности эпохи (и не только его) при запуске 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, мягко говоря, не особо охотно эту интеграцию поддерживает. Возможно, это попытка сделать заявление а‑ля: «мы всеми силами пытаемся сохранить индустрию независимых рекламных сетей» (ага).

© Habrahabr.ru