Wprowadzenie
CookiePilot to platforma do zarządzania zgodami cookies (CMP), zgodna z RODO, PKE i Google Consent Mode v2.
Dla kogo
- Właściciele stron: wdrożenie bez programowania.
- Developerzy: API, eventy, integracje z GTM.
- Agencje: white-label, zarządzanie wieloma domenami.
Szybki start
Krok 1: Rejestracja
- Załóż konto na app.cookiepilot.io/register.
- Dodaj domenę w panelu i skopiuj klucz API (format
cp_live_...).
Krok 2: Instalacja kodu
Instalacja bezpośrednia to dwa skrypty w sekcji <head>, w tej kolejności.
Krok 2a: Domyślne zgody (inline stub). Wklej jako pierwszy, przed jakimkolwiek innym skryptem (cookiepilot.js, GA, GTM, tagi reklamowe i trackujące):
<script>"use strict";(function(){window.dataLayer=window.dataLayer||[];var d={ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"granted",wait_for_update:500},h=false;try{for(var i=0;i<window.dataLayer.length;i++){var x=window.dataLayer[i];if(x&&x[0]==="consent"&&x[1]==="default"){h=true;break}}}catch(err){}if(!h&&window.dataLayer.length)window.dataLayer.unshift(["consent","default",d]);window.gtag=function(){window.dataLayer.push(arguments)};if(!h)window.gtag("consent","default",d);var a=document.cookie.match(/(^|)cookiepilot_consent=([^;]+)/);if(a){try{var e=JSON.parse(decodeURIComponent(a[2]));window.gtag("consent","update",{analytics_storage:e.analytics?"granted":"denied",ad_storage:e.marketing?"granted":"denied",ad_user_data:e.marketing?"granted":"denied",ad_personalization:e.marketing?"granted":"denied",functionality_storage:e.preferences?"granted":"denied",personalization_storage:e.preferences?"granted":"denied",security_storage:"granted"})}catch(err){}}})();</script>
Ten inline snippet od razu ustawia wszystkie kategorie na denied (z wait_for_update: 500), więc domyślny stan Google Consent Mode v2 jest gotowy zanim cokolwiek innego się załaduje. Dla powracającego użytkownika od razu odczytuje zapisaną zgodę z cookie i puszcza consent update.
Krok 2b: Skrypt banera. Dodaj zaraz po inline stubie:
<!-- CookiePilot -->
<script async src="https://cdn.cookiepilot.io/cookiepilot.js" data-cpkey="TWOJ_KLUCZ"></script>
Krok 3: Konfiguracja banera
W panelu: Domena → Konfiguracja → Wygląd:
- pozycja banera (góra, dół, modal),
- kolory i teksty,
- pływający przycisk "Ustawienia cookies" dla powracających użytkowników.
Integracja z Google Tag Manager
Przez GTM instalujesz CookiePilot jednym tagiem Custom HTML, który od razu ustawia domyślne zgody i ładuje baner w najwcześniejszej fazie GTM. Nie potrzebujesz osobnego pliku stub ani drugiego tagu.
Tag: CookiePilot - Consent Init + Banner
W GTM utwórz tag Custom HTML (Tagi → Nowy → Niestandardowy kod HTML) i wklej:
<script>"use strict";
(function() {
window.dataLayer=window.dataLayer||[];var d={ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"granted",wait_for_update:500},h=false;try{for(var i=0;i<window.dataLayer.length;i++){var x=window.dataLayer[i];if(x&&x[0]==="consent"&&x[1]==="default"){h=true;break}}}catch(err){}if(!h&&window.dataLayer.length)window.dataLayer.unshift(["consent","default",d]);window.gtag=function(){window.dataLayer.push(arguments)};if(!h)window.gtag("consent","default",d);var a=document.cookie.match(/(^|)cookiepilot_consent=([^;]+)/);if(a){try{var e=JSON.parse(decodeURIComponent(a[2]));window.gtag("consent","update",{analytics_storage:e.analytics?"granted":"denied",ad_storage:e.marketing?"granted":"denied",ad_user_data:e.marketing?"granted":"denied",ad_personalization:e.marketing?"granted":"denied",functionality_storage:e.preferences?"granted":"denied",personalization_storage:e.preferences?"granted":"denied",security_storage:"granted"})}catch(err){}}
var s = document.createElement('script');
s.src = 'https://cdn.cookiepilot.io/cookiepilot.js?cpkey=' + encodeURIComponent('TWOJ_KLUCZ');
document.head.appendChild(s);
})();
</script>
Trigger: Consent Initialization - All Pages. Tag musi uruchamiać się raz na stronę. Tagi Google (GA4, Google Ads), Facebook Pixel i inne tagi marketingowe NIE używają triggera Consent Initialization, tylko odpalają się później (Consent Checks albo trigger zależny od zgody). Zapisz tag i opublikuj kontener GTM.
Kolejność i triggery
| Kolejność | Tag | Trigger |
|---|---|---|
| 1 | CookiePilot - Consent Init + Banner | Consent Initialization - All Pages |
| 2 | GA4, Google Ads, UET | All Pages (Consent Mode sam obsłuży zgody) |
| 3 | Facebook Pixel, TikTok, LinkedIn itd. | Custom Event cookiepilot_consent_update + warunek zgody (patrz niżej) |
Tagi spoza Google (Facebook Pixel, TikTok, LinkedIn)
Google Consent Mode obsługuje tylko tagi Google. Dla pozostałych skryptów widget przy każdej zmianie zgody pushuje do dataLayer event:
dataLayer.push({
event: 'cookiepilot_consent_update',
cookiepilot_consent: {
necessary: true,
analytics: true,
marketing: true,
preferences: false
}
});
Event leci również przy każdym wejściu powracającego użytkownika (gdy widget odczyta cookie ze zgodą), więc trigger w GTM zadziała na każdej wizycie, nie tylko przy pierwszej decyzji.
Wspólny pattern (wykonaj raz)
Te trzy elementy konfigurujesz raz, potem używasz dla wszystkich tagów spoza Google.
- Trigger (Triggers → New → Custom Event): Event name
cookiepilot_consent_update. Bez warunków, bez "Once per page" (tag musi móc odpalić się ponownie po zmianie decyzji). - Data Layer Variable dla każdej kategorii której używasz:
- Name
cookiepilot_consent.marketing→ zmienna np.dlv.cp_marketing - Name
cookiepilot_consent.analytics→ zmienna np.dlv.cp_analytics - Name
cookiepilot_consent.preferences→ zmienna np.dlv.cp_preferences
- Name
- Trigger Group lub warunek w triggerze:
dlv.cp_marketing equals true(dla tagów marketingowych) albo odpowiednie pole.
W każdym z poniższych przykładów Trigger to ten sam Custom Event z dorzuconym warunkiem na właściwą zmienną.
Facebook Pixel
Tag w GTM: Tags → New → Custom HTML.
<script>
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
document,'script','https://connect.facebook.net/en_US/fbevents.js');
fbq('init', 'YOUR_PIXEL_ID');
fbq('track', 'PageView');
</script>
- Trigger:
cookiepilot_consent_update+ warunekdlv.cp_marketing equals true. - Tag firing options: Once per page.
Opcjonalnie, dla pełnej zgodności z Facebook Limited Data Use, dodaj drugi tag wywołujący fbq('consent','revoke') z triggerem dlv.cp_marketing equals false.
TikTok Pixel
Tag w GTM: Tags → New → Custom HTML.
<script>
!function (w, d, t) {
w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];ttq.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie","holdConsent","revokeConsent","grantConsent"],ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);ttq.instance=function(t){for(var e=ttq._i[t]||[],n=0;n<ttq.methods.length;n++)ttq.setAndDefer(e,ttq.methods[n]);return e},ttq.load=function(e,n){var r="https://analytics.tiktok.com/i18n/pixel/events.js",o=n&&n.partner;ttq._i=ttq._i||{},ttq._i[e]=[],ttq._i[e]._u=r,ttq._t=ttq._t||{},ttq._t[e]=+new Date,ttq._o=ttq._o||{},ttq._o[e]=n||{};n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=r+"?sdkid="+e+"&lib="+t;e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(n,e)};
ttq.load('YOUR_TIKTOK_PIXEL_ID');
ttq.grantConsent();
ttq.page();
}(window, document, 'ttq');
</script>
- Trigger:
cookiepilot_consent_update+ warunekdlv.cp_marketing equals true. - Tag firing options: Once per page.
ttq.grantConsent() to nowe API TikTok (od 2024). Bez tego TikTok dostaje hashowane dane bez zgody, co łamie warunki.
LinkedIn Insight Tag
<script type="text/javascript">
_linkedin_partner_id = "YOUR_LINKEDIN_PARTNER_ID";
window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];
window._linkedin_data_partner_ids.push(_linkedin_partner_id);
</script>
<script type="text/javascript">
(function(l) {
if (!l){window.lintrk = function(a,b){window.lintrk.q.push([a,b])};
window.lintrk.q=[]}
var s = document.getElementsByTagName("script")[0];
var b = document.createElement("script");
b.type = "text/javascript";b.async = true;
b.src = "https://snap.licdn.com/li.lms-analytics/insight.min.js";
s.parentNode.insertBefore(b, s);})(window.lintrk);
</script>
- Trigger:
cookiepilot_consent_update+ warunekdlv.cp_marketing equals true. - Tag firing options: Once per page.
Hotjar
<script>
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:YOUR_HOTJAR_ID,hjsv:6};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-',".js?sv=");
</script>
- Trigger:
cookiepilot_consent_update+ warunekdlv.cp_analytics equals true. - Tag firing options: Once per page.
Hotjar idzie pod analytics, nie marketing (mierzy zachowanie, nie reklamy). Sprawdź własną politykę cookies, niektóre firmy klasyfikują Hotjar inaczej.
Microsoft Clarity
<script type="text/javascript">
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "YOUR_CLARITY_PROJECT_ID");
</script>
- Trigger:
cookiepilot_consent_update+ warunekdlv.cp_analytics equals true. - Tag firing options: Once per page.
Pinterest Tag
<script>
!function(e){if(!window.pintrk){window.pintrk = function () {
window.pintrk.queue.push(Array.prototype.slice.call(arguments))};var
n=window.pintrk;n.queue=[],n.version="3.0";var
t=document.createElement("script");t.async=!0,t.src=e;var
r=document.getElementsByTagName("script")[0];
r.parentNode.insertBefore(t,r)}}("https://s.pinimg.com/ct/core.js");
pintrk('load', 'YOUR_PINTEREST_TAG_ID');
pintrk('page');
</script>
- Trigger:
cookiepilot_consent_update+ warunekdlv.cp_marketing equals true. - Tag firing options: Once per page.
Microsoft Ads (UET)
UET wspiera Google Consent Mode od końca 2023, więc nie potrzebujesz Custom Event triggera. Wstaw tag standardowo (All Pages, Once per page), a UET sam czyta ad_storage z GCM, które ustawia widget.
Mapowanie kategorii (skrót)
| Tag | Kategoria | Pole w cookiepilot_consent |
|---|---|---|
| Facebook Pixel | marketing | marketing |
| TikTok Pixel | marketing | marketing |
| LinkedIn Insight | marketing | marketing |
| marketing | marketing | |
| Hotjar | analytics | analytics |
| Microsoft Clarity | analytics | analytics |
| Mixpanel, Amplitude | analytics | analytics |
| Intercom, Drift, Crisp | preferences | preferences |
| GA4, Google Ads, UET | (GCM, bez triggera) | obsługiwane przez gtag('consent','update') |
API Reference
CookiePilot udostępnia obiekt window.CookiePilot:
| Metoda | Opis |
|---|---|
CookiePilot.getConsent() | Aktualny stan zgód lub null jeśli nie ma decyzji. |
CookiePilot.acceptAll() | Zgoda na wszystkie kategorie. |
CookiePilot.rejectAll() | Odrzuca wszystko poza necessary. |
CookiePilot.updateConsent(partial) | Aktualizuje wybrane kategorie, np. { analytics: true }. |
CookiePilot.showSettings() | Otwiera modal preferencji. |
CookiePilot.hideSettings() | Zamyka modal preferencji. |
CookiePilot.showMyConsent() / hideMyConsent() | Pokazuje/ukrywa pływający przycisk. |
Przykład
const consent = CookiePilot.getConsent();
// { necessary: true, analytics: true, marketing: false, preferences: false }
CookiePilot.updateConsent({ analytics: true });
document.getElementById('cookie-settings').addEventListener('click', () => {
CookiePilot.showSettings();
});
Link "Zarządzaj cookies" w stopce
<a href="#" onclick="CookiePilot.showSettings(); return false;">Zarządzaj cookies</a>
Eventy JavaScript
Widget dispatcuje natywny event cookiepilot:consent na window. Listener musi być zarejestrowany przed załadowaniem widgetu, jeśli chcesz złapać event dla powracającego użytkownika (dispatch leci natychmiast po starcie widgetu):
<script>
window.addEventListener('cookiepilot:consent', (e) => {
if (e.detail.marketing) {
fbq('init', 'YOUR_PIXEL_ID');
}
});
</script>
<script src="https://cdn.cookiepilot.io/cookiepilot.js" data-cpkey="TWOJ_KLUCZ"></script>
e.detail zawiera ten sam payload co getConsent(). Dla integracji przez GTM użyj dataLayer eventu opisanego wyżej zamiast tego, bo dataLayer jest persistent array i GTM łyka eventy historyczne.
Kategorie zgód
| Kategoria | Opis | Domyślnie |
|---|---|---|
necessary | Niezbędne do działania strony | Zawsze aktywne |
analytics | Statystyki i analityka | Wymagana zgoda |
marketing | Reklamy i remarketing | Wymagana zgoda |
preferences | Personalizacja, język | Wymagana zgoda |
Mapowanie na Google Consent Mode
| Kategoria CookiePilot | Pola Consent Mode |
|---|---|
analytics | analytics_storage |
marketing | ad_storage, ad_user_data, ad_personalization |
preferences | functionality_storage, personalization_storage |
| (zawsze) | security_storage: granted |
Google Consent Mode v2
Wersja 2 dodała ad_user_data i ad_personalization (wymagane od marca 2024 dla EU/EEA przy reklamach Google).
| Parametr | Opis |
|---|---|
ad_storage | Cookies reklamowe |
analytics_storage | Cookies analityczne |
ad_user_data | Wysyłka danych użytkownika do Google |
ad_personalization | Personalizacja reklam |
functionality_storage | Cookies funkcjonalne |
personalization_storage | Cookies personalizacyjne |
security_storage | Zawsze granted |
Mechanizm:
- Stub ustawia wszystkie pola na
deniedsynchronicznie, zwait_for_update: 500. - Po decyzji użytkownika widget puszcza
gtag('consent', 'update', {...})z mapowaniem powyżej. - Dla powracającego użytkownika punkt 2 leci natychmiast po starcie widgetu, na podstawie cookie.
Konfiguracja wyglądu
W panelu: Domena → Konfiguracja:
- Wygląd: pozycja, kolory, układ (BAR / BOX / MODAL).
- Teksty: nagłówek, opis, etykiety przycisków, opisy kategorii. 13 języków (EN, PL, DE, FR, ES, IT, NL, PT, SV, CS, RO, EL, HU).
- Przycisk zgód: pływający przycisk "Ustawienia cookies" widoczny po pierwszej decyzji (lewy/prawy dół).
- Custom CSS: pole na własne style. Widget renderuje się w Shadow DOM, więc selektory CSS z głównego dokumentu nie zadziałają. Tylko przez to pole.
Dostępność (WCAG 2.1 AA)
- ✅ Nawigacja klawiaturą (Tab, Shift+Tab, Enter, Escape).
- ✅ ARIA labels, role="dialog", aria-modal.
- ✅ Focus trap w modalu.
- ✅ Screen reader (live regions na zmianę stanu).
- ✅ Responsywność.
Integracje
WordPress
Mamy oficjalną wtyczkę: CookiePilot na WordPress.org.
- WordPress admin → Wtyczki → Dodaj nową → szukaj "CookiePilot".
- Zainstaluj i aktywuj.
- Ustawienia → CookiePilot → wklej klucz API z panelu.
Wtyczka sama wstawia stub i tag w <head> (z poprawną kolejnością przed innymi skryptami) i wystawia shortcode [cookiepilot_settings] do linku "Zarządzaj cookies" w stopce.
Jeśli wolisz bez wtyczki: użyj "Insert Headers and Footers" i wklej snippet z kroku 2 Szybkiego startu w sekcję Header.
Shopify
- Sklep → Motywy → Edytuj kod.
- W
theme.liquidwklej snippet przed</head>.
Next.js
// app/layout.tsx
import Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html>
<head>
<Script
src="https://cdn.cookiepilot.io/cookiepilot.js"
data-cpkey="TWOJ_KLUCZ"
strategy="beforeInteractive"
/>
</head>
<body>{children}</body>
</html>
);
}
strategy="beforeInteractive" zapewnia, że skrypt banera wykona się wcześnie. Pamiętaj, że inline stub z Kroku 2a (domyślne zgody) dodajesz osobno, w <head> przed tym skryptem, np. przez next/script z dangerouslySetInnerHTML albo bezpośrednio w app/layout.tsx.
FAQ
Czy skrypt spowalnia stronę?
Bundle to ok. 12 KB gzip, ładowany asynchronicznie. Bez wpływu na Core Web Vitals.
Jak długo trzymane są zgody?
Cookie z decyzją użytkownika: domyślnie 365 dni (konfigurowalne w panelu). Zdarzenia w analityce: 2 lata (TTL ClickHouse).
Czy event cookiepilot_consent_update leci dla powracającego użytkownika?
Tak. Widget odczytuje cookie przy starcie i pushuje event do dataLayer. Trigger Custom Event w GTM odpali się przy każdej wizycie, nie tylko przy pierwszej decyzji.
Gdzie zgłosić problem?
kontakt@cookiepilot.io lub chat w panelu.