ГлавнаяБаза знанийКак сделать баннер согласия на cookie, который реально блокирует счётчики

Как сделать баннер согласия на cookie, который реально блокирует счётчики

Cookie и счётчики 4 сентября 2026 г.

Пошаговая инструкция и код, как сделать баннер cookie по закону: что заблокировать до согласия, как собрать кнопки и где хранить журнал согласий.

Технически баннер cookie — это не окно с текстом «мы используем cookie», а код, который держит счётчики выключенными, пока посетитель не нажал кнопку. Разница между «баннер есть» и «баннер работает» видна в исходном коде страницы: у первого скрипт Метрики стоит в <head> и грузится всегда, у второго — появляется в разметке только после клика. Правовое основание для второго варианта — часть 1 статьи 6 152-ФЗ: без согласия обрабатывать данные можно только по основаниям из этой статьи, а аналитика и реклама в перечень не входят. Кому баннер обязателен и что грозит без него, разобрано в статье нужен ли баннер согласия на cookie — здесь сразу переходим к тому, как собрать рабочий вариант.

Что понадобится заранее

Прежде чем писать код, соберите четыре вещи — без них любой из следующих шагов придётся переделывать.

  • Доступ к коду страниц сайта или к диспетчеру тегов (Google Tag Manager, Яндекс Диспетчер тегов), а не только к визуальному конструктору без вставки своего кода.
  • Список того, что запускает сбор данных: аналитика, рекламные пиксели, виджеты чатов и форм со своей аналитикой на борту.
  • Опубликованная политика конфиденциальности со ссылкой, которую вставите в баннер. Если её ещё нет — сначала разместите политику на сайте.
  • Решение, где хранить факт согласия: на своём сервере или у стороннего сервиса баннера, и в какой стране стоит этот сервер. Это решается на шаге 1 и определяет, каким путём вы пойдёте дальше.

Шаг 1. Выберите: готовый сервис или свой код

Есть два рабочих пути, и выбор между ними — не про вкус, а про то, какой у вас доступ к сайту и что вы готовы контролировать сами.

Критерий Готовый сервис (CMP) Свой код
Время подключения часы дни, включая тестирование
Дизайн и кнопки готовые, настраиваются в панели пишете сами
Где хранится журнал согласий зависит от сервиса — нужно проверять отдельно там, где решите сами
Кому подходит сайтам без доступа к серверу — конструкторам, лендингам на подрядчике сайтам с доступом к коду и к своему хостингу

Готовый сервис быстрее: несколько строк кода — и баннер, кнопки, оформление и сохранение согласий уже работают. Плата за скорость — доверие к тому, где именно сервис хранит журнал. Часть популярных сервисов баннеров — европейские, и тогда закрывается один состав про cookie, но открывается другой: данные о согласии посетителей уходят на сервер за рубежом, а это то же нарушение локализации, что разобрано в статье про хранение персональных данных на российском сервере. Если выбираете сервис — проверяйте адрес сервера не по маркетинговому тексту на сайте сервиса, а по вкладке «Сеть» в инструментах разработчика: куда фактически уходит запрос при нажатии кнопки.

Если доступ к коду есть, дальше — три шага для самостоятельной сборки.

Не уверены, что у вас с этим порядок? Робот откроет сайт браузером и покажет, что видно проверяющему — бесплатно и без регистрации.

Шаг 2. Заблокируйте загрузку счётчиков до согласия

Главное правило: код счётчика никогда не лежит в разметке страницы напрямую. Он оборачивается в функцию, которая вызывается только по действию посетителя — клику «Принять» или уже сохранённому согласию с прошлого визита.

<script>
function loadTracker(src) {
  var s = document.createElement('script');
  s.src = src;
  s.async = true;
  document.body.appendChild(s);
}

function grantConsent() {
  localStorage.setItem('cookie_consent', 'granted');
  loadTracker('https://mc.yandex.ru/metrika/tag.js');
  // здесь же вызовы для остальных счётчиков
}

if (localStorage.getItem('cookie_consent') === 'granted') {
  grantConsent();
}
</script>

Пока grantConsent не вызвана, тега счётчика в разметке нет вообще — не «спрятан», а физически отсутствует. Отказ не требует отдельного кода: это просто ситуация, когда функция не сработала, и скрипт не появился.

Если счётчики подключены через диспетчер тегов — сам контейнер можно грузить сразу, это не трекер. Но теги внутри него обязаны срабатывать по отдельному триггеру «после согласия», а не по «All Pages». Иначе диспетчер решает проблему только на бумаге: теги стреляют так же, как без него.

У конструкторов сайтов (Tilda, Taplink и похожих) свои ограничения: счётчики там обычно подключаются через настройки сайта и грузятся при каждом заходе без варианта поставить условие. Рабочий путь — убрать счётчик из настроек платформы и вставить его тем же кодом через блок с произвольным HTML или JS, который такие конструкторы, как правило, разрешают добавить на страницу.

Шаг 3. Соберите баннер с двумя равнозначными кнопками

Баннер без кнопки отказа — не согласие, а его имитация. Кнопки «Принять» и «Отказаться» должны быть одинаковыми по размеру и заметности: серая ссылка под яркой зелёной кнопкой — это тёмный паттерн, который делает отказ формально существующим, а фактически недоступным.

