Система згоди без CMP: 0 доларів, два вихідні

Опубліковано:

Власна консент система (кукі-банер): нуль доларів, два вихідні. Не тому що шкода двадцяти баксів на CMP, а тому що хотілося, щоб рішення йшло від потреби, а не навпаки. Та і виглядало, як дуже цікавий виклик - накатити систему згоди на сетап без gtag & web GTM. Розповідаю, що вийшло, що не вийшло і які власні питання я закрив по дорозі.

Консент мод для мене завжди був (і залишається) незручною темою в силу того, що ця тема межує на стику між marTech і юриспруденцією. Навіть розуміючи, як на технічному рівні сигнал про згоду передається до вендора, ти, не будучи профільним юристом, не будеш на 100% впевненим в коректності реалізації системи згоди на сайті. Але в цій статті фокус буде все ж переважно на власному, підкапотному досвіді: як я налаштовував все, що повʼязано зі згодою, приватністю, куками, політиками конфіденційності і всього цього. Одразу обмовлюся: я не юрист. Усе нижче - мій досвід і моє читання норм, а не порада до дії. Перевіряйте на своєму випадку, а краще питайте профільного юриста.

Я сам по собі тривожник і навіть маючи нуль трафіку ще на етапі розробки сайту, вже замислився над тим, що мені буде спокійніше, якщо я точно нічого порушувати не буду. Навряд хтось буде шукати в домашньому блогу невідповідності реалізації до поточних юридичних норм і правових актів, але окрім того, що я люблю спати спокійно, мені закортіло поставити професійну галочку навпроти ачівки «дослідити консент від А до Я».

Але перш ніж занурюватись у норми і сигнали, покажу, що в підсумку вийшло. Банер у два шари: на першому - коротке пояснення і три рівноцінні дії, на другому - категорії з тумблерами і перелік кук, згрупований за тим, хто їх ставить, із описом і терміном життя кожної. Усе, що нижче, - про те, чому він саме такий.

Перший шар вікна згоди: заголовок «Окуляри завжди можна зняти» з намальованими окулярами, далі текст - моя аналітика та cookie допомагають бачити, які матеріали корисні, про що писати далі та що варто фіксити, деталі кожної вашої куки за кнопкою «Налаштувати», жодних закритих дверей, контент відкритий повністю, хоч із ними, хоч без. Унизу дві зелені кнопки «Прийняти все» і «Відхилити все», праворуч золотим - «Налаштувати», у верхньому куті хрестик.

Другий шар вікна згоди «За лаштунками»: три категорії з тумблерами - Необхідні увімкнені, Налаштування вимкнені, Статистика увімкнена. Під статистикою дві таблиці кук із колонками «назва», «для чого» і «скільки живе»: GOOGLE ANALYTICS - _ga і _ga_CVFELT5065, обидві по 400 днів; ЦЕЙ САЙТ - _ozb на 30 днів і _ozu на 400. Унизу кнопки «Прийняти все», «Відхилити все» та «Зберегти вибір».

Чи переймаюсь я за повноту даних?

Чесно, переймався і навіть дуже. Проте зараз відповідь буде «скоріше ні, ніж так». Якщо покласти руку на серце, мені аж некомфортно, коли усвідомлюю, що аналітика або рекламні системи фіксують не 100% сигналів - то ад-блокер працює, то заборона відстеження в кукі-банері, то ще щось… Намагаюся про це не думати.

В період, коли я налаштовував консент вперше, я все шукав способи, як хакнути систему - читав про кукілес пінги, фінгерпрінти + збереження ідентифікаторів НЕ в браузері користувача… Короче, хотів отримувати сигнал від юзерів навіть тоді, коли останній прямо заборонив це робити.

Зараз я хочу поступати екологічно і не конфліктувати з власною совістю. Для власного проекту я прийняв рішення - працюємо в білу + трошки сірої зони в районі кукілес пінгів. Поважаємо рішення юзера на приватність + тримаємо політику конфіденційності актуальною і написану людською мовою, щоб ще більше не конфьюзити користувача (до речі, це вимога статті 12 GDPR - писати «зрозумілою і простою мовою»)

Під чиї закони я попадаю?

З самого початку я планував писати двома мовами, рідною соловʼїною і англійською. Остання, як явний натяк на worldwide і прогнозовано, що моя потенційна цільова аудиторія буде розкидана по всьому світу (та фокус все ж таки переважно на Америку і Європу). Ну і будемо чесними - професійною термінологією, маю таке відчуття, гуглять не тільки інгліш нейтів-спікери.

Найжорсткіші вимоги має Європа - допоки не даси згоди, сайт не має права нічого фіксувати про тебе. Америка в цьому плані простіша - по замовчуванню тебе дозволяють трекати, але ти в будь який момент маєш можливість заборонити робити це.

Тож для початку я поділив світ на умовно три юрисдикції:

  1. strict (opt-IN);
  2. soft (opt-OUT);
  3. free.

Перша - то країни (переважно) Європейської зони, друга - Америка. Фолбеком - решта світу.

Я трохи заморочився і вирішив дещо спростити життя і вам. Для зручності зібрав усі юрисдикції в таблицю. В разі, якщо знайдете помилку або неточність, будь ласка, повідомте мені.

