Слушатели событий __tcfapi: руководство разработчика по скриптам, учитывающим согласие
Почему скриптам стоит слушать, а не опрашивать
Любому скрипту, зависящему от согласия — рекламному тегу, загрузчику аналитики, обёртке header bidding, — нужно знать две вещи: есть ли у CMP уже решение и каково оно. Распространённая ошибка — читать cookie при загрузке страницы или опрашивать CMP по таймеру, пока что-нибудь не появится. Оба подхода ломаются предсказуемо: формат cookie внутренний для CMP и может измениться, а опрос либо срабатывает слишком рано, либо впустую тратит время на ожидание.
IAB TCF определяет для этой задачи стандартный JavaScript-интерфейс — функцию __tcfapi. В этом руководстве разбираются команды, которые действительно нужны, события, которые вы будете получать, и ошибки, чаще всего встречающиеся в продакшене.
Заглушка и очередь
CMP на основе TCF должен как можно раньше разместить на странице небольшую заглушку (stub), ещё до загрузки основного скрипта CMP. Заглушка определяет window.__tcfapi и ставит в очередь все вызовы, сделанные до готовности CMP. Когда CMP заканчивает загрузку, он обрабатывает очередь и отвечает на каждый вызов.
Благодаря этому другие скрипты могут безопасно вызывать __tcfapi сразу: пока заглушка находится на странице раньше них, их вызовы не теряются. Если скрипт падает из-за того, что __tcfapi не определена, заглушка либо отсутствует, либо загружается слишком поздно — исправляйте порядок загрузки, а не добавляйте повторные попытки.
Команды, которые важны
ping
__tcfapi('ping', 2, callback) возвращает базовый статус, не дожидаясь решения пользователя. Ответ включает cmpLoaded, cmpStatus со значениями вроде stub, loading, loaded или error, а также displayStatus со значением visible, hidden или disabled. Он также сообщает gdprApplies, когда это становится известно. Используйте его для диагностики и чтобы понять, актуален ли TCF для этого посетителя вообще.
addEventListener
__tcfapi('addEventListener', 2, callback) — команда, которую должна использовать большинство интеграций. Колбэк получает объект tcData и флаг успеха и вызывается снова при каждом изменении состояния согласия. Начиная с TCF v2.2 это рекомендуемый способ получения данных о согласии; прежняя команда getTCData признана устаревшей.
removeEventListener
Каждый объект tcData содержит listenerId. Передайте его в __tcfapi('removeEventListener', 2, callback, listenerId), когда вашему скрипту больше не нужны обновления — например, одноразовому загрузчику, который уже принял решение.
Чтение eventStatus
Ключевое поле в tcData — eventStatus. У него три значения:
tcloaded— CMP нашёл действительное сохранённое решение, и баннер показан не будет. Можно сразу действовать на основе данных.cmpuishown— баннер отображается. Данные отражают прежнее состояние, но пользователь вот-вот может его изменить.useractioncomplete— пользователь только что сделал или подтвердил выбор. Действуйте по новым данным.
Типичный загрузчик ждёт tcloaded или useractioncomplete, затем проверяет нужные ему цели и вендоров. Событие cmpuishown он игнорирует, разве что записывает в лог, что баннер появился.
Проверка целей и вендоров
Внутри tcData согласие и законный интерес представлены объектами с ключами-идентификаторами:
tcData.purpose.consents[1]— согласие на цель 1 (хранение на устройстве).tcData.purpose.legitimateInterests[7]— статус законного интереса для цели 7.tcData.vendor.consents[ID]иtcData.vendor.legitimateInterests[ID]— статус по каждому вендору с использованием его идентификатора в Global Vendor List.tcData.gdprApplies— определил ли CMP, что к этому посетителю применяется GDPR. Если значениеfalse, скрипту следует выполнять логику без TCF.tcData.tcString— закодированная строка, которую вы передаёте партнёрам, ожидающим её.
Проверяйте и цель, и вендора. Согласия на цель без согласия для вендора (или наоборот) для большинства вендоров недостаточно, чтобы обрабатывать данные.
Iframe и межфреймовые вызовы
Реклама и виджеты часто работают внутри iframe, которые не видят __tcfapi родительской страницы. TCF решает это протоколом postMessage: CMP добавляет на верхнюю страницу фрейм с именем __tcfapiLocator, а код внутри iframe может найти его, отправить сообщение __tcfapiCall и получить ответ __tcfapiReturn. Большинство рекламных SDK уже делают это. Если вы пишете собственный код для iframe, реализуйте тот же шаблон, а не читайте cookie между фреймами.
Частые ошибки и как их заметить
- Действия по
cmpuishown. Скрипты, загружающиеся при любом срабатывании колбэка, запустятся до решения пользователя. Фильтруйте поeventStatus. - Слишком раннее удаление слушателя. Если удалить его после первого колбэка, вы пропустите последующий
useractioncompleteи так и не загрузитесь. - Игнорирование отзыва согласия. Постоянно работающие скрипты должны продолжать слушать и останавливаться или перенастраиваться при отзыве согласия.
- Игнорирование
gdprApplies. За пределами регионов TCF объекты целей могут быть пустыми; считать это «отсутствием согласия» значит отключить доход, который вам разрешено получать. - Отсутствие проверки флага успеха. Если
successравен false, запишите это в лог; обычно это сигнал о неисправной настройке CMP.
Тестирование интеграции
В консоли браузера вызовите __tcfapi('ping', 2, console.log), чтобы убедиться, что CMP на месте, затем зарегистрируйте слушатель с console.log в качестве колбэка и пройдите по баннеру. При первом визите вы должны увидеть cmpuishown, а следом useractioncomplete, а после перезагрузки — tcloaded. Повторите для варианта «принять все», «отклонить все» и пользовательского выбора и убедитесь, что скрипт корректно работает в каждом случае.
Главные выводы
- Используйте
__tcfapiвместо чтения cookie CMP или опроса. - Убедитесь, что заглушка CMP загружается раньше любого скрипта, вызывающего API.
- Используйте
addEventListenerи действуйте только поtcloadedилиuseractioncomplete. - Проверяйте статус и цели, и вендора и учитывайте
gdprApplies. - Внутри iframe применяйте шаблон postMessage с
__tcfapiLocator.