Главная›База знаний›Как сделать баннер согласия на 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 сервиса баннера.
Быстрее всего то же самое делает бесплатная проверка: она заходит на сайт как посетитель и смотрит, грузятся ли счётчики до нажатия кнопки, — то есть то же самое, что вы только что проверили руками.
Что ещё требуется по этой же норме
- Баннер закрывает cookie и счётчики по статье 6 152-ФЗ. Форма заявки требует отдельного согласия по статье 9 — это другая точка сбора, разобрана в статье согласие на обработку персональных данных в форме.
- Если журнал согласий или сами данные посетителей хранятся за рубежом — это отдельное нарушение про локализацию, даже если с cookie на сайте всё в порядке: хранение персональных данных на российском сервере.
- Полный разбор того, кому баннер обязателен и какая вилка штрафа грозит без него, — в статье нужен ли баннер согласия на cookie.
Частые вопросы
Можно ли просто скопировать баннер с другого сайта?
Технически да, но тогда нужно проверить логику блокировки, а не только внешний вид. Если счётчик на донорском сайте всё равно грузится в <head>, скопированный баннер унаследует ту же ошибку: появится на экране, но ничего не заблокирует.
Обязательно ли писать код самому, если счётчики уже подключены через Tag Manager?
Нет. Диспетчер тегов делает то же самое — просто триггер вызывается не кликом по кнопке напрямую, а событием, которое баннер отправляет в dataLayer после согласия. Принцип не меняется: ничего не грузится до этого события.
Что делать с уже установленными счётчиками, если баннер подключают позже? Перенести их код туда же, откуда он сейчас грузится напрямую — из шаблона страницы или настроек CMS — и завернуть в ту же функцию, что вызывается по согласию. Наложение баннера поверх без изменения способа подключения счётчика ничего не блокирует.
Нужен ли баннер, если счётчик уже поддерживает Google Consent Mode? Да. Consent Mode лишь передаёт в теги статус согласия, а получает этот статус тот же баннер с кнопками «Принять» и «Отказаться». Без баннера передавать нечего.
Сколько хранить журнал согласий? Закон конкретного срока для cookie не называет. Разумный ориентир — держать запись минимум столько, сколько установлен общий срок хранения персональных данных в вашей политике конфиденциальности, плюс запас на случай спора после отзыва согласия.