Отже, ви маєте рухатись від того, звідки ваша цільова аудиторія, ваші відвідувачі. Режим вже було проговорено в цій статті, strict - заборонено, поки не дана згода, soft - дозволено, поки користувач не заборонив. Важлива і остання колонка - в кожній юрисдикції є свої нюанси.

Юрисдикція Закон Режим Що це означає для сайту
ЄС, 27 GDPR + ePrivacy 5(3) через нацзакони суворий банер обовʼязковий; до відповіді не можна ні писати, ні читати; доводити згоду мушу я
Норвегія, Ісландія, Ліхтенштейн ті самі, через угоду про ЄЕЗ суворий усе те саме
Китай PIPL ст. 13 суворий банер обовʼязковий; законного інтересу в законі нема зовсім
Індія DPDPA ст. 4 і 7 суворий банер обовʼязковий; «законні використання» - закритий список, аналітики в ньому нема
Туреччина KVKK + настанова щодо кук суворий банер обовʼязковий; тексти згоди й повідомлення мають бути окремими
Квебек Law 25, ст. 8.1 суворий для профілів банер потрібний, якщо профілюємо; до відповіді впізнання і профілювання вимкнені
Британія * PECR reg. 6 + Schedule A1 §5 мʼякий, для мене суворий пільга на власну статистику є, але відпадає при передачі даних назовні
Японія * APPI ст. 31 мʼякий, для мене суворий збирати можна, передавати - ні: передача третій стороні потребує згоди
Швейцарія revFADP ст. 30 і 31 мʼякий банер не обовʼязковий; явно висловлене «ні» виконати зобовʼязаний
Чорногорія Закон про ел. комунікації ст. 124(3) мʼякий потрібна видима можливість відмовитися і пояснення цілей
Бразилія LGPD ст. 7(IX) + настанова ANPD 2024 мʼякий для статистики письмова оцінка інтересу; профілі й реклама - лише зі згодою
Корея PIPA ст. 15(1)(6) мʼякий, але хитко інтерес мусить «явно переважати» права людини - планка вища за європейську
Нігерія NDP Act 2023 + GAID ст. 26 мʼякий письмова оцінка; профілювання і реклама третіми сторонами на цій підставі заборонені
Саудівська Аравія PDPL ст. 6 у ред. 2023 мʼякий оцінка обовʼязкова, чутливі дані виключені
Індонезія UU PDP ст. 20 мʼякий оцінка балансу інтересів
Таїланд PDPA ст. 24(5) і 32 мʼякий заперечення виконати зобовʼязаний, інтерес доводжу я
Канада, федерально PIPEDA, додаток 1, п. 4.3.6 мʼякий годиться припущена згода, тобто зрозуміле повідомлення
Австралія ** Privacy Act 1988, APP 3 зараз не стосується поріг обороту 3 млн AUD звільняє - це мій випадок
ПАР POPIA ст. 11 мʼякий право заперечити з особистих обставин
США 20 законів штатів; Каліфорнія - CCPA § 1798.135 мʼякий плюс сигнал поріг 100 000 споживачів штату блог не дотягує; GPC виконувати у 12 штатах незалежно від порога
Україна Закон № 2297-VI вільний банер не показується; спосіб заперечити - звернення до власника, а не кнопка

* Британія і Японія за законом мʼякі, але в моєму випадку виходить суворо: пільга на власну статистику відпадає, щойно дані йдуть назовні, а вони йдуть у Google.

** Австралії зараз не стосується - поріг обороту 3 млн AUD звільняє. Звільнення скасовують 10.12.2026, після чого режим стане мʼяким.

Хоча юрисдикцій і нормативних актів багато, всі вони, переважно, про одне і те саме. Пропрацюєте логіку роботи сайту і консент банера по трьом категоріям (strict, soft, free) і цього має бути абсолютно достатньо. Принаймні, такий шлях обрав я для себе і цього блогу.

Чи треба мені купляти CMP?

На обʼємі нульового трафіку мова звісно не про 4 мішка деняг (локальний мем), ціна - 10-20 доларів за якийсь мінімальний платний тариф. Та основне питання навіть не в грошах.

В основі мого блогу все крутиться навколо концепції DIY (do it yourself) + я точно не прихильник навішувати на сайт 100500 різного js-коду незрозумілого походження (памʼятаєте, я навіть свідомо відмовився від веб ГТМу). Справа навіть не в масштабі цього блогу, як проекту - на основному місці роботи ми також розробляємо внутрішню CMP. Чому? Бо готові рішення не гнучкі і часто обвішені різним непотребом в якості додаткових функцій. Тож скоро плануємо і переїзд з Enterprise-рішення на наше домашнє, інхаусове.