<div id="cookie-banner">
  <p>Мы используем cookie для аналитики. Подробнее — в
     <a href="/policy" target="_blank">политике конфиденциальности</a>.</p>
  <button onclick="grantConsent(); closeBanner();">Принять</button>
  <button onclick="rejectConsent(); closeBanner();">Отказаться</button>
</div>
function rejectConsent() {
  localStorage.setItem('cookie_consent', 'rejected');
}
function closeBanner() {
  document.getElementById('cookie-banner').style.display = 'none';
}

Ссылка на политику стоит прямо в тексте баннера, а не в отдельном меню, куда ещё нужно догадаться зайти. Посетитель соглашается на обработку — он должен видеть, на какую именно, не покидая баннер.

Шаг 4. Сохраняйте журнал согласий на российском сервере

localStorage решает только одну задачу — запомнить выбор на устройстве посетителя, чтобы баннер не показывался повторно. Доказательством согласия он не является: часть 3 статьи 9 152-ФЗ обязывает доказывать наличие согласия оператора, а не посетителя, а запись на чужом устройстве оператор предъявить не может.

Поэтому рядом с localStorage.setItem нужен запрос на свой сервер:

function grantConsent() {
  localStorage.setItem('cookie_consent', 'granted');
  fetch('/api/consent', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ status: 'granted', ts: Date.now() })
  });
  loadTracker('https://mc.yandex.ru/metrika/tag.js');
}

На сервере сохраняйте не просто «согласие было», а слепок обстоятельств: время, статус (принял или отказался) и версию политики, действовавшую на этот момент. Если политику потом переписали, а вопрос по конкретному согласию возник спустя месяцы, важно показать именно тот документ, с которым согласился посетитель. Сервер, где лежит эта запись, обязан находиться в России — это та же обязанность по локализации, что и для остальных персональных данных сайта.

Типовые ошибки при подключении

  • Счётчик остаётся в <head> «на всякий случай», а баннер просто накладывается визуально поверх страницы. Самая частая ошибка — потому что технически проще не трогать рабочий код, чем переписывать способ подключения счётчика.
  • В диспетчере тегов все теги настроены на срабатывание «All Pages» — согласие из баннера никак на них не влияет, хотя визуально баннер выглядит рабочим.
  • Счётчик успевает стартовать до клика через сторонний плагин или виджет, который поставили отдельно от баннера и забыли про него, — баннер контролирует один источник трекеров, а не все.
  • Журнал согласий хранится только в localStorage посетителя. При споре предъявить нечего: доказательство лежит на устройстве человека, а не у оператора.
  • Кнопка отказа сделана мелкой ссылкой под заметной кнопкой «Принять» — формально кнопки две, фактически равнозначна только одна.

Как проверить, что баннер работает

Наш сканер проверяет ровно то же самое, что описано ниже: заходит на сайт как обычный посетитель и смотрит, есть ли сетевые запросы к трекерам до того, как что-либо нажато. Насколько красиво оформлен баннер, для этой проверки не имеет значения — важен только порядок запросов.

  • Откройте сайт в режиме инкогнито, во вкладке «Сеть» включите фильтр по домену счётчика (например, mc.yandex.ru) — до нажатия кнопки в списке запросов ничего быть не должно.
  • Нажмите «Отказаться» — запросов к счётчику по-прежнему нет ни на этой странице, ни при переходе на следующую.
  • Нажмите «Принять» — запрос к счётчику появляется сразу после клика.
  • Перезайдите на сайт после «Принять» — баннер больше не показывается, счётчик грузится сразу: согласие запомнилось.
  • Проверьте, что клик по кнопке отправляет запись на сервер, а не только в localStorage — во вкладке «Сеть» должен появиться запрос к своему API или к API сервиса баннера.

Быстрее всего то же самое делает бесплатная проверка: она заходит на сайт как посетитель и смотрит, грузятся ли счётчики до нажатия кнопки, — то есть то же самое, что вы только что проверили руками.

Что ещё требуется по этой же норме

Частые вопросы

Можно ли просто скопировать баннер с другого сайта? Технически да, но тогда нужно проверить логику блокировки, а не только внешний вид. Если счётчик на донорском сайте всё равно грузится в <head>, скопированный баннер унаследует ту же ошибку: появится на экране, но ничего не заблокирует.

Обязательно ли писать код самому, если счётчики уже подключены через Tag Manager? Нет. Диспетчер тегов делает то же самое — просто триггер вызывается не кликом по кнопке напрямую, а событием, которое баннер отправляет в dataLayer после согласия. Принцип не меняется: ничего не грузится до этого события.

Что делать с уже установленными счётчиками, если баннер подключают позже? Перенести их код туда же, откуда он сейчас грузится напрямую — из шаблона страницы или настроек CMS — и завернуть в ту же функцию, что вызывается по согласию. Наложение баннера поверх без изменения способа подключения счётчика ничего не блокирует.

Нужен ли баннер, если счётчик уже поддерживает Google Consent Mode? Да. Consent Mode лишь передаёт в теги статус согласия, а получает этот статус тот же баннер с кнопками «Принять» и «Отказаться». Без баннера передавать нечего.

Сколько хранить журнал согласий? Закон конкретного срока для cookie не называет. Разумный ориентир — держать запись минимум столько, сколько установлен общий срок хранения персональных данных в вашей политике конфиденциальности, плюс запас на случай спора после отзыва согласия.