Реалізація cookie-банера
Реалізуємо cookie-банер з блокуванням скриптів під ключ відповідно до GDPR, термін 2–3 дні. Нещодавно до нас звернувся інтернет-магазин з 50+ скриптами аналітики та реклами — вони не могли довести регулятору, що згода була усвідомленою. Без гранулярного cookie-бара сайт ризикує отримати штрафи до 20 млн євро за порушення GDPR. Багато власників ресурсів досі використовують простий попап «Ми використовуємо куки», який не відповідає законодавству. Згода має бути явною, добровільною та категоризованою. Ми розробляємо cookie-бар під ключ, який блокує скрипти до підтвердження користувача, фіксує кожну згоду та дозволяє легко її відкликати. Наш досвід — 7+ років у продакшені, реалізували понад 50 проектів з повною відповідністю GDPR.
Чому важливий гранулярний cookie-бар?
GDPR вимагає, щоб користувач міг погодитись на кожен тип куків окремо. Категорії «функціональні», «аналітичні», «маркетингові» — мінімальний набір. Без гранулярності ви збираєте або все, або нічого, що знижує конверсію та довіру. Крім того, при перевірці легко довести, що згода була усвідомленою. Ми гарантуємо, що наш cookie-бар відповідає всім вимогам Регламенту. Економія на юридичних ризиках: штрафи за невідповідність можуть сягати 4% від річного обороту компанії.
Як ми реалізуємо cookie-бар: від аудиту до деплою
Процес роботи
- Аналітика — визначаємо, які скрипти та куки використовуються на сайті. В середньому на типовому проекті знаходимо 10–15 трекерів.
- Проектування — проектуємо логіку згоди, категорії, UI-компонент. Використовуємо React 18 з TypeScript.
- Реалізація — пишемо React-компонент та PHP-контролер (див. код нижче).
- Тестування — перевіряємо блокування скриптів, запис у localStorage, відправлення на сервер.
- Деплой — інтегруємо в проект, налаштовуємо CI/CD.
Самописне рішення в 2 рази дешевше готових бібліотек при річному використанні. Додавання аудит-логу та системи відкликання — ще 1–2 дні.
Що входить в роботу
- React-компонент cookie-бара з кастомізацією стилів.
- PHP API для збереження згод у БД.
- Інтеграція з Google Analytics, Yandex.Metrica, Facebook Pixel (з блокуванням до згоди).
- Документація по API та налаштуванню.
- Підтримка протягом 2 тижнів після деплою.
Як блокувати скрипти до отримання згоди?
У нашому рішенні скрипти аналітики завантажуються тільки після виклику applyConsent з відповідними прапорами. Наприклад, функція loadGoogleAnalytics динамічно створює <script> та вставляє його в <head> тільки якщо consent.analytics === true. Це гарантує, що жоден трекер не спрацює до явного дозволу користувача. Такий підхід у 100% випадків проходить перевірку на відповідність GDPR.
Категорії куків
| Категорія | Обов'язкова згода | Приклади |
|---|---|---|
| Необхідні | Ні | session, CSRF-токен, cookie-consent |
| Функціональні | Так | мова, тема, запам'ятати мене |
| Аналітичні | Так | Google Analytics, Yandex.Metrica |
| Маркетингові | Так | Google Ads, Facebook Pixel |
React компонент
import { useState, useEffect } from 'react';
interface CookieConsent {
functional: boolean;
analytics: boolean;
marketing: boolean;
}
const CONSENT_KEY = 'cookie_consent_v2';
function useCookieConsent() {
const [consent, setConsent] = useState<CookieConsent | null>(null);
const [showBanner, setShowBanner] = useState(false);
useEffect(() => {
const saved = localStorage.getItem(CONSENT_KEY);
if (saved) {
const parsed = JSON.parse(saved);
setConsent(parsed);
applyConsent(parsed);
} else {
setShowBanner(true);
}
}, []);
const acceptAll = () => {
const all = { functional: true, analytics: true, marketing: true };
save(all);
};
const rejectAll = () => {
const none = { functional: false, analytics: false, marketing: false };
save(none);
};
const save = (c: CookieConsent) => {
localStorage.setItem(CONSENT_KEY, JSON.stringify({
...c,
updatedAt: new Date().toISOString(),
}));
setConsent(c);
setShowBanner(false);
applyConsent(c);
reportConsent(c);
};
return { consent, showBanner, acceptAll, rejectAll, save, openSettings: () => setShowBanner(true) };
}
function applyConsent(consent: CookieConsent) {
// Включити/вимкнути скрипти аналітики
if (consent.analytics) {
loadGoogleAnalytics();
loadYandexMetrica();
}
if (consent.marketing) {
loadFacebookPixel();
}
}
async function reportConsent(consent: CookieConsent) {
await fetch('/api/cookie-consent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ consent, ip: undefined }), // IP визначає сервер
});
}
export function CookieBanner() {
const { showBanner, acceptAll, rejectAll, save } = useCookieConsent();
const [showDetails, setShowDetails] = useState(false);
const [selections, setSelections] = useState({ functional: false, analytics: false, marketing: false });
if (!showBanner) return null;
return (
<div className="cookie-banner" role="dialog" aria-label="Налаштування cookies">
<div className="cookie-banner__content">
<h2>Ми використовуємо cookies</h2>
<p>
Ми використовуємо необхідні кукі для роботи сайту. З вашої згоди — аналітичні та маркетингові.{' '}
<a href="/cookie-policy">Докладніше</a>
</p>
{showDetails && (
<div className="cookie-categories">
<label className="cookie-category cookie-category--required">
<input type="checkbox" checked disabled />
<span>Необхідні</span>
<small>Завжди включені. Забезпечують базову роботу сайту.</small>
</label>
{(['functional', 'analytics', 'marketing'] as const).map(cat => (
<label key={cat} className="cookie-category">
<input
type="checkbox"
checked={selections[cat]}
onChange={e => setSelections(s => ({ ...s, [cat]: e.target.checked }))}
/>
<span>{{ functional: 'Функціональні', analytics: 'Аналітичні', marketing: 'Маркетингові' }[cat]}</span>
</label>
))}
</div>
)}
<div className="cookie-banner__actions">
<button onClick={rejectAll} className="btn btn--outline">Відхилити все</button>
<button onClick={() => setShowDetails(!showDetails)} className="btn btn--outline">Налаштувати</button>
{showDetails
? <button onClick={() => save(selections)} className="btn btn--primary">Зберегти</button>
: <button onClick={acceptAll} className="btn btn--primary">Прийняти все</button>
}
</div>
</div>
</div>
);
}
.cookie-banner {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: white;
border-top: 1px solid #e5e7eb;
box-shadow: 0 -4px 24px rgba(0,0,0,0.08);
z-index: 9999;
padding: 1.5rem;
}
.cookie-banner__actions {
display: flex;
gap: 0.75rem;
margin-top: 1rem;
flex-wrap: wrap;
}
Сервер: фіксація згоди
class CookieConsentController extends Controller
{
public function store(Request $request): JsonResponse
{
$request->validate([
'consent.functional' => 'required|boolean',
'consent.analytics' => 'required|boolean',
'consent.marketing' => 'required|boolean',
]);
CookieConsent::create([
'user_id' => auth()->id(),
'session_id' => $request->session()->getId(),
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
'consent' => $request->consent,
'version' => config('cookies.policy_version', '2.0'),
'consented_at' => now(),
]);
return response()->json(['status' => 'saved']);
}
}
Підключення Google Analytics тільки зі згодою
function loadGoogleAnalytics() {
if (document.getElementById('ga-script')) return; // вже завантажено
const script = document.createElement('script');
script.id = 'ga-script';
script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_ID}`;
script.async = true;
document.head.appendChild(script);
window.dataLayer = window.dataLayer || [];
function gtag(...args: unknown[]) { window.dataLayer.push(args); }
gtag('js', new Date());
gtag('config', GA_ID, { anonymize_ip: true });
}
Порівняння рішень: самописний cookie-бар vs готові бібліотеки
| Критерій | Самописний | Готові (CookiNinja, Osano) |
|---|---|---|
| Гнучкість | Висока: будь-який дизайн, логіка | Обмежена шаблонами |
| Залежності | Немає зовнішніх | Підключають свої скрипти |
| Відповідність GDPR | Повний контроль | Часткове (потрібно перевіряти) |
| Вартість | Разові витрати | Щомісячна підписка |
Строк реалізації
Cookie-банер з трьома категоріями, збереженням згоди в localStorage та API: 2–3 дні. З аудит-логом згод у БД та GDPR-сумісним відкликанням: 3–4 дні.
Як протестувати GDPR-відповідність перед деплоєм?
Перевіряємо відповідність за чек-листом: відкриваємо сайт у режимі інкогніто та переконуємось, що GA і Yandex.Metrica не стартують до згоди — заходимо в DevTools → Network і фільтруємо по «google-analytics» та «mc.yandex»; приймаємо тільки аналітичні куки та контролюємо, що маркетингові скрипти мовчать; через вкладку Application → LocalStorage знаходимо ключ cookie_consent_v2 з коректними прапорами; перевіряємо, що запит до /api/cookie-consent повертає 200 і дані записалися в БД; тестуємо відкликання згоди — скрипти повинні припинити роботу протягом 1 секунди; переконуємось, що повторний візит не показує банер знову; перевіряємо рендеринг на екранах шириною 320, 768 та 1280 px. Cookie-бар повинен працювати у всіх браузерах без винятків.
Замовте реалізацію cookie-бара під ключ — ми гарантуємо відповідність GDPR та повну підтримку після впровадження. Зв'яжіться з нами для безкоштовної консультації та оцінки вашого проекту.