Повертаємось до блогу. Якщо зафіксувати списком, ось причини, що спонукали мене рухатися в бік власного рішення:

  1. Концепція DIY, як найгнучкіше рішення для подальшої кастомізації;
  2. Мінус одна зайва підписка, економія грошей;
  3. Скрипт банеру готового CMP рішення важить, як 5 моїх сторінок (умовно);
  4. Обʼєктивно, я поки не розумію, за яку технологію компанії CMP беруть гроші, окрім того, що це - коробкове рішення;
  5. Можливість налаштувати кастомну систему редакцій банера і сховища підписів для кожного окремого користувача (цікавий пункт, буде далі окремо);
  6. Не зрозуміло на перший погляд, як інтегрувати готове рішення з чистим серверним трекінгом на сайті;

Якщо думали, що в мене були якісь муки вибору - ні, рішення було прийняте хвилини за три на користь самопалу. Тож система консенту загалом обійшлася в 0 доларів, а розробка і реалізація зайняла приблизно 2 вихідні дні.

Звідки береться сигнал і як він доїжджає до вендора?

Далі буде трохи довідкової інфи, але це та важлива інформація, на котру варто звернути увагу (на мою думку). Також маємо на увазі, що конкретна моя реалізація трекінгу відрізняється від 99% сайтів (згаданий нижче gtag у мене відсутній)

Спочатку сигнал про згоду створюється тим самим gtag’ом, скриптом, на котрому, простими словами, тримається весь трекінг Гугловських сервісів, котрий формує пейлоуд і відправляє хіти з браузера.

Далі, у випадку взаємодії користувача з банером, створюється новий сигнал. Ці сигнали транспортуються від браузеру користувача до вендора через пейлоуд чотирма параметрами

  1. gcd (Google Consent Data)
  2. gcs (Google Consent Status / State /)
  3. npa (Non-personalized Ads)
  4. dma (Digital Markets Act)

Зауважу, що офіційну розшифровку абревіатур Гугл надав лише для NPA, решта - суто домисли від комʼюніті.

GCD

Найінформативніший параметр, значення котрого мають наступний вигляд 13t3t3t3t5l1 (це лише приклад). Як і решта параметрів, передається на рівні кожного івенту і несе в собі поточний стан згоди користувача. Містить в собі наступне:

  1. Версія формату
  2. Чотири пари символів по типам згоди
  3. 3 служебні символи

Навіть не пропоную запамʼятовувати, та якщо цікаво, детальніше можете глянути cheat sheet, що я вам підготував. Але я таке в голові не тримаю і вам воно, мабуть, теж не треба.

Довідкова картка: як влаштоване значення gcd. Угорі приклад 13t3t3t3t5l1, розбитий на дванадцять знаків у рамках - версія формату, чотири пари по типах згоди (ad_storage, analytics_storage, ad_user_data, ad_personalization) і три службові знаки. Нижче: літера це число від 0 до 63, порядковий номер в алфавіті Google; коди станів - 0 нічого не відомо, 1 не задано, 2 заборонено, 3 дозволено; розбір пари 3t по розрядах - делегування типу, неявно виведений стан, оголошення до взаємодії, замовчування сайту, відповідь людини; призначення трьох службових знаків; і правило старшинства: відповідь людини сильніша за замовчування сайту, замовчування - сильніше за неявно виведений стан.

Якщо поки незрозуміло, можете спробувати скористатися декодером - вставляєте значення gcd, а на виході людською мовою буде пояснення за поточний стан згоди користувача.

GCS

Особливого сенсу в існуванні параметру gcs я, мабуть що, не бачу, оскільки він цілком виводиться із значення параметру gcd та жодної додаткової інформації в собі не несе. Єдине застосування його я бачив в кастомних темплейтах тегів і змінних в серверному контейнері.

Та все ж давайте розглянемо, що там передається. Всього 9 унікальних значень

Значення ad_storage analytics_storage
G111 дозволено дозволено
G110 дозволено заборонено
G11- дозволено не задано
G101 заборонено дозволено
G100 заборонено заборонено
G10- заборонено не задано
G1-1 не задано дозволено
G1-0 не задано заборонено
G1-- не задано не задано

Девʼять і виходить: два типи згоди, у кожного три стани - дозволено, заборонено, не задано.

Одну річ варто знати, і в чужих розборах її нема. Стан «не задано» (риска) і стан «заборонено» (нуль) беруться не звідти, звідки здається. Якщо дозвіл виведено неявно, у gcs стає риска, тобто «нічого не відомо». А якщо неявно виведено заборону - стає нуль, тобто «заборонено». Несиметрично: неявне «так» ховається, неявне «ні» проголошується. Чому так - код не каже, він лише так робить.

Але знову ж таки, це не те, що вартує до запамʼятовування

NPA & DMA

NPA, Non-personalized Ads - єдиний параметр «навиворіт», від зворотнього. Це рекламний параметр, котрий вказує, що обʼяви треба показувати всліпу, тобто без урахування того, що Гугл вже знає про користувача. Одиниця в значенні вмикає цей режим, нуль - дефолтне значення. Отже, при npa = 1 НЕ буде працювати наступне:

  1. таргетинг по аудиторіям
  2. демографічний таргетинг
  3. підбір по минулій поведінці юзера (пошукові запити, переглянуті сайти, гео історія і тд)
  4. Гугл не використовує нову інформацію про користувача для добору оголошень

Варто також сказати, що нічого нового цей параметр не несе - все вже зашито в gcd.

