Cookie-баннеры и согласия: как не потерять позиции

Cookie-баннер — это единственный элемент сайта, который юрист требует поставить, дизайнер соглашается сделать «как у всех», а разработчик подключает готовым скриптом за пять минут. И ровно этот элемент способен обнулить работу по скорости, испортить первый экран на мобильных, добавить сайту полсекунды к загрузке и в отдельных случаях спрятать контент от робота. Требования 152-ФЗ выполнить нужно — вопрос только в том, какой ценой. В этой статье разбираем cookie-согласия так, как мы внедряем их на проектах SEO-продвижения: что закон реально требует, как баннер влияет на CLS, INP и поведенческие метрики, какие реализации безопасны, а какие стоят позиций, и как проверить свою на предмет скрытых потерь.
Коротко
- 152-ФЗ требует информировать пользователя, публиковать политику обработки персональных данных и получать согласие — но не требует блокировать сайт до клика и не требует европейского cookie-wall.
- Баннер, вставленный в поток документа скриптом после загрузки, — самая частая причина внезапного роста CLS с 0,02 до 0,2 и вылета из «зелёной» зоны Core Web Vitals.
- Готовые сторонние CMP-платформы добавляют 40–150 КБ JavaScript, лишний DNS-запрос и TLS-рукопожатие к чужому домену: то, что чинили месяц, ломается одним тегом.
- Роботы Яндекса и Google не сохраняют cookie между запросами — если контент подгружается только после согласия, для поиска его не существует.
- Полноэкранный оверлей на мобильных бьёт по поведенческим: в Метрике отказ — это визит с одним просмотром короче 15 секунд, а баннер во весь экран производит их массово.
- Правильная реализация — 3–6 КБ собственного кода, вёрстка баннера в HTML сразу, position: fixed вне потока, критический CSS инлайном, отложенная инициализация только для рекламных пикселей.
- Проверять эффект нужно на полевых данных (Метрика, CrUX), а не в Lighthouse: в лабораторном прогоне баннер часто просто не успевает появиться.
Что 152-ФЗ требует на самом деле — и чего не требует
Половина проблем с cookie-баннерами возникает из-за того, что российские сайты копируют европейские решения. GDPR построен на принципе предварительного согласия: до клика пользователя нельзя запускать ни аналитику, ни рекламные пиксели, ни функциональные скрипты. Отсюда родились тяжёлые CMP-платформы, которые блокируют исполнение сторонних тегов, держат реестр вендоров и грузят по сотне килобайт кода. В российском правовом поле такой конструкции не требуется.
Что действительно вытекает из 152-ФЗ «О персональных данных» и связанной практики Роскомнадзора:
- Публичная политика обработки персональных данных. Документ должен быть в свободном доступе, со ссылкой из любого места сайта — обычно из подвала. Это прямое требование к оператору: обеспечить неограниченный доступ к документу, определяющему политику обработки.
- Информирование о том, какие данные и зачем собираются. Cookie сами по себе не всегда персональные данные, но идентификаторы аналитических систем, связанные с профилем посетителя, трактуются как таковые. Формулировка «мы используем файлы cookie» без пояснения категорий — слабая позиция.
- Согласие на обработку. Для форм — отдельный чекбокс с ссылкой на политику и на согласие. Для cookie — фиксация факта, что пользователь был проинформирован и продолжил пользоваться сайтом либо нажал кнопку.
- Уведомление Роскомнадзора об обработке персональных данных. Для подавляющего большинства коммерческих сайтов оно обязательно, и подаётся оно один раз.
- Локализация баз данных на территории РФ. Требование, из-за которого нельзя бездумно ставить зарубежные сервисы аналитики и чатов.
Чего 152-ФЗ не требует: закрывать сайт непрозрачным оверлеем до клика, блокировать скроллинг, запрещать доступ при отказе, показывать модальное окно с двумя уровнями настроек и списком из шестидесяти вендоров. Все эти элементы пришли из чужого регулирования и на российском проекте создают только издержки — по скорости, по конверсии и по поведенческим метрикам.
ГРАНИЦА ОТВЕТСТВЕННОСТИ
Мы не юридическая фирма и не даём правовых заключений. Формулировки текста баннера, состав политики и объём согласий согласуйте с юристом — особенно если работаете в медицине, финансах, образовании или обрабатываете данные несовершеннолетних. Наша зона — техническая реализация: сделать так, чтобы утверждённый юристом баннер не стоил вам позиций, скорости и заявок. Штрафы за нарушения в области персональных данных измеряются сотнями тысяч рублей для юрлиц и растут при повторных нарушениях, так что экономить на юридической части не стоит — экономить надо на килобайтах.
| Требование | Что должно быть на сайте | Техническая цена | SEO-риск при неверной реализации |
|---|---|---|---|
| Политика обработки ПД в открытом доступе | Отдельная страница + сквозная ссылка в подвале | Одна страница, ноль скриптов | Низкий. Ошибка — закрыть страницу от индексации без причины или поставить на неё noindex «на всякий случай» |
| Информирование об использовании cookie | Баннер или строка уведомления с ссылкой на политику | 3–6 КБ при собственной реализации | Высокий: именно здесь возникают CLS, перекрытие первого экрана и лишний JS |
| Согласие на обработку в формах | Чекбокс без предустановленной галочки, ссылки на документы | Разметка формы | Средний: чекбокс, ломающий отправку на мобильных, режет конверсию сильнее любого баннера |
| Возможность отозвать согласие | Ссылка «Настройки cookie» в подвале, открывающая баннер повторно | Один обработчик клика | Низкий, если ссылка не создаёт отдельный URL с параметром |
| Фиксация факта согласия | Лог: отметка времени, версия политики, состав категорий | Одна таблица в БД или запись в CRM | Отсутствует, если запись идёт асинхронно и не блокирует отрисовку |
| Локализация данных в РФ | Российские аналитика, формы, чаты, хостинг | Выбор стека | Средний: зарубежные виджеты одновременно нарушают требование и тормозят сайт |
Как баннер ломает Core Web Vitals
Три метрики Core Web Vitals — LCP, CLS и INP — реагируют на cookie-баннер по-разному, и понимать эту разницу критично: одна и та же плашка может не влиять ни на что либо испортить сразу две метрики, в зависимости от способа вставки.
CLS: главная жертва
Cumulative Layout Shift измеряет визуальную нестабильность: насколько сильно элементы прыгают после того, как пользователь уже видит страницу. Порог «хорошо» — 0,1, «требует улучшения» — до 0,25, дальше «плохо». Значение считается по сессионным окнам: серия сдвигов, разделённых паузами не более секунды и укладывающихся в пятисекундное окно, суммируется, а в итоговый показатель идёт максимальное окно.
Классический сценарий поломки выглядит так. Верстальщик делает баннер обычным блоком в потоке — например, сверху страницы или перед подвалом. Скрипт вставляет его в DOM через 300–800 мс после загрузки, когда пользователь уже видит контент. Блок высотой 120 пикселей на десктопе и 200 на мобильном сдвигает вниз весь документ. Один такой сдвиг на мобильном экране высотой 800 пикселей даёт вклад в CLS порядка 0,2 — то есть сам по себе выбрасывает страницу из зелёной зоны, даже если всё остальное на сайте идеально.
Второй, менее очевидный сценарий: баннер исчезает. Пользователь нажимает «Принять», блок удаляется из потока, контент прыгает вверх. Здесь спасает правило исключения: сдвиги, произошедшие в пределах 500 мс после пользовательского ввода, в CLS не засчитываются. Но правило работает, только если сдвиг действительно вызван кликом и уложился в полсекунды. Если после клика идёт запрос на сервер, а блок убирается по ответу через 900 мс — сдвиг засчитается полностью.
Третий сценарий, который находят реже всего: баннер меняет высоту. Текст загрузился, шрифт подменился, кнопки перенеслись на вторую строку — плашка выросла на 40 пикселей и толкнула контент. Особенно характерно для баннеров с кастомным шрифтом без корректного font-display и для длинных юридических формулировок на узких экранах.
ПРАВИЛО, КОТОРОЕ РЕШАЕТ 90% ПРОБЛЕМЫ
Элемент с position: fixed или position: absolute выведен из потока документа и не сдвигает соседние элементы. Cookie-баннер, свёрстанный как фиксированная плашка внизу экрана, физически не может создать layout shift — независимо от того, когда он появился и как изменил высоту. Это не оптимизация, а архитектурное решение: сначала выбираем правильный тип позиционирования, и половина работы по CLS отпадает сама.
LCP: косвенный, но реальный вклад
Largest Contentful Paint фиксирует момент отрисовки самого крупного элемента в области просмотра. Порог «хорошо» — 2,5 секунды. Сам баннер редко становится LCP-элементом, но он влияет на метрику двумя путями.
Первый — конкуренция за поток. Внешний скрипт CMP, подключённый без атрибутов async или defer, блокирует парсинг HTML. Пока браузер не скачал и не исполнил чужой файл, он не двигается дальше по документу — а значит, не обнаруживает картинку героя и не начинает её загрузку. Полсекунды блокировки в начале документа стоят ровно полсекунды LCP.
Второй — новые сетевые соединения. Сторонний CMP живёт на своём домене: браузеру нужен DNS-lookup, TCP-хендшейк, TLS-рукопожатие, и только потом загрузка. На мобильном соединении это 200–400 мс до первого байта чужого скрипта, причём в самый неудачный момент — на критическом пути отрисовки. Мы разбирали эту механику в материале про скорость загрузки сайта: каждый новый третьесторонний домен стоит дороже, чем кажется по весу файла.
Третий, редкий случай — баннер действительно становится LCP-элементом. Так бывает на страницах со скудным первым экраном: если плашка занимает заметную площадь и содержит крупный текстовый блок, браузер может посчитать LCP именно её. Метрика при этом привязывается к моменту появления баннера, то есть к самому позднему событию на странице.
INP: цена «умных» настроек
Interaction to Next Paint измеряет отзывчивость: сколько миллисекунд проходит от действия пользователя до следующей отрисовки. Порог «хорошо» — 200 мс. Простой баннер с двумя кнопками к INP отношения не имеет. Проблемы начинаются у многоуровневых CMP с экраном настроек: клик по «Настроить» запускает построение списка категорий, пересчёт состояния десятков чекбоксов, обращение к внешнему API за конфигурацией. Длинная задача в главном потоке — и вот интеракция стоит 400–600 мс.
Отдельно вредна практика «по клику на Принять инициализируем всё сразу»: в один тик подключаются счётчики, пиксели, карты, чаты. Браузер получает пачку синхронных задач, интерфейс замирает на секунду, а пользователь в этот момент уже тапает по меню и не получает отклика. Правильно — разносить инициализацию через requestIdleCallback или хотя бы через setTimeout с нулевой задержкой, чтобы отдать отрисовку раньше, чем начнётся тяжёлая работа.
| Метрика | Порог «хорошо» | Как баннер портит | Что делать |
|---|---|---|---|
| CLS | ≤ 0,1 | Вставка блока в поток после отрисовки; изменение высоты; удаление блока позже 500 мс после клика | position: fixed, разметка в HTML сразу, показ переключением CSS-класса |
| LCP | ≤ 2,5 с | Блокирующий сторонний скрипт, лишний домен, баннер как крупнейший элемент экрана | Свой код инлайном, никаких синхронных внешних CMP, компактная плашка |
| INP | ≤ 200 мс | Тяжёлый экран настроек, залповая инициализация всех тегов по клику | Разнести инициализацию, минимум состояния, никаких запросов на рендере |
| TTFB | ≤ 0,8 с | Серверная проверка согласия на каждом запросе, отключение полностраничного кэша | Решение хранить в cookie, состояние определять на клиенте, кэш не ломать |
| Отказы (Метрика) | — | Оверлей во весь экран, невозможность закрыть, перекрытие кнопки заказа | Плашка не выше 20–25% высоты экрана, явная кнопка закрытия |
Что видит поисковый робот
Самая опасная ошибка в этой теме — не медленный баннер, а баннер, который прячет контент от индексирующего робота. Здесь важно понимать один факт: роботы Яндекса и Google не хранят cookie между запросами. Каждый обход — это чистая сессия без истории. Соответственно, если ваш сайт показывает контент только после согласия, для поиска у вас нет контента.
Три сценария, каждый со своими последствиями
- Баннер как визуальный слой поверх готового HTML. Контент отрисован, в DOM присутствует полностью, плашка просто лежит сверху. Робот получает документ целиком, индексация не страдает. Это единственный безопасный вариант, и именно к нему нужно приводить любую реализацию.
- Cookie-wall с редиректом. Пользователь без согласия отправляется на /consent/ или /cookie-policy/. Робот при обходе любого URL получает 302 на служебную страницу. Результат — из индекса начинают выпадать целые разделы, а в отчётах об индексации появляется вал «недостаточно качественная» и «неканоническая». Схема встречается редко, но когда встречается — обходится дороже всего.
- Отложенный рендеринг контента. Сценарий для SPA: приложение инициализируется, проверяет согласие, и только потом монтирует основной компонент. Для робота страница остаётся пустым каркасом. Это частный случай общей проблемы JavaScript-SEO, но с дополнительным нюансом: разработчик обычно уверен, что «всё рендерится», потому что в своём браузере cookie согласия у него давно стоит.
КАК ПРОВЕРИТЬ ЗА ДВЕ МИНУТЫ
Откройте страницу в режиме инкогнито с отключённым JavaScript (DevTools → Settings → Debugger → Disable JavaScript) и посмотрите, есть ли на экране основной текст. Затем повторите проверку в «Инструменте проверки ответа сервера» Яндекс.Вебмастера и в «Проверке URL» Google Search Console — в отрендеренном HTML должен присутствовать весь контент страницы, а не только шапка и баннер. Если в исходном коде вместо текста пусто, а в браузере с включённым JS всё на месте — у вас проблема, и она стоит трафика.
Порядок элементов в DOM и сниппет
Ещё один недооценённый момент. Если разметка баннера физически стоит в начале <body>, до заголовка H1 и основного текста, то в текстовом слепке страницы первым идёт юридическая формулировка про файлы cookie. На большинстве запросов это ни на что не влияет, но на страницах с бедным контентом поисковик может собрать описание сниппета именно из этого текста. Простое решение: держать разметку баннера последним элементом перед закрывающим тегом body и позиционировать его фиксированно. Визуально ничего не меняется, семантически документ становится чище.
Часть специалистов дополнительно оборачивает текст баннера в <!--noindex--> для Яндекса. Вреда от этого нет, ощутимой пользы — тоже, если баннер и так стоит в конце документа. Гораздо важнее не запрещать в robots.txt файлы CSS и JS, отвечающие за баннер: робот рендерит страницу и должен видеть, что плашка компактна и не перекрывает контент. Закрытый от индексации стиль превращает аккуратную полоску внизу в глазах робота в неизвестный блок — а Google явно оценивает навязчивость межстраничных элементов на мобильных.
Мобильные экраны и навязчивые интерстишалы
Google с 2017 года понижает страницы, где контент на мобильных перекрыт навязчивым межстраничным элементом. Cookie-уведомления из-под санкции выведены отдельной оговоркой — но только те, которые используют разумную долю экрана. Полноэкранное модальное окно с затемнением всего документа под эту оговорку не подпадает, и трактуется ровно так же, как рекламная заглушка.
Практические ориентиры, от которых мы отталкиваемся при мобильной оптимизации:
- Высота плашки — не более 20–25% высоты вьюпорта. На экране 800 пикселей это 160–200 пикселей: хватает на два предложения текста и две кнопки.
- Никакого затемняющего фона на весь экран. Backdrop уместен для оформления заказа, но не для уведомления.
- Скроллинг не блокируется. overflow: hidden на body в момент показа баннера — прямой путь к отказам.
- Кнопка закрытия (или «Принять») — минимум 44×44 пикселя, в зоне досягаемости большого пальца, не в дальнем верхнем углу.
- Учитывайте безопасную зону iPhone: padding-bottom: env(safe-area-inset-bottom), иначе кнопка уедет под системную полосу.
- Проверьте конфликт z-index с фиксированной панелью заказа, кнопкой «Наверх» и виджетом чата. Типичная ситуация: баннер перекрывает кнопку «Купить» на карточке товара — и весь мобильный трафик неделю не может оформить заказ.
Поведенческие метрики: где именно теряются деньги
Для Яндекса поведенческие факторы остаются одним из ключевых блоков ранжирования, и cookie-баннер попадает в них напрямую — потому что стоит между посетителем и контентом в самый чувствительный момент, в первые секунды визита.
Механика простая. В Яндекс.Метрике отказом считается визит с одним просмотром страницы длительностью менее 15 секунд. Пользователь пришёл из выдачи, увидел вместо ответа модальное окно с юридическим текстом, не понял, куда нажимать, вернулся назад. Это одновременно: отказ в Метрике, короткая сессия и возврат в выдачу — то есть худший из возможных сигналов. Один такой посетитель погоды не делает, но если реализация раздражает 20–30% мобильной аудитории, разница видна на уровне раздела.
Что мы видим на проектах при разборе связки «баннер — поведение»:
Перекрытый ответ на запрос
Посетитель искал цену. Первый экран — плашка на треть высоты. Ответа не видно, скролл требует сначала разобраться с баннером. Часть аудитории просто не доходит до контента.
Неравноценный выбор
«Принять всё» — красная и крупная, «Отклонить» — серая ссылка мелким шрифтом. Юридически спорно, поведенчески — вызывает недоверие и раздражение у части посетителей.
Баннер, который возвращается
Cookie согласия ставится на сессию или не ставится вовсе из-за ошибки в домене. Пользователь видит плашку на каждой странице. Глубина просмотра падает мгновенно.
Баннер на закэшированной странице
Полностраничный кэш отдаёт HTML без баннера, скрипт дорисовывает его через секунду. Пользователь видит вспышку, метрика видит layout shift.
Нет способа закрыть
Крестик забыли или он не работает на тач-устройствах. Единственный выход — согласиться. Такие реализации дают всплеск возвратов в выдачу в первые 10 секунд.
Наложение на другие виджеты
Баннер, чат и кнопка обратного звонка занимают нижнюю треть экрана вместе. На мобильном это выглядит как поломка сайта.
Всё перечисленное относится к юзабилити ровно так же, как к SEO: одно и то же изменение одновременно снижает отказы, повышает глубину просмотра и увеличивает конверсию в заявку. Cookie-баннер — редкий случай, когда юридическое требование, метрики скорости и коммерческий результат тянут в одну сторону: делать компактно и незаметно.
Аналитика и согласие: как не ослепнуть
Тонкий вопрос: запускать ли счётчик Яндекс.Метрики до получения согласия. Радикальный подход «ничего не грузим до клика» выглядит юридически безупречно, но имеет цену, которую редко считают заранее.
Цена такая. Часть посетителей закрывает страницу быстрее, чем нажимает кнопку. Часть игнорирует баннер и продолжает читать. Эти визиты в статистику не попадут вообще — счётчик не инициализирован. В результате вы теряете не «немного данных», а именно самые короткие визиты, то есть систематически искажаете картину: средняя длительность сессии выглядит лучше реальной, доля отказов — ниже, источники трафика перекошены в пользу лояльной аудитории. Хуже того, разрыв возникает между двумя окнами наблюдения — до внедрения баннера и после, и весь исторический ряд перестаёт быть сопоставимым.
Практическая схема, которую мы считаем разумным компромиссом:
- Счётчик веб-аналитики инициализируется сразу, обработка описана в политике, баннер информирует об этом при первом визите. Российское регулирование не требует предварительной блокировки в европейском смысле.
- Вебвизор, карты скроллинга и запись форм — по согласию. Это запись поведения конкретного человека, и здесь осторожность оправдана. Технически отключается параметрами инициализации счётчика.
- Рекламные пиксели и ремаркетинг — строго по согласию на маркетинговые cookie. Одновременно это разгружает первую загрузку: пиксели подключаются после взаимодействия, а не на критическом пути.
- Внешние виджеты (карты, видео, чаты) — по клику на плейсхолдер. Приём даёт двойной эффект: и требование выполнено, и с первой загрузки уходят сотни килобайт стороннего кода.
Отдельно про сквозную аналитику: если вы отключаете сбор идентификаторов до согласия, атрибуция заявок к каналам ломается на этих визитах. Это надо заранее обговорить с отделом маркетинга, иначе через квартал вас ждёт разговор о «пропавших конверсиях», которые никуда не пропадали.
Сравнение вариантов реализации
Ниже — типы баннеров, которые встречаются на российских коммерческих сайтах, и их поведение по ключевым параметрам. Столбец «Риск CLS» относится к типовой, а не идеальной реализации.
| Тип реализации | Риск CLS | Влияние на первый экран | Вес кода | Когда уместно |
|---|---|---|---|---|
| Фиксированная плашка внизу | Нулевой (вне потока) | Занимает 10–15% экрана, контент виден | 3–6 КБ | Рекомендуемый вариант по умолчанию для 90% сайтов |
| Компактная карточка в углу | Нулевой | Минимальное, но конфликтует с чатом | 3–6 КБ | Десктоп-ориентированные проекты, B2B |
| Верхняя полоса, сдвигающая контент | Высокий | Сдвигает всю страницу вниз | 2–4 КБ | Только если высота зарезервирована в HTML заранее |
| Модальное окно с затемнением | Нулевой по CLS, высокий по поведенческим | Полностью перекрывает контент | 5–15 КБ | Практически никогда на российском сайте |
| Сторонний CMP-сервис | Средний, зависит от вендора | Зависит от настроек шаблона | 40–150 КБ + новый домен | Мультиязычные проекты с европейской аудиторией |
| Плагин CMS «из коробки» | Средний | Зависит от шаблона | 20–80 КБ, часто с jQuery | Быстрый старт с обязательным последующим аудитом |
| Cookie-wall (блокировка до согласия) | — | Контент недоступен | Любой | Не применять: прямая угроза индексации |
Про плагины отдельно. На WordPress популярные решения для согласий тянут собственные библиотеки, иногда jQuery, свой CSS и админский интерфейс с десятками опций. Реальная функциональность, которая нужна российскому сайту, — показать плашку, запомнить решение, дать возможность передумать — укладывается в несколько килобайт. Если проект уже борется за десятые доли секунды LCP, замена плагина на собственный код часто оказывается самой дешёвой оптимизацией из возможных.
Правильная реализация: пошагово
Согласуйте текст и категории с юристом
До вёрстки. Нужны: финальная формулировка уведомления, перечень категорий cookie (технические, аналитические, рекламные, функциональные), ссылки на политику обработки и на пользовательское соглашение, версия документа для логирования согласий.
Сверстайте баннер прямо в HTML-шаблоне
Разметка отдаётся сервером вместе со страницей, последним блоком перед закрывающим body. Никакой вставки через innerHTML или document.write. Класс по умолчанию — скрытое состояние, показ переключается добавлением класса.
Позиционируйте фиксированно и опишите стиль инлайном
position: fixed; left/right/bottom: 0; z-index выше контента, но ниже критичных виджетов. Критический CSS баннера — в инлайновом блоке в head, чтобы плашка отрисовалась в первом кадре и не мигала. Это 15–20 строк.
Определяйте состояние на клиенте, а не на сервере
Крошечный инлайновый скрипт в head читает cookie согласия и, если согласие есть, сразу проставляет на html класс-признак — баннер не показывается вообще, ни на кадр. Серверная логика показа ломает полностраничный кэш и увеличивает TTFB.
Сохраняйте решение правильно
Cookie, а не только localStorage: cookie доступна серверу и переживает переходы между поддоменами при корректном domain. Срок — 6–12 месяцев. В значение пишите не «1», а состав категорий и версию политики: при обновлении документа согласие нужно запросить заново.
Разнесите инициализацию тегов
По клику «Принять» не запускайте всё в один тик. Сначала спрячьте баннер и отдайте кадр, затем через requestIdleCallback подключайте пиксели и виджеты. INP скажет спасибо, а пользователь не увидит замирания интерфейса.
Добавьте точку отзыва согласия
Ссылка «Настройки cookie» в подвале, открывающая ту же плашку. Важно: обработчик на клик, а не переход на отдельный URL с параметром — иначе вы плодите мусорные адреса, которые робот начнёт обходить.
Логируйте факт согласия асинхронно
Отправка записи в БД — через fetch с keepalive или sendBeacon, без блокировки интерфейса и без ожидания ответа перед скрытием баннера. В записи: отметка времени, версия политики, выбранные категории, обезличенный идентификатор.
Проверьте на полевых данных через 4 недели
Сравните CLS и LCP до и после в отчёте скорости Яндекс.Вебмастера и в данных CrUX, посмотрите долю отказов на мобильных в Метрике по посадочным страницам. Лабораторный прогон Lighthouse эту правку часто не видит вовсе.
Типовые ошибки: проблема, причина, решение
Таблица собрана по результатам технических аудитов — это то, что мы находим чаще всего, когда приходим на проект с уже установленным баннером.
| Проблема | Причина | Решение | Приоритет |
|---|---|---|---|
| CLS вырос с 0,02 до 0,2 после релиза | Баннер вставляется JS в поток документа после DOMContentLoaded | Перевести на position: fixed, разметку отдавать сервером | Критичный |
| LCP прибавил 0,4–0,8 с | Синхронный внешний скрипт CMP в head блокирует парсинг | Собственная реализация либо async + локальное размещение файла | Критичный |
| Контент не виден роботу | Рендеринг основного блока после проверки согласия в SPA | Разделить рендер контента и логику согласия; проверить в Вебмастере | Критичный |
| Баннер показывается на каждой странице | Cookie ставится на текущий путь вместо корня либо без domain | path=/ и корректный domain с точкой для поддоменов | Высокий |
| Плашка мигает на закэшированных страницах | Полностраничный кэш отдаёт разметку без учёта состояния | Состояние определять инлайновым скриптом в head до отрисовки | Высокий |
| Мобильная конверсия просела | Баннер перекрывает кнопку заказа или sticky-панель | Пересчитать z-index и отступы, протестировать на реальных устройствах | Высокий |
| INP на мобильных выше 300 мс | Все теги инициализируются одним синхронным блоком по клику | Разнести через requestIdleCallback, отдать кадр первым | Средний |
| В индексе мусорные URL вида ?cookie=1 | Решение сохраняется через переход по ссылке с параметром | Обработчик клика без навигации; параметр закрыть в robots.txt | Средний |
| Текст про cookie попадает в сниппет | Разметка баннера стоит в начале body до H1 | Перенести блок в конец документа | Низкий |
| Баннер не закрывается на iOS | Обработчик только на click без учёта тач-целей, малая зона нажатия | Кнопка минимум 44×44 px, проверка в реальном Safari | Высокий |
Как измерить реальный эффект
Главная методическая ошибка при проверке cookie-баннера — тестировать его в лаборатории. В своём браузере у вас cookie согласия давно проставлена, и баннер не показывается. В Lighthouse при холодном прогоне он показывается, но часто уже после того, как замер завершён. В итоге инструмент рапортует «всё зелёное», а реальные пользователи получают сдвиг макета.
Порядок корректной проверки
- Инкогнито + троттлинг. Открыть страницу в приватном окне с эмуляцией мобильного устройства и медленной сети (Slow 4G, CPU 4× slowdown). Именно в этих условиях баннер прилетает с ощутимой задержкой.
- Панель Performance в DevTools. Записать загрузку, найти на треке события Layout Shift, включить подсветку регионов сдвига (Rendering → Layout Shift Regions). Каждый сдвиг подсвечивается синим — вы буквально увидите, что и куда прыгнуло.
- Полевые данные. Отчёт «Скорость сайта» в Яндекс.Вебмастере (строится на данных Метрики от реальных посетителей) и CrUX-часть PageSpeed Insights. Обновление полевых данных занимает недели, поэтому сравнивать «до и после» имеет смысл не раньше чем через 28 дней.
- Сегменты в Метрике. Сравнить долю отказов и глубину просмотра на мобильных до и после внедрения, отдельно по посадочным страницам из поиска. Разница по типу устройства обычно нагляднее, чем общая цифра.
- Отрендеренный HTML глазами робота. «Проверка ответа сервера» в Вебмастере и «Проверка URL» в Search Console — убедиться, что весь контент на месте и никакого редиректа на страницу согласия нет.
- Скан краулером. Прогнать сайт Screaming Frog и посмотреть, не появились ли URL с параметрами согласия и не изменились ли коды ответа на посадочных.
ЛОВУШКА ПОВТОРНОГО ПРОГОНА
Второй и последующие запуски PageSpeed Insights для одного URL могут дать другой результат, чем первый: сервис работает без сохранённых cookie, но кэш CDN и прогретый бэкенд меняют тайминги. Не делайте выводов по одному замеру — берите медиану из 5 прогонов и обязательно сверяйте с полевыми данными. Механику расхождения лабораторных и полевых метрик мы подробно разбирали в статье про Core Web Vitals.
Особые случаи
Сайт за CDN и полностраничный кэш
Если перед сайтом стоит кэширующий слой, любая серверная логика показа баннера превращается в проблему: либо кэш отдаёт всем один и тот же вариант (и часть посетителей видит плашку повторно), либо вы выключаете кэш и теряете сотни миллисекунд TTFB. Единственно верное решение — состояние на клиенте: HTML одинаков для всех, а решение о показе принимает инлайновый скрипт, читающий cookie до первой отрисовки. Тонкости кэширования и заголовков Vary разбирали в материале про CDN и SEO.
Мультирегиональные проекты и поддомены
Если у компании сеть поддоменов по городам, согласие логично хранить на общем домене второго уровня: cookie с domain=.example.ru читается всеми поддоменами, и посетитель не увидит баннер заново при переходе из Москвы в Екатеринбург. Обратная ситуация — когда поддомены юридически принадлежат разным лицам: тогда согласия разделяют, и это уже вопрос к юристу, а не к разработчику.
Международные версии
Для проектов с европейской аудиторией российская облегчённая схема не годится: там нужен полноценный предварительный контроль над скриптами. Разумная архитектура — определять регион на CDN и отдавать разным аудиториям разные конфигурации согласия, сохраняя лёгкий вариант для российского трафика. Разделять при этом надо не URL, а поведение: плодить отдельные адреса вида /ru/consent/ и /eu/consent/ не нужно, они только засоряют индекс.
Интернет-магазины
Для e-commerce критичен конфликт баннера с интерфейсом покупки: фиксированная панель «Добавить в корзину», плавающая корзина, всплывающие уведомления о добавлении товара. Перед внедрением проверьте на реальных устройствах весь путь: карточка — корзина — оформление. Отдельно проследите, чтобы отказ от аналитических cookie не ломал работу самой корзины: если технические cookie завязаны на ту же логику согласия, отказ приводит к пустой корзине и потерянному заказу. Технические cookie согласия не требуют — они относятся к обеспечению работоспособности сервиса.
Что даёт правильная реализация в сумме
Если свести всё сказанное к практическому результату, грамотный cookie-баннер — это:
- Нулевой вклад в CLS. Метрика остаётся такой же, какой была до внедрения, — а значит, вся предыдущая работа по стабильности макета не обнуляется.
- 3–6 КБ вместо 40–150. Один домен вместо двух, отсутствие блокирующих запросов на критическом пути.
- Полная доступность контента роботу. Ни редиректов, ни отложенного рендеринга, ни закрытых от индексации стилей.
- Отсутствие мусорных URL. Согласие не порождает адресов с параметрами, которые робот начнёт обходить и индексировать.
- Ровные поведенческие. Плашка не перекрывает ответ на запрос пользователя и не провоцирует возврат в выдачу в первые секунды.
- Выполненное требование закона. С логом согласий, версионированием политики и возможностью отзыва.
Ни один из этих пунктов сам по себе не выводит сайт в ТОП. Но каждый из них — из категории «легко потерять и дорого вернуть». Cookie-баннер относится к тому классу правок, где грамотная реализация не даёт прироста, а безграмотная отнимает уже достигнутое, и именно поэтому мы включаем его проверку в базовый технический аудит наравне с robots.txt и картой сайта. Примеры проектов, где технические правки такого рода дали ощутимый эффект, собраны в нашем портфолио, а состав работ и стоимость сопровождения — на странице цен на продвижение.
И последнее. Cookie-баннер — часть общего впечатления от сайта, которое поисковик оценивает через коммерческие факторы: прозрачные документы, понятные условия, аккуратный интерфейс. Сайт, где политика обработки данных написана человеческим языком, а уведомление не мешает читать, выигрывает не только у робота. Это тот случай, когда «сделать по-человечески» и «сделать правильно для SEO» — одно и то же действие.
Частые вопросы
Прямой нормы «на сайте должен быть баннер» в 152-ФЗ нет. Есть обязанность оператора публиковать политику обработки персональных данных в свободном доступе и получать согласие на обработку. Поскольку идентификаторы аналитических систем связываются с профилем посетителя, сложившаяся практика — информировать пользователя о применении cookie и фиксировать согласие. Форма при этом законом не задана: это может быть компактная плашка внизу экрана, и полноэкранное окно с настройками категорий здесь не требуется.
Прямого фактора «наличие баннера» не существует. Влияние идёт через два канала: скорость и стабильность страницы (Яндекс учитывает скорость и показывает её в отдельном отчёте Вебмастера на данных Метрики) и поведенческие метрики — отказы, глубина просмотра, возвраты в выдачу. Компактная плашка не влияет ни на что. Полноэкранный оверлей на мобильных влияет заметно, причём именно на посадочных страницах из поиска, где посетитель пришёл за конкретным ответом.
Три условия. Первое: элемент позиционируется через position: fixed — он выведен из потока и физически не может сдвинуть соседние блоки. Второе: разметка отдаётся сервером в составе HTML, а не вставляется скриптом после загрузки. Третье: критический CSS баннера подключён инлайном в head, чтобы плашка не появлялась вторым кадром после загрузки внешней таблицы стилей. При соблюдении всех трёх вклад в CLS будет нулевым независимо от скорости сети.
Это вопрос к юристу, но техническую сторону стоит понимать. Российское регулирование не построено на европейском принципе предварительной блокировки, и распространённая практика — инициализировать счётчик сразу, описав обработку в политике и уведомив пользователя баннером. Если вы всё же откладываете счётчик до клика, будьте готовы к систематическому искажению данных: вы потеряете именно короткие визиты, а исторический ряд станет несопоставимым с предыдущими периодами. Компромисс, который мы обычно рекомендуем: базовый счётчик сразу, Вебвизор и запись форм — по согласию.
Почти всегда причина в параметрах cookie. Проверьте три вещи: атрибут path должен быть равен «/», а не текущему разделу; domain должен покрывать все нужные поддомены; срок жизни не должен быть сессионным. Четвёртая по частоте причина — полностраничный кэш, который отдаёт всем одинаковую разметку: тогда решение о показе должен принимать инлайновый скрипт на клиенте, читающий cookie до первой отрисовки. И пятая, редкая: SameSite и Secure выставлены так, что браузер отклоняет cookie на смешанном контенте.
Плагин — быстрый старт с последующим обязательным аудитом. Типичные решения для WordPress и Битрикс тянут собственные библиотеки, иногда jQuery, свой CSS и админку с десятками опций; в сумме 20–80 КБ ради функциональности, которая укладывается в 3–6 КБ. Если проект не борется за скорость, плагин допустим. Если вы уже вытачиваете десятые доли секунды LCP, замена плагина на собственный код — одна из самых дешёвых оптимизаций: полдня работы верстальщика при измеримом эффекте.
Может, в трёх случаях. Первый — cookie-wall с редиректом на страницу согласия: робот получает редирект вместо контента, разделы выпадают из индекса. Второй — отложенный рендеринг в SPA, когда основной компонент монтируется только после проверки согласия: робот видит пустой каркас. Третий, более мягкий — запрет в robots.txt на CSS и JS баннера: робот рендерит страницу и не может оценить, что плашка компактна. Первые два критичны, третий портит оценку мобильного удобства. Проверяется всё за пару минут через «Проверку ответа сервера» в Вебмастере.
Фиксация факта согласия — это ваша доказательная база при проверке, поэтому лог нужен. Разумный минимум записи: отметка времени, версия документа политики, состав выбранных категорий, обезличенный идентификатор посетителя. Хранить — не меньше срока действия самого согласия, а срок обычно ставят 6–12 месяцев, после чего запрос повторяется. Отдельно: при обновлении текста политики версию нужно инкрементировать, тогда баннер автоматически покажется тем, кто соглашался со старой редакцией. Технически запись должна уходить асинхронно, чтобы не задерживать скрытие плашки.
Проверим ваш cookie-баннер и уберём его влияние на скорость и позиции
Найдём скрытые потери: сдвиги макета, лишний сторонний JavaScript, перекрытие первого экрана на мобильных, мусорные URL и риски для индексации. Приведём реализацию к безопасной схеме, сохранив выполнение требований закона. Прозрачный договор, отчёты каждую неделю.
- Пакет «Старт» от 55 000 ₽/мес
- Пакет «Стандарт» 75 000 ₽/мес
- Пакет «Премиум» 95 000 ₽/мес
- Бесплатный аудит и прогноз
- Договор с гарантией результата
- Отчёты каждую неделю
Комментарии (14)
Виталий
Разбор про position: fixed стоит всей статьи. У нас баннер вставлялся скриптом в начало body, и CLS после релиза улетел почти в 0,2 — ровно ваш сценарий. Перевели в фиксированную плашку, вернулись в зелёную зону без единой правки в остальном коде.
Ирина_К
У нас сайт за CDN с полностраничным кэшем, и плашка мигала у всех подряд, даже у тех, кто уже согласился. Долго не могли понять причину, пока не прочитали ваш раздел про особые случаи. Перенесли определение состояния в инлайновый скрипт в head — мигание ушло.
AdminSEO Мастер
Ирина, всё верно — это самая частая связка «кэш плюс серверная логика показа». Проверьте заодно, что кэшируемый HTML одинаков для всех и вы не завели отдельный вариант в Vary: иначе эффективность кэша падает, а TTFB растёт незаметно.
Дмитрий В.
Хорошо, что отдельно оговорили границу ответственности. А то обычно SEO-статьи начинают трактовать 152-ФЗ так, будто это GDPR.
Ольга Ш.
Подскажите по пункту про Метрику. Юрист настаивает, чтобы счётчик вообще не грузился до клика по «Принять». Насколько сильно поедет статистика, если сделать так, и можно ли потом как-то сопоставить данные с прошлым годом?
AdminSEO Мастер
Ольга, решение за юристом, но техническая цена такая: вы потеряете именно самые короткие визиты, поэтому средняя длительность сессии и доля отказов станут выглядеть лучше реальных. Сопоставить ряды строго не выйдет — можно только зафиксировать дату внедрения и дальше сравнивать периоды после неё. Компромисс из статьи (базовый счётчик сразу, Вебвизор и запись форм по согласию) обычно снимает большую часть возражений.
Сергей_бизнес
Владелец небольшого производства. Поставили плагин из коробки, потому что так посоветовал разработчик. Теперь понимаю, что тащу 60 килобайт ради двух кнопок.
vladimir77
А что если баннер нужен только для европейской части аудитории? Не хочется ради 5% посетителей вешать тяжёлый CMP на всех.
AdminSEO Мастер
Владимир, именно об этом раздел про международные версии: регион определяется на уровне CDN, и разным аудиториям отдаётся разная конфигурация согласия. Главное — разделять поведение, а не адреса: отдельные URL вида /eu/consent/ только засоряют индекс и ничего не решают.
Анна Т.
Про то, что роботы не хранят cookie между запросами, знала теоретически, но никогда не связывала это с баннером. Пошла проверять сайт с отключённым JS.
Максим
Немного поспорю насчёт таблицы с типами реализации. Карточка в углу на десктопе выглядит аккуратно, но на мобильном она почти всегда лезет на чат или кнопку «Наверх». Мы в итоге всё равно вернулись к нижней полосе.
Егор_фронт
Совет про Layout Shift Regions в DevTools — прямо находка. Включил подсветку, и сразу стало видно, что прыгает не баннер, а шапка под ним.
Татьяна
У нас в индексе действительно нашлись адреса с параметром согласия, как в таблице ошибок. Согласие сохранялось переходом по ссылке. Спасибо, что назвали причину, я бы сама не догадалась связать одно с другим.
Юрий_ecom
Магазин, около 12 тысяч SKU. Вопрос по разделу про e-commerce: как правильно развести технические cookie корзины и аналитические, чтобы отказ от аналитики не обнулял заказ? Сейчас у нас всё завязано на один флаг согласия, и я боюсь трогать.
AdminSEO Мастер
Юрий, технические cookie обеспечивают работоспособность сервиса и согласия не требуют — их нельзя держать в общей логике с аналитическими. Заведите отдельные ключи под корзину и сессию, а в cookie согласия храните состав категорий, а не единицу. Перед выкаткой обязательно пройдите весь путь карточка — корзина — оформление на реальных устройствах; если нужен взгляд со стороны, мы такие сценарии смотрим в рамках технического аудита.
Николай П.
Отдельное спасибо за напоминание про safe-area-inset-bottom. У нас кнопка «Принять» на айфонах наполовину уезжала под системную полосу, и никто из команды этого не замечал, потому что все тестировали в эмуляторе.
kirill_dev
Про разнесение инициализации через requestIdleCallback согласен полностью. У нас по клику на «Принять» стартовали счётчики, карта и чат одним куском, интерфейс подвисал почти на секунду.
Полина
Скептически отношусь к тезису, что баннер вообще заметно влияет на позиции. Проверяли в PageSpeed после установки — цифры не изменились. Или тут как раз тот случай, про который вы пишете в разделе про измерение?
AdminSEO Мастер
Полина, скорее всего именно тот. В лабораторном прогоне баннер часто не успевает появиться до конца замера, поэтому смотреть надо на полевые данные — отчёт скорости в Вебмастере и CrUX-часть PageSpeed, причём не раньше чем через четыре недели после правки. И отдельно сегмент мобильных в Метрике: отказы там реагируют раньше, чем метрики скорости.