Как сделать cookie-баннер: готовый скрипт и настройка под 152-ФЗ
Cookie-баннер, скопированный «с чужого сайта» пять минут назад, чаще всего не соответствует требованиям 152-ФЗ: одна кнопка без отказа, счётчики грузятся сразу, согласие нигде не сохраняется. Разберём, как сделать cookie баннер, который реально соответствует закону, — с рабочим скриптом, вставками для Tilda и WordPress и логикой хранения согласия. Если баннер уже есть и нужно просто проверить его на соответствие 152-ФЗ, смотрите чеклист в статье Cookie-баннер по 152-ФЗ: как настроить и не получить штраф.
Из чего состоит правильный баннер технически
С точки зрения кода задача сводится к четырём частям:
- Разметка — сам баннер: текст, ссылка на политику, кнопки выбора.
- Хранение выбора — где и как запоминается решение посетителя (localStorage, cookie, сервер).
- Управление скриптами — обработка третьих лиц (Метрика, пиксели, счётчики) запускается только после согласия на соответствующую категорию.
- Возможность отозвать выбор — ссылка или кнопка «Настройки cookie», доступная в любой момент.
Разделение по категориям — не украшение, а требование закона: с 1 сентября 2025 года согласие должно быть отдельным по каждой цели обработки, а не единым пакетом «на всё». Поэтому в скрипте ниже минимум две категории — «необходимые» (без согласия) и «аналитика/реклама» (с согласием).
Готовый скрипт для самописного сайта
Вставьте перед закрывающим тегом </body>. Это рабочий минимум с двумя кнопками, сохранением выбора и отложенным запуском аналитики.
<div id="cookie-banner" style="position:fixed;bottom:0;left:0;right:0;
background:#1f2937;color:#fff;padding:16px;display:none;z-index:9999;
font:14px/1.5 sans-serif">
<span>Мы используем cookie для работы сайта и аналитики. Аналитические и
рекламные cookie включаются только с вашего согласия. Подробнее — в
<a href="/privacy/" style="color:#93c5fd">политике конфиденциальности</a>.</span>
<span style="margin-left:12px;white-space:nowrap">
<button onclick="cookieChoice(true)">Принять всё</button>
<button onclick="cookieChoice(false)">Только необходимые</button>
</span>
</div>
<script>
var CONSENT_KEY = 'cookieConsent';
var CONSENT_VERSION = '2026-08'; // меняйте при правках политики — старое согласие станет неактуальным
function cookieChoice(consent) {
var payload = { value: consent ? 'all' : 'necessary', ts: Date.now(), version: CONSENT_VERSION };
localStorage.setItem(CONSENT_KEY, JSON.stringify(payload));
document.getElementById('cookie-banner').style.display = 'none';
if (consent) initAnalytics();
logConsentToServer(payload); // необязательно, но полезно для доказательства при проверке
}
function getConsent() {
try {
var raw = localStorage.getItem(CONSENT_KEY);
if (!raw) return null;
var parsed = JSON.parse(raw);
return parsed.version === CONSENT_VERSION ? parsed : null;
} catch (e) {
return null;
}
}
window.addEventListener('load', function () {
var consent = getConsent();
if (!consent) {
document.getElementById('cookie-banner').style.display = 'block';
} else if (consent.value === 'all') {
initAnalytics();
}
});
function initAnalytics() {
// сюда — код Яндекс.Метрики, рекламных пикселей и других аналитических скриптов
}
function logConsentToServer(payload) {
// POST на свой endpoint: /api/consent-log — фиксируем факт и время согласия на сервере
// fetch('/api/consent-log', { method: 'POST', body: JSON.stringify(payload) });
}
// Ссылку "Настройки cookie" в футере привяжите к этой функции — она снова открывает баннер
function openCookieSettings() {
document.getElementById('cookie-banner').style.display = 'block';
}
</script>
Три момента, которые обычно упускают:
CONSENT_VERSION— если вы меняете список cookie или политику, поднимите версию, и у всех посетителей баннер покажется заново. Без этого люди годами живут со старым согласием на изменившийся набор данных.logConsentToServer— сам по себе localStorage ничего не доказывает Роскомнадзору при проверке, потому что живёт только в браузере конкретного человека. Серверный лог с обезличенным идентификатором, датой и версией политики — то, чем можно подтвердить факт получения согласия.openCookieSettings— обязательная точка входа для отзыва согласия. Разместите ссылку в футере постоянно, а не только в баннере.
Вставка для Tilda
В Tilda нет нативного конструктора баннеров с категориями, поэтому используется код-вставка:
- Настройки сайта → вкладка «Ещё» → «Вставка кода в HEAD» — если баннер должен быть на всех страницах.
- Скрипт из блока выше вставляется в поле «Код перед закрывающим BODY» там же.
- Отключите автозапуск счётчика Яндекс.Метрики в стандартной интеграции Tilda (Настройки → Аналитика) и подключите его вручную внутри функции
initAnalytics()— иначе счётчик стартует до согласия независимо от баннера. - Ссылку на политику в баннере укажите на страницу
/privacy/(или как называется ваша страница с политикой конфиденциальности на Tilda).
Частая ошибка на Tilda — оставить встроенную интеграцию Метрики включённой «для подстраховки» вместе с ручным скриптом. В итоге счётчик грузится дважды: один раз при загрузке страницы (до согласия), второй — после клика. Автоматическую интеграцию нужно выключить полностью.
Вставка для WordPress
Вариант без плагинов — через functions.php активной темы (или дочерней темы, чтобы не потерять код при обновлении):
add_action( 'wp_footer', function () {
?>
<!-- сюда вставляется HTML и <script> блока из раздела выше -->
<?php
} );
Если аналитика подключена через плагин (например, счётчик Метрики или GTM-плагин), проверьте у него настройку отложенной загрузки или условие подключения — большинство таких плагинов позволяют указать JS-переменную или cookie-флаг, при отсутствии которого скрипт не выводится. Если плагин такой настройки не даёт, надёжнее отключить его автоматическую вставку и вызывать код счётчика вручную из initAnalytics(), как в примере для самописного сайта.
Готовые cookie-плагины для WordPress (Cookie Notice, Complianz и аналоги) закрывают эту логику из коробки, но большинство из них по умолчанию настроены под GDPR — при установке проверьте, что в них включён режим блокировки скриптов до согласия, а не только отображение баннера.
Что должно происходить при отзыве согласия
Кнопка или ссылка «Настройки cookie» должна не просто открывать баннер заново, а реально менять состояние:
- если пользователь ранее согласился, а потом отказался — аналитические cookie нужно не только перестать устанавливать, но и удалить уже установленные (
document.cookie = 'name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/'для каждого известного имени cookie счётчика); - запись в localStorage обновляется на
necessary, серверный лог — новой записью с отметкой отзыва; - если аналитический скрипт уже инициализирован и умеет отключаться (у части систем есть API вида
ym(id, 'reachGoal')только при активном счётчике, но нет штатного «выключить»), проще перезагрузить страницу после отзыва — так скрипт просто не подключится заново.
Как проверить, что баннер работает правильно
После установки откройте сайт в приватном окне браузера (или очистите localStorage и cookie) и проверьте через вкладку «Сеть» в инструментах разработчика:
- запросы к счётчикам аналитики (
mc.yandex.ru,google-analytics.comи т.п.) не должны появляться до клика по «Принять»; - после клика «Только необходимые» эти запросы по-прежнему не должны идти;
- после клика «Принять всё» запросы появляются, а выбор сохраняется — обновите страницу, баннер не должен показаться снова.
Это тот самый момент, где чаще всего расходится теория и реальность: баннер визуально корректен, но счётчик Метрики как был зашит в <head> напрямую через интеграцию конструктора, так и продолжает грузиться при каждом заходе. С позиции 152-ФЗ это означает, что согласие получают уже после того, как данные собраны, — то есть фактически не получают вовсе. Автоматический сканер сайта проверяет именно это — не только наличие баннера, но и реальный порядок загрузки скриптов относительно клика по кнопке.
Типичные технические ошибки при внедрении
- Счётчик подключён напрямую в
<head>через конструктор сайта. Даже если баннер визуально настроен правильно, встроенная интеграция аналитики (в Tilda, WordPress-теме или в шаблоне лендинга) часто подключает счётчик отдельно от вашего скрипта согласия. Проверяйте это отдельно от самого баннера — через вкладку «Сеть» в инструментах разработчика, как описано выше. - Согласие хранится только в cookie с коротким сроком жизни. Если срок жизни cookie с флагом согласия — сутки или неделя, баннер будет показываться повторно слишком часто, а часть пользователей начнёт нажимать «Принять всё» просто чтобы избавиться от плашки, не читая условия. Ставьте разумный срок — от 6 до 12 месяцев, и обязательно сбрасывайте его при смене
CONSENT_VERSION. - Баннер загружается с задержкой в несколько секунд после счётчиков. Если скрипт баннера подключён в конце
</body>, а счётчик аналитики — в<head>тем же файлом шаблона, есть окно в пару секунд, когда счётчик уже сработал, а баннер ещё не появился. Технически это тоже обработка без согласия — просто короткая по времени. Инициализация аналитики должна физически зависеть от результата проверкиgetConsent(), а не просто идти позже по разметке. - Один и тот же флаг согласия используется для всех категорий. Если в коде нет разделения между «необходимые», «аналитика» и «реклама», а есть только общий
true/false, вы технически не можете предложить пользователю согласиться на одно и отказаться от другого — а это прямое требование закона с 1 сентября 2025 года. - Мобильная версия баннера перекрывает контент и не даёт кнопке «Отклонить» появиться на экране без скролла. Формально кнопка есть в коде, но фактически недоступна на маленьком экране без прокрутки — с точки зрения UX-аудита это тоже трактуется как затруднённый отказ.
Штраф, если баннер не работает как надо
Если аналитические cookie грузятся до согласия или согласие оформлено как единственная кнопка без отказа, это квалифицируют как обработку персональных данных без согласия — ч. 2 ст. 13.11 КоАП, до 700 000 ₽ для юрлиц, при повторном нарушении до 1 500 000 ₽. Если при этом в политике не описано, какие cookie использует сайт и зачем, добавляется отдельный состав за неполноту политики — до 60 000 ₽ по ч. 3 ст. 13.11 КоАП. Полный разбор требований к согласию — в статье Нужно ли согласие на cookie: что требует закон и что делает Роскомнадзор, а весь список проверяемых пунктов сайта — в чеклисте Как привести сайт в соответствие с 152-ФЗ: 9 пунктов.
Проще всего проверить готовый баннер не вручную через DevTools, а прогнать сайт через автоматический сканер — он покажет, срабатывают ли счётчики до согласия и корректно ли настроена сама форма согласия.
Все статьи по теме — в хабе Cookie и согласие.
Частые вопросы
Как запретить загрузку метрики до согласия +
Не вставляйте код счётчика (Яндекс.Метрики, рекламных пикселей) напрямую в <head>. Оберните его инициализацию в функцию вроде initAnalytics() и вызывайте её только из обработчика клика на кнопку «Принять», либо при загрузке страницы — но только если в хранилище уже есть сохранённое согласие на аналитические cookie. Если счётчик подключён через Google Tag Manager или Яндекс.Диспетчер тегов, настройте в них триггер, срабатывающий по флагу согласия, а не по загрузке страницы.
Как хранить подтверждение согласия на cookie +
Минимум — сохранить факт и дату выбора в localStorage браузера, этого достаточно для работы самого баннера. Но для юридической защиты при проверке Роскомнадзора одного localStorage мало: он живёт только у конкретного посетителя и обнуляется при очистке кэша. Лучше дополнительно логировать событие согласия на сервере — IP или обезличенный идентификатор сессии, timestamp, версию политики, выбранные категории. Так вы сможете подтвердить факт получения согласия, даже если пользователь почистил браузер.
Нужна ли кнопка «Отклонить» в баннере +
Да, и она обязана быть так же заметна, как кнопка «Принять». Согласие, которое пользователь не может свободно отклонить, юридически не считается согласием — это прямо следует из требования к добровольности и осознанности согласия по 152-ФЗ. Баннер с одной кнопкой «Хорошо, понятно» и без варианта отказа Роскомнадзор трактует как нарушение: у посетителя нет реального выбора.
Как сделать cookie-баннер на Tilda +
В Tilda нет встроенного конструктора cookie-баннеров с категориями, поэтому баннер добавляют через код: Настройки сайта → Ещё → Вставка кода в HEAD и перед BODY (либо в конкретную страницу). Верстку и скрипт баннера вставляете в поле «Код перед закрывающим BODY», а инициализацию счётчиков Метрики выносите из автоматических интеграций Tilda в свою функцию, которая вызывается только после согласия. Готовый пример — в разделе ниже.
Проверьте свой сайт на нарушения 152-ФЗ
Бесплатный анализ за 1 минуту — без регистрации
Проверить сайт →