DMA, Digital Markets Act - параметр, названий не на честь технології, а на честь закону. Стосується він ні мене, ні вас і навіть не ваших користувачів. Стосується він великих «гравців»:

  1. Google
  2. Apple
  3. Meta
  4. Amazon
  5. Microsoft;
  6. ByteDance (TikTok);
  7. Booking.com

Це - європейський акт про конкуренцію, суть: велика платформа не може склеювати дані про юзера між своїми сервісами без його згоди. Наприклад: ви шукали в Пошуку «оренда авто в Барселоні», а за годину відкрили Youtube. Без вашої згоди Гугл не має права показати вам там рекламу прокату - бо це означало б скласти докупи те, що він знає про вас із двох своїх сервісів. Зі згодою - має. Саме звідси і взялися флажки ad_user_data & ad_personalization.

dma = 1 ставиться, коли (одночасно):

  1. консент система оголосила, що працює TCF АБО режим згоди рекламодавця;
  2. консент система повідомила, що вважає трафік таким, що підпадає під GDPR;

В мене dma завжди нуль бо ніколи не виконується перша умова.

Якщо підсумувати, самодостатні серед чотирьох параметрів лише два: gcd & dma. gcs & npa можна отримати на основі значення gcd.

Як трекаються користувачі, котрі зробили Reject All?

Тут трохи нотаток про так звані cookieless хіти. По суті, це такі ж реквести, як і при наданій згоді за виключенням, що в них не передається жодної сталої інформації (user_pseudo_id, session_id тощо), по котрій можливо звʼязати ці реквести між собою і асоціювати з конкретним користувачем.

Окремо про IP - не передати його неможливо в принципі бо він є в будь-якому http реквесті. Але передати != автоматично записати. Власне, що я і роблю - якщо у користувача ще нема згоди, браузер айпішник відправляє, але я зі своєї сторони його просто не читаю і не записую.

Також в кукілес пінг не потрапляють шість параметрів:

Параметр Що це
sid айді сесії: секунди, коли вона почалася
sct яка це сесія по рахунку в цього юзера
seg чи була сесія залученою
_fv перший візит: куки сесії цього отримувача ще не було
_nsi новий для сайту: ідентифікатор браузера створено заново
_ss початок сесії

Усі шість виводяться з куки, а при відмові куки нема. Надіслати їх означало б вигадати сесію людині, якої я не впізнаю.

Окремо закцентую увагу на cid. Це client_id (user_pseudo_id), ідентифікатор браузеру. По ньому рахуються користувачі. При згоді цей ідентифікатор записується в куку. Коли згоди нема, писати їх не можемо, та вони генеруються все одно. Є нюанс: цей ідентифікатор генерується заново на кожному завантаженні сторінки. Таким чином склейка подій однієї людини в загальний користувацький шлях стає неможливою. Другий нюанс: у межах одного завантаження ідентифікатор однаковий, тож події, що відбуваються в рамках одного завантаження сторінки, мають спільний, але все ж тимчасовий cid (client_id або user_pseudo_id)

Такий сірий Гугл

Коли людина натискає кнопку «Заборонити» в кукі-банері, гтаг насправді не замовкає. На такому ж механізмі побудована логіка на цьому сайті, що описана вище - події шлються дещо урізаними + не записуються куки. Гугл такий підхід взагалі не приховує і пише прямим текстом

When consent is denied, consent state and measurements without cookies are sent

Оборона такого рішення від Гугла тримається на трьох пунктах:

  1. «ми нічого не пишемо на пристрій юзера»;
  2. «айпі потрібен, щоб визначити гео користувача. Далі ми його не зберігаємо»;
  3. «по даним, що все ж таки відправляються, людину не впізнати»;

Наче навіть виглядає безпечно. Та ePrivacy писався не тільки про зберігання кук. Він - а саме стаття 5(3) Директиви 2002/58/ЄС - про дві різні дії: записати щось юзеру на пристрій і взяти щось з пристрою юзера. Під забороною і те, і те, але достатньо однієї умови.

Тут і схована конструкція. «Нічого не пишемо» - Гугл спокійно закриває першу дію, прямо ігноруючи другу. А саме про останню у регуляторів сказано однозначно. Якщо інформація «відправляється назад по мережі на сервер», це і є отримання доступу, і те, що її порахували прямо на пристрої, нічого не змінює.

Інакше кажучи: закон дивиться не на те, де зроблено обчислення, а на те, чи покинули дані пристрій. Скрипт може порахувати роздільну здатність екрана в браузері, нікуди не звертаючись, - і поки число лишається там, питань нема. Щойно воно пішло на сервер, це вже «отримання доступу», і стаття 5(3) застосовується.

Окремо про айпі. «Не зберігаю» - це відповідь не на те питання. Закон питає саме про отримання. Можна нічого не зберігати, але доступ вже відбувся.

«Людину не впізнати» - тут краще читати мовою оригіналу: «cannot directly identify an individual». Ключове слово «directly». Гляньте, в довідці гугл сам перелічує у складі пінгу: юзер-агент, роздільна здатність екрану, айпі, реферер, час і рандомне число на кожне завантаження сторінки. Якщо вдивитися, то цього набору достатньо, щоб зробити фінгерпрінт пристрою. І Гугл не каже, що займається подібним, він каже, що напряму людину не впізнати. Формально він не бреше бо кожен параметр хіту поокремо насправді нічого не значить. Цінність їх виникає тоді, коли вони передаються в купі.

