Pełna Referencja JavaScript API
Kompletny kontrakt window.CookieZen. Podstawowe snippety znajdziesz w Integracji JavaScript API - szybki start. Wszystkie przepisy integracyjne (React, AbortController, Multi-tab, GTM, iframe) opisuje plik cookiezen-docs-api.md.
Korzystasz z Agentów AI typu Cursor, Claude Code lub Codex? Pobierz paczkę cookiezen-docs-api.md, która zawiera kompletną referencję API w jednym miejscu. Plik został dostosowany w celu przyspieszenia pracy z narzędziami LLM.
Kategorie zgód
| Kategoria | Opis | Domyślnie |
|---|---|---|
essential | Niezbędne do działania strony | Zawsze true |
preferences | Czat, personalizacja, systemy opinii | false |
analytics | Google Analytics, Hotjar, Clarity | false |
marketing | Facebook Pixel, Google Ads, TikTok | false |
require() przyjmuje tylko trzy kategorie nieobowiązkowe (wszystko poza essential). essential jest read-only.
Metody window.CookieZen
| Metoda | Sygnatura | Opis |
|---|---|---|
ready() | () => Promise<api> | Rozwiązuje się po załadowaniu banera (bot/failsafe: natychmiast). |
getConsent() | () => Snapshot | Zawsze zwraca obiekt. Sprawdzaj .finalized. |
hasConsent(cat) | (cat) => boolean | Synchroniczne sprawdzenie kategorii. hasConsent('essential') zawsze zwraca true (w każdym trybie). |
hasResponse() | () => boolean | true po decyzji użytkownika (accept/reject/customize/withdraw). |
require(cat, opts?) | (cat, {timeout?, signal?}) => Promise<true> | Czeka na zgodę. Odrzuca z kodem błędu. |
on(event, cb) | (evt, cb) => api | Subskrypcja (łańcuchowa). 8 eventów (poniżej). |
off(event, cb) | (evt, cb) => api | Anuluje subskrypcję. Zawsze wywołuj przy czyszczeniu w SPA / React. |
once(event, cb) | (evt, cb) => api | Subskrypcja jednorazowa z automatycznym wyłączeniem. |
accept() | () => Promise<Snapshot> | Akceptacja wszystkiego z poziomu kodu (action='accept'). Zamyka otwarty baner pierwszej wizyty. |
decline() | () => Promise<Snapshot> | Odmowa z poziomu kodu (action='reject' lub 'withdraw'). Zamyka otwarty baner pierwszej wizyty. |
submitConsent(partial) | (Partial<Cats>) => Promise<Snapshot> | Częściowe scalenie, action='customize'. Zamyka otwarty baner pierwszej wizyty. |
show(opts?) | ({view?: 'main'|'details'}) => void | Otwiera centrum zgód. |
showSettings() | () => void | Alias show({view:'details'}). Dla integracji bez własnego JS użyj deep linku #cookiezen-settings (sekcja niżej). |
onMarketingConsent(cb) | skrót | Alias on('marketing', cb). |
onAnalyticsConsent(cb) | skrót | Alias on('analytics', cb). |
onPreferencesConsent(cb) | skrót | Alias on('preferences', cb). |
debug() | () => DebugSnapshot | Diagnostyka: listy zablokowanych skryptów. |
Deep link #cookiezen-settings: otwarcie ustawień przez link
Rekomendowane dla każdego klienta, który nie chce / nie może wkleić własnego JavaScriptu na stronie (CMS-y bez własnego JS: Shoper, Wix, prosty WordPress przez edytor treści).
Wystarczy odnośnik z hashem #cookiezen-settings. Baner sam wykryje go i otworzy widok szczegółów (kategorie + przełączniki + ID zgody, jeśli już zapisana).
<!-- Najprostsze: względny hash, działa na każdej podstronie -->
<a href="#cookiezen-settings">Ustawienia cookies</a>
<!-- Pełny URL, wklej w pole "URL" przycisku w CMS (Shoper menu, Wix link, itp.) -->
https://twoja-domena.pl/#cookiezen-settingsJak to działa (routing zależy od stanu zgody użytkownika):
| Stan użytkownika | Co się otwiera | Po co |
|---|---|---|
| Powracający (zgoda już zapisana) | Pływający popup: DOKŁADNIE to samo co kliknięcie pływającego przycisku (podsumowanie kategorii + „Pokaż szczegóły" z ID zgody i datą + przyciski „Anulowanie zgody" / „Zmień swoją zgodę") | Deep link zastępuje pływający przycisk gdy klient go ukryje. UX musi być 1:1, żeby użytkownik dalej miał dostęp do ID i opcji zmiany/wycofania. |
| Pierwsza wizyta (brak zgody) | Standardowy baner pierwszej wizyty (accept / reject / customize). Hash jest cicho konsumowany, więc odświeżenie po wyrażeniu zgody nie wyświetla niespodziewanego popupa. | Główny baner ma już wszystkie przełączniki potrzebne nowemu użytkownikowi; otwieranie dedykowanego centrum byłoby duplikatem. |
Mechanika:
- Wejście na stronę z hashem + zapisana zgoda → pływający popup od razu.
- Wejście z hashem + brak zgody → główny baner pierwszej wizyty, hash skonsumowany.
- Kliknięcie w link w trakcie sesji uruchamia trzy ścieżki (bez przeładowania):
- hashchange: klasyczna nawigacja hashem,
- capture click na <a href*="#cookiezen-settings">: fallback dla SPA (Shoper Storefront itp.), z preventDefault w tej samej karcie,
- popstate: wstecz/naprzód z hashem w URL.
- Krótkie okno deduplikacji (~100 ms) chroni przed podwójnym otwarciem gdy
clickihashchangeodpalą się razem (inaczej popup by się zamknął przez przełączenie). target="_blank": baner nie przechwytuje kliknięcia; nowa karta otwiera się z hashem i obsługuje go przy załadowaniu.- Na wielostronicowych sklepach preferuj względny hash
#cookiezen-settingszamiast absolutnego URL do strony głównej. - Hash jest konsumowany po obsłużeniu (baner usuwa go przez
history.replaceState), więc odświeżenie nie zostawia śmieci w pasku adresu. - Skanery i boty: pominięte (baner w tych trybach w ogóle się nie pokazuje).
Kiedy preferować showSettings() w JS:
- Reaktywny UI we własnym SPA (React/Vue):
onClick={() => window.CookieZen.showSettings()}. - Centrum klienta z własną logiką (np. otwierane modale).
Gotowe snippety (link absolutny dla Twojej domeny + HTML + względny hash) znajdziesz w panelu CookieZen: Wygląd baneru → Pozycja przycisku ustawień cookies → Ukryty.
Snapshot
getConsent() zwraca obiekt o tym kształcie:
type Snapshot = {
categories: { essential: true; preferences: boolean; analytics: boolean; marketing: boolean; };
consentId: string | null; // UUID po finalizacji
timestamp: number | null; // ms epoch
policyVersion: string | null;
action: 'accept' | 'reject' | 'customize' | 'withdraw' | null;
finalized: boolean; // false gdy użytkownik nie zatwierdził decyzji
};getConsent() nigdy nie zwraca null. Przed finalizacją → finalized: false i null w metadanych. Sprawdzaj if (CookieZen.getConsent().finalized).
policyVersion
Wersja polityki skonfigurowana w panelu CMP (np. "v1.2"). Podbicie wersji unieważnia zapisaną zgodę przy następnym pełnym załadowaniu strony: cookie zgody i powiązana pamięć przeglądarki są czyszczone, finalized wraca do false, a wiszące require() nie rozwiążą się ze starej decyzji.
Reset następuje przy załadowaniu strony: w SPA bez przeładowania podbicie wersji na serwerze nie wymusi ponownego pytania o zgodę. Użyj location.reload() lub show(), jeśli potrzebujesz ponownego pytania w tej samej sesji.
Automatyczne usuwanie artefaktów first-party
Po decline(), wycofaniu (withdraw) lub submitConsent() z odmówioną kategorią, a także przy starcie strony dla powracającego użytkownika z odmową, CookieZen automatycznie usuwa first-party cookies, localStorage, sessionStorage i IndexedDB sklasyfikowane przez skaner w tej kategorii.
- Sterowane klasyfikacją skanera; chronione są własne artefakty zgody CMP i krytyczne nazwy (koszyk, sesja).
- W innych kartach: synchronizacja przez
storageczyści teżsessionStoragedanej karty dla kategorii odmówionych. - Brak opcji wyłączenia, to część kontraktu zgody. Ręczne czyszczenie w
unloadSdk()to opcjonalne zabezpieczenie dla zewnętrznych SDK.
Integracja przez iframe (placeholder)
Przy ręcznym blokowaniu zablokowany <iframe> (np. widget opinii Trustmate) jest ukryty i zastąpiony placeholderem (Shadow DOM) z przyciskiem zgody:
- Iframe nie ładuje się do czasu przyznania wymaganej kategorii.
- Klik w placeholder nadaje całą wymaganą kategorię i zamyka otwarty baner pierwszej wizyty (jeśli był widoczny).
- Po zgodzie placeholder znika, iframe się pokazuje; usunięcie iframe z DOM czyści placeholder.
- Współgra z
on('change')i nie wymaga własnego kodu HTML od integratora.
Szczegóły i snippet: cookiezen-docs-api.md §10.10a.
Eventy
8 typów eventów w JS API. 5 z nich (ready, consent, change, accept, decline) ma odpowiadający DOM CustomEvent na window (zob. niżej); eventy kategorii (marketing/analytics/preferences) istnieją wyłącznie w JS API.
| Event | Od razu przy on() | Przy kolejnych zmianach |
|---|---|---|
consent | Tak, z aktualnym Snapshot | Tak (każda zmiana, informacyjny) |
ready | Tak, natychmiast | brak |
change | Nie | Tak (gdy zmieniła się co najmniej jedna kategoria) |
accept | Nie | Tak (przejście do stanu sfinalizowanego, min. jedna kategoria przyznana) |
decline | Nie | Tak (przejście do stanu sfinalizowanego, wszystkie kategorie odmówione) |
marketing / analytics / preferences | Tak, jeśli przyznana | Tak (przy zmianie false → true) |
Doprecyzowanie semantyki accept / decline (przejście = zmiana co najmniej jednej kategorii LUB pierwsza finalizacja decyzji):
- Pierwsza akceptacja lub
customizez min. jedną przyznaną kategorią →accept. - "Odrzuć wszystko" jako pierwsza decyzja →
decline. Emituje się, mimo że kategorie się nie zmieniły (stan domyślny to już wszystkie odmówione; przejściem jest sama finalizacja). Uwaga:changew tym przypadku NIE odpala (brak zmiany kategorii). customizeobniżające zgodę, ale z min. jedną kategorią nadal przyznaną (np. cofnięcie analytics przy zachowanym marketingu) →accept, niedecline. Logikę per kategoria buduj napayload.categorieslub na evenciechange.- Wycofanie kończące się odmową wszystkich kategorii →
decline. - Druga
decline()z rzędu (wszystkie kategorie już odmówione) → brak eventu (nie zaszło żadne przejście).
Argument callbacka ready: callback dostaje instancję API (window.CookieZen), nie Snapshot.
Kolejność emisji przy zmianie stanu: change → accept lub decline → eventy kategorii → consent.
Powracający użytkownik (bez zbędnych eventów): przy przeładowaniu strony consent odpala się (informacyjny), ale change/accept/decline NIE, bo w bieżącej sesji stan się nie zmienił. Rozwiązuje klasyczny problem CMP-ów (Cookiebot OnAccept wywołuje się przy każdym załadowaniu strony).
Payload change
type ChangePayload = Snapshot & {
previousCategories: ConsentCategories;
changedCategories: ('marketing' | 'analytics' | 'preferences')[];
};DOM Events
Pięć eventów ma odpowiadający CustomEvent na window (dla wzorca addEventListener). Eventy kategorii nie mają odpowiedników DOM - nie istnieje np. cookiezen:marketing; użyj CookieZen.on('marketing', cb).
| Event | event.detail |
|---|---|
cookiezen:ready | {categories, finalized}, emitowany przy każdym załadowaniu strony po inicjalizacji |
cookiezen:consent | ChangePayload, informacyjny |
cookiezen:change | ChangePayload, realna zmiana stanu |
cookiezen:accept | Snapshot |
cookiezen:decline | Snapshot |
window.addEventListener('cookiezen:accept', function(e) {
if (e.detail.categories.marketing) initPixel();
});Kody błędów: kontrakt odrzucenia require()
require() rzuca Error z polem code. Stabilny kontrakt:
| Kod | Kiedy | err.category |
|---|---|---|
CONSENT_DECLINED | hasResponse() && !hasConsent(cat); dodatkowo natychmiast w trybie bot/failsafe | Tak |
CONSENT_TIMEOUT | Minął opts.timeout ms | Tak |
CONSENT_ABORTED | opts.signal.abort() | Tak |
INVALID_CATEGORY | cat ∉ {marketing, analytics, preferences} | Nie |
CONSENT_DECLINED obejmuje dwie sytuacje: (1) tryb normalny - użytkownik sfinalizował decyzję i kategoria jest odmówiona; (2) tryb bot/failsafe - baner nigdy się nie załaduje, więc zgoda nigdy nie zostanie przyznana i require() odrzuca natychmiast, mimo finalized: false. Traktuj ten kod jako "zgoda jest i będzie niedostępna", a komunikaty dla użytkownika formułuj neutralnie (np. "włącz cookies marketingowe, aby zobaczyć tę treść"), a nie oskarżycielsko ("odrzuciłeś zgodę").
Zasady timeoutu
- Bez
opts.timeout→console.warn+ twardy limit 30 minut (fail-safe). opts.timeout: 30000→ odrzucenie po 30 sekundach.opts.timeout: 0lubInfinity→ świadomie bez limitu, bez ostrzeżenia w konsoli.
Uwaga: timeout: 0 oznacza tu "bez limitu", a NIE "odrzuć natychmiast". To odstępstwo od konwencji znanej z innych API - nie przenoś tamtego przyzwyczajenia.
Wzorce inicjalizacji
Kolejka poleceń (Twój skrypt po naszym loaderze)
API jest dostępne jako stub od razu po załadowaniu loadera, a wywołania są kolejkowane i opróżniane po inicjalizacji banera. Wszystkie metody Promise (require, accept, decline, submitConsent, ready) obsługują Promise już w stubie.
Metod synchronicznych nie da się zakolejkować, więc stub odpowiada na nie zdefiniowanym stanem sprzed inicjalizacji (stabilny kontrakt):
getConsent()zwraca pełny Snapshot zfinalized: false, wszystkimi kategoriami nieobowiązkowymi nafalseinullw metadanych.hasConsent(cat)zwracatruetylko dla'essential',falsedla pozostałych - nawet gdy użytkownik ma zapisaną zgodę (stub nie czyta pamięci przeglądarki).hasResponse()zwracafalse.
Nie traktuj hasConsent('marketing') === false odczytanego ze stubu jako decyzji użytkownika. Do decyzji służą require() / on('change'), które rozstrzygają się na realnym stanie po inicjalizacji banera.
<script src="https://cz-cdn.com/api/cmp/loader?site_key=TWOJ_KEY"></script>
<script>
CookieZen.on('change', function ({ categories }) {
console.log('marketing:', categories.marketing);
});
</script>CookieZenCallback_OnReady (Twój skrypt może załadować się PRZED naszym loaderem)
Na platformach z asynchronicznym ładowaniem (Shoper Storefront, IdoSell, Magento) nie ma gwarancji, że nasz loader wykona się jako pierwszy. Wtedy zdefiniuj globalną funkcję, a CookieZen wywoła ją po inicjalizacji niezależnie od kolejności. Wzorzec analogiczny do CookiebotCallback_OnLoad z Cookiebot.
<script>
window.CookieZenCallback_OnReady = function (CookieZen) {
CookieZen.require('marketing', { timeout: 30000 }).then(initWidget).catch(function () {});
CookieZen.on('change', function (p) {
if (p.categories.marketing) initWidget();
else destroyWidget();
});
};
</script>Późna rejestracja: jeśli zarejestrujesz CookieZenCallback_OnReady PO inicjalizacji CookieZen, nie odpali się. Wtedy użyj CookieZen.on('ready', cb); ready odpala się od razu przy subskrypcji.
Kilka wtyczek na jednym sklepie: CookieZenCallback_OnReady to pojedyncza globalna funkcja - ostatnie przypisanie wygrywa i po cichu wyłącza poprzednie (to samo ograniczenie ma Cookiebot). Jeśli Twoja wtyczka może współistnieć z innymi, zamiast nadpisywać - dowiąż się do poprzedniej wartości:
(function () {
var prev = window.CookieZenCallback_OnReady;
window.CookieZenCallback_OnReady = function (CookieZen) {
if (typeof prev === 'function') { try { prev(CookieZen); } catch (e) {} }
// ... Twoja integracja ...
};
})();Bot / failsafe
Gdy baner nie załaduje się (wykrycie bota lub failsafe timeout 7s), window.CookieZen jest podmieniany na mini-API:
require()odrzuca natychmiast zCONSENT_DECLINED, mimofinalized: false(szczegóły w sekcji o kodach błędów).hasConsent(cat)zwracatruetylko dla'essential';hasResponse()zwracafalse.getConsent()zwraca Snapshot zfinalized: falsei wszystkimi kategoriami nieobowiązkowymi nafalse.accept()/decline()/submitConsent()zwracają Snapshot sprzed finalizacji (no-op).on()/once()przyjmują subskrypcje, ale odpalają tylkoconsentiready(natychmiast, przez fire-on-subscribe). Pozostałe eventy nigdy nie wystąpią.- DOM event
cookiezen:readyemitowany.
Kod z try/catch na require() działa identycznie w trybie normalnym i bot/failsafe.
Cookie po stronie serwera
Cookie cmp_consent_<siteKey> (np. cmp_consent_site_abc123) na domenie głównej, SameSite=Lax. Nazwa zawiera Twój site_key, dzięki czemu zgoda jest izolowana między stronami współdzielącymi tę samą domenę nadrzędną:
{
"finalized": true,
"consentId": "c_xyz...",
"categories": {"essential": true, "preferences": false, "analytics": true, "marketing": false},
"policyVersion": "v1.2",
"timestamp": 1715000000000,
"action": "customize"
}// Zastąp <siteKey> swoim site_key (lub przeskanuj cookies po prefiksie cmp_consent_).
$raw = $_COOKIE['cmp_consent_<siteKey>'] ?? null;
if ($raw) {
$c = json_decode(urldecode($raw), true);
if ($c && !empty($c['finalized'])) {
$marketing = !empty($c['categories']['marketing']);
$action = $c['action'] ?? null;
}
}const raw = req.cookies?.['cmp_consent_<siteKey>'];
if (raw) {
const c = JSON.parse(decodeURIComponent(raw));
if (c?.finalized) {
const marketing = c.categories?.marketing === true;
}
}Stare cookies bez action → action: null, reszta pól wczytuje się normalnie.
Typy TypeScript
interface ConsentCategories {
essential: true;
preferences: boolean;
analytics: boolean;
marketing: boolean;
}
interface Snapshot {
categories: ConsentCategories;
consentId: string | null;
timestamp: number | null;
policyVersion: string | null;
action: 'accept' | 'reject' | 'customize' | 'withdraw' | null;
finalized: boolean;
}
interface ChangePayload extends Snapshot {
previousCategories: ConsentCategories;
changedCategories: ('marketing' | 'analytics' | 'preferences')[];
}
interface RequireOptions {
timeout?: number; // ms; 0/Infinity = bez limitu
signal?: AbortSignal;
}
type ConsentEvent =
| 'consent' | 'ready' | 'change' | 'accept' | 'decline'
| 'marketing' | 'analytics' | 'preferences';
interface ConsentError extends Error {
code: 'CONSENT_DECLINED' | 'CONSENT_TIMEOUT' | 'CONSENT_ABORTED' | 'INVALID_CATEGORY';
category?: 'marketing' | 'analytics' | 'preferences';
}
interface CookieZenAPI {
ready(): Promise<CookieZenAPI>;
getConsent(): Snapshot;
hasConsent(category: string): boolean;
hasResponse(): boolean;
require(category: 'marketing' | 'analytics' | 'preferences', opts?: RequireOptions): Promise<true>;
// Payload callbacka zależnie od eventu: 'change' -> ChangePayload;
// 'ready' -> instancja API (CookieZenAPI, nie Snapshot); pozostałe -> Snapshot.
on(event: ConsentEvent, cb: (payload: Snapshot | ChangePayload | CookieZenAPI) => void): CookieZenAPI;
off(event: ConsentEvent, cb: Function): CookieZenAPI;
once(event: ConsentEvent, cb: (payload: Snapshot | ChangePayload | CookieZenAPI) => void): CookieZenAPI;
accept(): Promise<Snapshot>;
decline(): Promise<Snapshot>;
submitConsent(partial: Partial<{ marketing: boolean; analytics: boolean; preferences: boolean; }>): Promise<Snapshot>;
show(opts?: { view?: 'main' | 'details' }): void;
showSettings(): void;
onMarketingConsent(cb: (snap: Snapshot) => void): CookieZenAPI;
onAnalyticsConsent(cb: (snap: Snapshot) => void): CookieZenAPI;
onPreferencesConsent(cb: (snap: Snapshot) => void): CookieZenAPI;
debug(): unknown;
}
declare global {
interface Window {
CookieZen: CookieZenAPI;
CookieZenCallback_OnReady?: (api: CookieZenAPI) => void;
}
interface WindowEventMap {
'cookiezen:ready': CustomEvent<{ categories: ConsentCategories; finalized: boolean }>;
'cookiezen:consent': CustomEvent<ChangePayload>;
'cookiezen:change': CustomEvent<ChangePayload>;
'cookiezen:accept': CustomEvent<Snapshot>;
'cookiezen:decline': CustomEvent<Snapshot>;
}
}Consent Mode → kategorie
Gdy Google Consent Mode jest włączony dla strony (ustawienie domyślne; można je wyłączyć w panelu CookieZen), CookieZen emituje standardowe sygnały Google Consent Mode v2 do window.dataLayer (gtag('consent', 'update', ...)) po każdej decyzji użytkownika. Dzięki temu narzędzia Google (GTM, GA4, Google Ads) oraz każda integracja oparta na Consent Mode automatycznie respektują zgodę bez dodatkowego kodu.
Jeśli Twoja integracja nasłuchuje Consent Mode, poniżej mapowanie kluczy na kategorie CookieZen:
| Klucz Consent Mode | Kategoria CookieZen |
|---|---|
ad_storage | marketing |
ad_user_data | marketing |
ad_personalization | marketing |
analytics_storage | analytics |
functionality_storage | preferences |
personalization_storage | preferences |
Kształt debug() (DebugSnapshot)
debug() zwraca migawkę stanu wyłącznie do diagnostyki. Nie buduj na niej kodu produkcyjnego: kształt nie jest częścią stabilnego kontraktu i służy tylko do ręcznej diagnostyki.
type DebugSnapshot = {
version: number; // wersja formatu snapshotu (obecnie 2)
siteKey: string;
url: string; // window.location.href w chwili wywołania
uptimeMs: number; // ms od startu banera (diagnostyka czasowa)
consent: {
categories: ConsentCategories;
method: string; // 'none' | 'unknown' | zapisana metoda zgody (np. 'accept')
loaderHadConsent: boolean;
};
// Rejestr zablokowanych zasobów (skrypty + iframe) - do diagnostyki automatycznego/ręcznego blokowania.
blocked: Array<{
src: string; // URL lub '(inline)'
kind: 'inline' | 'external' | 'iframe';
categories: string[]; // kategorie wymagane do odblokowania
reason: string; // 'manual-data-attr' | 'auto-detect' | 'default-preferences' | ...
by: 'loader' | 'banner'; // kto zablokował
t: number; // znacznik czasu (ms)
}>;
armed: unknown[]; // skrypty uzbrojone (armed) - rejestr diagnostyczny
unknown: unknown[]; // zasoby o nierozpoznanej kategorii
stats: {
blockedTotal: number;
blockedByLoader: number;
blockedByBanner: number;
armedTotal: number;
unknownTotal: number;
pendingBlockedScripts: number; // <script type="text/plain" data-cmp-category> czekające na zgodę
pendingBlockedFrames: number; // <iframe> czekające na zgodę
};
print: () => void; // czytelny wydruk snapshotu do konsoli narzędzi deweloperskich
};Przepisy integracyjne
Gotowe wzorce (React z czyszczeniem, once('accept'), AbortController, accept / decline z poziomu kodu, kontekstowa zgoda, GTM Custom HTML, synchronizacja iframe, synchronizacja wielu kart, integracja SDK plugin z load + unload + graceful fallback, cross-CMP przez Consent Mode) znajdziesz w cookiezen-docs-api.md, sekcja §10 Recipes.