При цьому порушенням таку схему ніхто досі з регуляторів не назвав. Один текст закону - стаття 5(3) ePrivacy, - дві трактовки: регулятора і Гуглу. І перевіряти, чиє тлумачення коректніше, поки ніхто не став.

Тож щойно я розібрав аргументи, на яких сам і стою. Сірість у мене запозичена у Гугла і ризик я беру свідомо.

Отже, коли користувач робить відмову, у мене все одно він трекається. Так, з обмеженнями і без можливості впізнати його завтра, але трекається. Але мабуть це моя межа совісті і мені спокійніше назвати це вголос, ніж замовчувати.

Які є вимоги до банеру?

За часів, коли ми командою налаштовували консент мод на роботі за допомогою дорогужчої CMP, я памʼятаю той нескінченний потік питань «А що», «А як» і тд в контексті того, що має бути відображено (і в якому вигляді) в самому банері.

Згадаю перелік питань, котрими я задавався і котрі вважав за необхідне закрити, одразу під спойлерами - відповіді:

Наскільки ОК мати лише маленький банер «Ми збираємо ваші дані» і одну кнопку ОК в якості згоди?

Не ок. EDPB (European Data Protection Board) прямо пише: відсутність варіанту відмовитись на будь-якому екрані банеру, де є кнопка згоди - пряме порушення. Отже, якщо є кнопка «ОК», на тому ж рівні має бути і кнопка «НЕ ОК». І обидві мають бути рівноцінними і однаково привабливими до натискання.

Чи є фіксовані вимоги до текстів кнопок і посилань?

Нема. Є заборона на введення користувача в оману. EDPB свідомо відмовляється задавати якісь візуальні стандарти оформлення банерів і в разі чого кожен окремий кейс розглядають індивідуально. Текст має бути читабельним, однозначним

Чи є вимоги до розміру банеру і чи можна приховати його, не давши жодної відповіді?

Вимог до розміру нема - хоч на половину сторінки. А от відсутність чіткого волевиявлення однозначно прирівнюється до повної відмови.

Чи можна закрити контент банером, зробити такий собі Cookie Wall, не пускаючи користувача до сайту допоки він не дасть свою відповідь?

EDPB вважає це певним елементом примусу, а отже подібні відповіді не розцінює, як справжнє волевиявлення. Тож раджу не ризикувати подібним, якщо маєте значну частку трафіку з країн Європи.

Чи обовʼязкова розгорнута інфа про кожну куку?

Сам перелік кук обовʼязковий, не обовʼязково тримати саме в банері повний опис кожної окремої куки (можна перенести на політику конфіденційності). Вести список і доводити доцільність кожної окремої куки - обовʼязок власника сайту. Що важливо: регулятори не чекають від вас досконалого списку. Вони самі визнають, що куки змінюються регулярно. Вони скоріше чекають дисципліни роботи зі списком і його актуальності.

Що має входити в опис кожної окремої куки?

Імʼя, хто ставить (вендор), навіщо, скільки живе, правова підстава. Якщо дані з куки отримує третя сторона, тоді додатково варто вказати посилання на її політику обробки даних.

Чи є вимоги до категорій кук - назви, в якому розрізі і тд?

Такої сутності, як категорії, регулятори не задають взагалі. Задається гранулярність: користувач повинен мати можливість, наприклад, відмовитись від реклами, але дозволити відстежувати себе аналітикою. Категорично заборонено штучно роздувати категорію необхідних кук, пхаючи туди, наприклад, аналітичні куки.

Як тримати список кук актуальним?

Чесна відповідь: тримати завжди повним і актуальним - ніяк, і регулятори це прямо визнають. Куки можуть змінюватися односторонньо (зі сторони вендорів), а друга сторона не зобовʼязана кожен день моніторити зміни в політиках вендорів. Тому від власників сайту і очікують не ідеального списку, а розуміння, що список живий і час від часу оновлюється.

Чи можна зробити універсальний банер одразу для всіх юрисдикцій?

Банер може бути однаковим, але не логіка роботи. Найбанальніший приклад: Європа спочатку забороняє, а потім питає, Америка - навпаки, спочатку дозволяє, а потім може запитати. Плюс для Америки є сигнал GPC, котрий станом на вересень 2026 зобовʼязані виконувати 12 штатів: Каліфорнія, Колорадо, Коннектикут, Делавер, Меріленд, Міннесота, Монтана, Небраска, Нью-Гемпшир, Нью-Джерсі, Орегон і Техас. Тобто в «soft» режимі банер перестає бути головним. Головним стає хедер Sec-GPC: 1 від твого браузеру.

Якщо браузер каже «ні», а юзер натискає «так»?

Сигнал GPC генерується на рівні браузеру і, що логічно, розповсюджується на всі сайти, котрі відвідує користувач. Каліфорнійські правила вирішують однозначно: спочатку виконай заборону, а потім вже можеш повідомити користувача про це і перепитати його згоди. Тобто просто натискання «Прийняти все» недостатньо - позитивний сигнал GPC скасовує саме усвідомлена згода, котру юзер дав тоді, коли йому вказали, що браузер просить протилежного.

Отже, головне питання тут не «як скласти список», а «звідки його взяти»

Перелік береться від інструментів, що очевидно: маєте рекламу Гугл Адсу? Йдете в політику від Гугла, забираєте собі всі куки, що стосуються реклами. Таким чином нова кука не зможе зʼявитися у користувачів від сервісу, котрий ви не встановлювали. Проте тут межа: подібний опис дає вам повний перелік джерел, але не гарантує повного списку кук - вендор може втиху додати нову куку, а ви вчасно цей момент не прослідкуєте (не будете ж ви кожен день заходити на сторінку його політики обробки даних).

Я вирішив це питання одним словником кук і трьома перевірками. Словник - файл, в котрому ведеться опис кожної куки: імʼя, категорія, хто пише, кому йдуть дані, скільки живе. Звідси перелік підтягується в кукі-банер на другий шар, а також на сторінку політики конфіденційності. Розсинхрон виключено, оскільки джерело одне.

Далі - перевірки з фактом. Кожна відповідає на своє питання.

Перевірка №1: код, або що взагалі може поставитись. На кожній збірці сайту перевірка вичитує код і компонує список кук, що можуть проставитись. Кожна назва куки з цього списку зобовʼязана знаходитись у словнику і навпаки: якщо запис є, а в коді куки нема - ловимо червоний чек.

Перевірка №2: браузер, або що поставилось не від серверу. Прогін справжнім браузером (використовуючи Playwright) по зібраній статиці: сторінки віддає файловий сервер, а мій воркер Cloudflare при цьому, очевидно ж, недоступний. Отже фіксується виключно те, що ставиться в браузері, а не від імені серверу.

Перевірка №3: склад сирих даних, назви кук (без значень), що поставились у живих людей. І куки звідти мають бути в словнику. Зʼявляється на складі невідома кука - при наступному прогоні чеків на складі буде горіти червоним.

Жодна з перелічених перевірок сама по собі не повна: код не знає, що виконалось, браузер бачить лише завчасно прописані сценарії, а склад показує список заднім числом. Разом вони перекривають три різні сліпі зони, і допоки на моєму сайті нема чужих скриптів, цих трьох перевірок мені буде вистачати.

Останній момент: у мене є навіть версіювання, як списку кук, так і банеру з політикою конфіденційності. Якщо я зроблю зміну в поточному списку кук, автоматично змінюються як версія банеру, так і політики, оскільки список кук являється їх невідʼємною частиною.

Журнал згод - як захистити себе юридично

Три слова, які далі зустрічаються постійно. Щоб не плутатися:

  1. Підпис - одна відповідь однієї людини: що дозволила, коли, з якої сторінки і в якому режимі. Лежить окремим файлом, і саме він є доказом;
  2. Редакція - стан того, що їй показали: список кук, вікно згоди разом з його виглядом і кнопками, текст політики конфіденційності. Змінилося будь-що з цього - зʼявилася нова редакція;
  3. Відбиток - вісім знаків, якими названа редакція. Підпис посилається на редакції саме відбитками, а не переказує їх зміст.

Що вимагає закон

Стаття 7(1) GDPR (більш людською мовою): власник даних має бути здатним довести те, що конкретна особа давала згоду. Яким шляхом буде доводити, закон не каже.

EDPB у настанові щодо згоди, п. 107: «The GDPR does not prescribe exactly how this must be done». В тому ж місці і відповідь на питання, скільки зберігати цей доказ - допоки дані обробляються, в силі і обовʼязок показати згоду на обробку цих даних.

CNIL додатково перелічує придатні варіанти:

  1. Відбиток коду з таймстемпом;
  2. Знімок екрану з банером;
  3. Сторонні зовнішні аудити;
  4. Історія налаштувань в CMP;

Чогось накшталт особистого кабінету «мої дані» в цьому переліку нема, але все ж таки я захотів дати змогу кожному глянути на власний підпис.

Редакції банера і політики конфіденційності

Запис без версії тексту, котру показали людині, на мою думку, не доводить нічого. Тому кожен підпис у моїй системі несе три відбитки редакцій:

  1. версія словника кук;
  2. версія банеру;
  3. версія політики конфіденційності

по два варіанти, окремо на кожну мову. Відбиток - вісім знаків, порахованих від самого тексту в один бік (хеш). Разом з ним зберігається і сама редакція: інакше виходить ключ без замка.

Оновилась версія політики конфіденційності - створився новий запис на складі, усі наступні підписи посилатимуться на нову редакцію. Так само з куками і банером. Окремо зазначу, що оскільки список кук являється складовою як банеру, так і політики, в разі оновлення першого автоматично робиться версіонування усіх трьох сутностей одночасно.

Як я зберігаю згоду кожного окремого користувача

Журнал зберігає підписи. У користувача його ідентифікатор субʼєкта (subject_id) зберігається в кукі _ozr з характеристикою Path=/_consent/, тобто браузер робить запис лише на службову адресу. Окрім як на цьому шляху, більше кука ніде не існує. Тож такою сегментацією ми виключаємо можливість потрапляння subject_id в аналітичні дані.

Сховище журналу згод, розділ records: список папок, названих номерами людей - 03038ae5-8be6-4829-9af3-c7288ac92938, 0682db9d-d89e-4561-99a8-40df92c0eab2 і далі, серед них e730a02c-379a-46a9-b77c-672248466619 з попереднього знімка. Кожна папка - один субʼєкт, усередині лежать його підписи.Сховище журналу згод, розділ records: список папок, названих номерами людей - 03038ae5-8be6-4829-9af3-c7288ac92938, 0682db9d-d89e-4561-99a8-40df92c0eab2 і далі, серед них e730a02c-379a-46a9-b77c-672248466619 з попереднього знімка. Кожна папка - один субʼєкт, усередині лежать його підписи.

Сам підпис - це девʼятнадцять полів:

Поле Що це
record номер цього підпису
subject номер людини з куки _ozr
at коли підпис створено
decided_at коли людина натиснула кнопку
ts той самий час, але числом
button яку саме кнопку натиснула
origin знято з натискання чи догнано по куці
action підсумок одним словом: усе, частково чи відмова
granted що дозволила
denied що відхилила
mode режим: суворий, мʼякий чи вільний
country країна, з якої прийшов запит
is_eu чи підпадає захід під європейські правила
lang мова вікна, яке показали
page сторінка, з якої натиснуто кнопку
cookies_version відбиток редакції списку кук
banner_version відбиток редакції вікна
policy_version відбиток редакції політики
expires_at до якої дати діє

На сторінці підпису є рядок, якого в самому підписі нема зовсім, - Аналітика. Багато хто впізнає в ньому рідненький client_id, він же user_pseudo_id. У самому підписі його нема: там лише номер підпису, номер людини, рішення, режим і країна, мова, три відбитки редакцій та дати. Показує його сторінка підпису, і тільки в ту мить, коли ви її відкрили. Потрібен він тому, що прохання «видаліть мої дані» стосується не журналу згод, а складу івентів - там людина знаходиться саме за цим номером, і ні за яким іншим.

Сторінка «показати мій запис про згоду»: запис 3e9a6f4c-5710-4ec0-9c4f-db94ab6e2a3e, людина e730a02c-379a-46a9-b77c-672248466619, рішення ухвалене 7 вересня 2026 року, дозволено preferences, statistics і marketing, відхилено нічого, кнопка accept_all, режим strict (DE), діє до 12 жовтня 2027 року, вікно 112cb852 (uk), куки 520ed672, політика 7a395c17, джерело - знято з вашого натискання, аналітика 368737993.1785734098. Унизу: рішень усього 2 і адреса, на яку писати, щоб ці дані видалили.Сторінка «показати мій запис про згоду»: запис 3e9a6f4c-5710-4ec0-9c4f-db94ab6e2a3e, людина e730a02c-379a-46a9-b77c-672248466619, рішення ухвалене 7 вересня 2026 року, дозволено preferences, statistics і marketing, відхилено нічого, кнопка accept_all, режим strict (DE), діє до 12 жовтня 2027 року, вікно 112cb852 (uk), куки 520ed672, політика 7a395c17, джерело - знято з вашого натискання, аналітика 368737993.1785734098. Унизу: рішень усього 2 і адреса, на яку писати, щоб ці дані видалили.

Це - найтонше місце всієї схеми. Номер підпису живе в журналі консенту, client_id - у складі івентів. Поки вони нарізно, склад лишається знеособленим: там просто браузери без персоналій. Варто записати ці два айдішники поруч бодай раз - і кожен івент стає івентом конкретної людини, яка колись натиснула кнопку в моєму вікні.

Тому сторінка «показати мій підпис про згоду» показує обидва номери поруч і не зберігає жодного. Це єдиний екран, де вони зустрічаються, і зустріч триває рівно стільки, скільки ви цю сторінку читаєте. Перегляд цієї сторінки в аналітику теж не потрапляє - інакше я сам зробив би те, проти чого виступаю.

Як це дістається, коли знадобиться

Сценарій простий. Приходить мені лист з проханням показати, на що і коли погоджувався користувач. У листі - копіпаст зі сторінки «показати мій запис про згоду»*. По номеру підпису я знаходжу його файл, а в ньому три відбитки - словника кук, банера і політики. Далі три звернення до сховища, по одному на кожен відбиток.

Сховище журналу згод, розділ versions: папки редакцій банера - banner-112cb852-uk, banner-0dec4001-uk, banner-15408399-en та інші - і файли редакцій словника кук і політики: cookies-520ed672.json на 6,59 КБ, policy-7a395c17-uk.json на 13,36 КБ. Саме ці три відбитки - 112cb852, 520ed672 і 7a395c17 - записані в підписі вище.Сховище журналу згод, розділ versions: папки редакцій банера - banner-112cb852-uk, banner-0dec4001-uk, banner-15408399-en та інші - і файли редакцій словника кук і політики: cookies-520ed672.json на 6,59 КБ, policy-7a395c17-uk.json на 13,36 КБ. Саме ці три відбитки - 112cb852, 520ed672 і 7a395c17 - записані в підписі вище.

Політика приїжджає текстом цілком, поруч дата, коли редакція зʼявилась уперше. Словник - списком кук, які показувались у тій редакції. Банер - двома файлами: parts.json з вихідними текстами вікна (розмітка обох шарів, оформлення, картинки - рівно те, що віддав сервер для створення банеру) і сам banner.html, зібраний з них.

Саме останній файл і є те, заради чого все робилось. Він самодостатній: усе оформлення всередині, жодного зовнішнього референсу. Відкривається без інтернету, через рік, на чужому компʼютері - і показує той самий банер з тими самими кнопками та тією самою таблицею кук. Сайт до того часу може бути переписаний тричі, на редакцію це не вплине.

І про те, що робить цей banner.html доказом, а не картинкою. Доказ - не сам банер, а супутні файли поруч з ним і відбиток, порахований від них. Будь-хто, у кого є ці файли, може перерахувати відбиток і звірити з номером, записаним у підписі. Збіглось - це та сама редакція. Не збіглось - редакція не та. Вісім знаків тут працюють як номер редакції, а не як криптографічний захист: підібрати інший текст з таким самим коротким відбитком теоретично можна, тому доказом служить звʼязка «підпис плюс редакція в моєму сховищі», а не стійкість самого числа.

Замість висновку

Отже, що я виніс під час розробки власного рішення і написання цієї статті?

В Європі має бути фокус на двох законах, а не на одному: GDPR + ePrivacy. Останній - про пристрій, як про запис на нього (кукі), так і про те, щоб якусь інформацію зчитати (хедери, юзер агент і тд). GDPR - про персональні дані і на якій підставі ми їх обробляємо.

Це різні предмети і плутанина між ними породжує половину суперечок про консент у Європі. А от решта світу спирається переважно (бо все ж є виключення) на один закон.

Прозорість не дає прав. Розповісти про збір - обовʼязок за статтею 13 GDPR. Мати право збирати - окреме питання підстави: згода, договір чи законний інтерес. Написати в політиці і вважати, що питання закрито - найпоширеніша підміна. Сайт чесно написав, що аналітика строго необхідна, і на тому заспокоївся. Але запис у політиці не створює необхідності: на першому ж проханні довести, чому аналітика необхідна, захист посиплеться.

З чотирьох параметрів, що стосуються передачі консент-сигналу по жилах у пейлоуді, несуть «додану вартість» лише двоє: gcd & dma. gcs & npa виводяться з gcd.

Гугл при відмові не замовкає, і я теж. Ця «сірість» у мене запозичена і ризик я беру свідомо. Чому? Бо порушенням жодний регулятор це ще не назвав. Отже роблю висновок, що поки «можна, але з обережністю».

Дати відмову в банері має бути так само просто, як і дати згоду. Це чи не найголовніша вимога до банера і вона про дії, а не про естетику. Один клік на згоду і три на відмову через другий шар банеру - вже порушення. Колір регулятори оцінюють випадок за випадком і явно забороняють лише одне: кнопку з нечитабельним текстом або відверто слабким контрастом.

Категорії кук (назва категорії, вісь категорії) ніде не задані. Задана лише гранулярність: має бути можливість відмовитися від одного і дати згоду на інше.

Чотири категорії (необхідні, функціональні, аналітика, реклама) - це скоріше традиція, ніж вимога. І мене дивує, що сформувався саме такий набір. У Google щодо реклами три окремі сигнали:

  1. ad_storage - чи можна писати рекламні ідентифікатори;
  2. ad_user_data - чи можна віддавати йому дані про мене;
  3. ad_personalization - чи можна збирати мене в аудиторії.

Я не бачу причини забороняти сайту записати клік-айді, по якому я прийшов, і водночас не хочу потрапити в чиюсь аудиторію чи віддати Гуглу свою пошту, хай навіть у вигляді хеша. Це три різні рішення, а в кожному банері, який я відкривав, вони гасяться одним кліком під спільною назвою «маркетинг».

Причина, підозрюю, банальна: більше перемикачів - нижча конверсія банера. Але нічого не заважає розділити «маркетинг» на дві категорії і дати людині вибрати точніше. Я так і зробив би, якби вмикав рекламу (та поки в мене суцільний «маркетинг»)

Cookie Wall. Перекривати контент, поки людина не відповість, регулятори вважають примусом: вибір під тиском - не вибір. Тут, щоправда, згоди між ними немає: EDPB категоричний, а у Франції загальний заборонний підхід скасувала Держрада, і там кожен кейс розглядається поокремо.

Ох, відчуття, що навіть для висновку треба власний висновок, при тому, що є ще в голові, що хотілося б додатково зазначити. Та буду зупинятись. В цілому, я дуже задоволений результатом проробленої роботи і глибиною моїх досліджень. В разі питань і побажань, будь ласка, звертайтесь за кнопкою нижче.

Напишіть - все прочитаю і всім відповім.

Або просто напишіть на hello@ozthewizard.com