Instrukcja użycia→ Wklej poniższy skrypt w sekcji <head> na stronie internetowej
→ Dostosuj tagi do zgód Consent Mode w ustawieniach w GTMSpis treściSkrypt bannera
<!-- PK Cookie Consent + Google Consent Mode v2 — wklej w <head> PRZED snippetem GTM -->
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
(function(){
var POLICY_VERSION = '1'; // zmień, gdy zmienia się polityka/zakres cookies — użytkownicy dostaną baner ponownie
var raw = (document.cookie.split(';').map(function(c){return c.trim();})
.find(function(c){return c.indexOf('consent=')===0;}) || '').substring(8);
var s = { consent:'no', analytics:'no', advertisement:'no', personalization:'no' };
var v = null;
raw.split(',').forEach(function(p){
var kv = p.split(':');
if (kv[0] in s) s[kv[0]] = (kv[1] === 'yes' ? 'yes' : 'no');
if (kv[0] === 'v') v = kv[1];
});
var hasChoice = (s.consent === 'yes' && v === POLICY_VERSION);
if (!hasChoice) { s.analytics = 'no'; s.advertisement = 'no'; s.personalization = 'no'; }
var g = function(x){ return x === 'yes' ? 'granted' : 'denied'; };
var toConsent = function(st){
return {
'analytics_storage': g(st.analytics),
'ad_storage': g(st.advertisement),
'ad_user_data': g(st.advertisement),
'ad_personalization': g(st.advertisement),
'personalization_storage': g(st.personalization),
'functionality_storage': 'granted',
'security_storage': 'granted'
};
};
var def = toConsent(s);
def['wait_for_update'] = 500;
gtag('consent', 'default', def);
gtag('set', 'url_passthrough', true);
gtag('set', 'ads_data_redaction', s.advertisement !== 'yes');
if (hasChoice) {
gtag('consent', 'update', toConsent(s));
window.dataLayer.push({
event: 'gtm_consent_update',
consent_source: 'stored',
consent_action: 'page_load',
consent: {
functionality: 'yes',
analytics: s.analytics,
advertisement: s.advertisement,
personalization: s.personalization
},
consent_raw: raw
});
}
window.__pkPolicyVersion = POLICY_VERSION;
})();
</script>
<style id="cb-styles">
:root{ --cb-ico-scale:1.30; }
#cb-overlay{
position:fixed; inset:0; background:rgba(0,0,0,.45);
z-index:2147483647;
display:flex; align-items:center; justify-content:center;
}
#cb-modal{
background:#ffffff; color:#0f172a; width:min(720px,92vw);
border-radius:16px; border:1px solid #e5e7eb; box-shadow:0 24px 80px rgba(0,0,0,.25);
overflow:hidden; z-index:2147483647;
}
.cb-top{ padding:0 24px; border-bottom:1px solid #e5e7eb; display:flex; gap:28px; }
.cb-tab{ padding:16px 0 14px; border-bottom:3px solid transparent; cursor:pointer; font-weight:800; color:#0f172a; }
.cb-tab.active{ border-color:#1960BF; }
.cb-body{ padding:22px; max-height:60vh; overflow:auto; }
.cb-title{ margin:0 0 10px; font-size:28px; font-weight:800; }
.cb-desc{ margin:0 0 16px; color:#475569; font-size:16px; }
.cb-info{ font-size:16px; color:#0f172a; }
.cb-info p{ margin:0 0 12px; }
.cb-info a, .cb-desc a{ color:#1960BF; font-weight:800; border-bottom:0; padding-bottom:0; box-shadow:none; }
.cb-list{ margin-top:8px; border-top:1px solid #e5e7eb; }
.cb-li{
display:flex; align-items:flex-start; justify-content:space-between;
padding:16px 0; border-bottom:1px solid #e5e7eb; gap:16px;
}
.cb-li strong{ font-weight:800; }
.cb-left{ min-width:0; }
.cb-sub{ margin:.35rem 0 0; color:#64748b; font-size:14px; line-height:1.4; }
.cb-right{ display:flex; align-items:center; gap:12px; flex:0 0 auto; }
.cb-switch{ position:relative; width:56px; height:32px; }
.cb-switch input{ position:absolute; opacity:0; width:0; height:0; }
.cb-slider{ position:absolute; inset:0; background:#e7e7e7; border-radius:999px; transition:.2s; }
.cb-slider:before{
content:""; position:absolute; left:3px; top:3px; width:26px; height:26px;
background:#fff; border-radius:50%; transition:.2s; box-shadow:0 1px 2px rgba(0,0,0,.25);
}
.cb-switch input:checked + .cb-slider{ background:#1960BF; }
.cb-switch input:focus-visible + .cb-slider{ outline:3px solid #1960BF; outline-offset:2px; }
.cb-switch input:checked + .cb-slider:before{ transform:translateX(24px); }
.cb-switch.disabled input:checked + .cb-slider{ background:#4A80D6; }
.cb-switch.disabled{ opacity:.9; }
.cb-actions{
display:flex; gap:12px; flex-wrap:wrap; padding:16px 22px;
border-top:1px solid #e5e7eb; background:#fafafa;
margin-bottom:15px;
}
.cb-actions.center{ justify-content:center; }
.cb-actions.end{ justify-content:flex-end; }
.cb-btn{
border:0; border-radius:12px; padding:12px 18px; cursor:pointer;
font-weight:900; min-width:210px; text-align:center;
}
.cb-btn.primary{ background:#1960BF; color:#fff; }
.cb-btn.secondary{ background:#1960BF; color:#fff; }
.cb-btn.ghost{ background:#fff; border:1px solid #e5e7eb; color:#1960BF; }
@media(max-width:640px){ .cb-btn{ flex:1 1 100%; min-width:100%; } }
#custom-button{
position:fixed; bottom:20px; left:20px; width:60px; height:60px; border:none; border-radius:50%;
background-color:#1960BF; cursor:pointer; z-index:2147483647;
display:flex; align-items:center; justify-content:center; transition:background-color .3s ease, transform .3s ease;
overflow:hidden;
}
#custom-button .cb-ico-wrap{ width:100%; height:100%; display:flex; align-items:center; justify-content:center; }
#custom-button .cb-ico{ width:36px; height:36px; display:block; transform:scale(var(--cb-ico-scale)); transform-origin:center; }
#custom-button:hover{ background-color:#144a94; transform:scale(1.06); }
</style>
<script id="cb-script">
(function(){
const COOKIE_NAME = "consent";
const TTL_DAYS = 180;
const POLICY_VERSION = window.__pkPolicyVersion || "1";
// Cookies stron trzecich do usunięcia po odrzuceniu/wycofaniu danej kategorii.
const CATEGORY_COOKIES = {
analytics: [/^_ga($|_)/, /^_gid$/, /^_gat/, /^_clck$/, /^_clsk$/, /^CLID$/, /^ANONCHK$/, /^MUID$/, /^SM$/],
advertisement: [/^_gcl_/, /^_fbp$/, /^_fbc$/, /^_gac_/, /^IDE$/, /^test_cookie$/],
personalization: []
};
const UI = {
text: {
tabs:["Zgody","Szczegóły","Informacje"],
title:"Ta strona używa plików cookie",
desc:'Niezbędne pliki cookie zapewniają działanie i bezpieczeństwo strony. Za Twoją zgodą używam też cookies analitycznych i reklamowych (m.in. Google, Microsoft Clarity, Meta). Możesz zaakceptować wszystkie, odrzucić wszystkie lub wybrać kategorie. Zgodę możesz w każdej chwili zmienić lub wycofać, klikając ikonę ciasteczka w rogu strony. Szczegóły w <a href="/polityka-prywatnosci/" target="_blank" rel="noopener">polityce prywatności</a>.',
detailsIntro:"Wybierz kategorie, na które wyrażasz zgodę (domyślnie wyłączone):",
acceptAll:"Akceptuj wszystkie",
rejectAll:"Odrzuć wszystkie",
customize:"Dostosuj",
save:"Zapisz wybrane",
infoHTML:
'<p>Administratorem danych jest właściciel serwisu. Dane z cookies analitycznych i reklamowych trafiają do dostawców narzędzi (Google Ireland Ltd., Microsoft Ireland Operations Ltd., Meta Platforms Ireland Ltd.).</p>' +
'<p>Zgoda jest przechowywana przez 180 dni w pliku cookie <code>consent</code> (wraz z datą decyzji). Masz prawo dostępu do danych, ich sprostowania, usunięcia oraz wniesienia skargi do UODO.</p>' +
'<p>Więcej w <a href="/polityka-prywatnosci/" target="_blank" rel="noopener">polityce prywatności</a>.</p>'
},
detailsRows:[
["Niezbędne (zawsze włączone)","functionality",true,"Konieczne do działania i bezpieczeństwa strony (np. sesja, koszyk, zapamiętanie Twojej decyzji o cookies). Nie wymagają zgody."],
["Analityczne","analytics",false,"Google Analytics 4, Microsoft Clarity — statystyki odwiedzin, źródła ruchu, nagrania sesji (anonimizowane)."],
["Reklamowe","advertisement",false,"Google Ads, Meta Pixel — pomiar skuteczności kampanii i dopasowanie reklam."],
["Personalizacyjne","personalization",false,"Dopasowanie treści i interfejsu (np. zapamiętane preferencje, rekomendacje)."]
]
};
const KEYS = ["consent","functionality","analytics","advertisement","personalization"];
const DEFAULTS = { consent:"no", functionality:"yes", analytics:"no", advertisement:"no", personalization:"no" };
function serializeState(state){
return KEYS.map(k => `${k}:${state[k]}`).join(",");
}
function serializeCookie(state, meta){
return serializeState(state) + `,v:${meta.v},ts:${meta.ts}`;
}
function setCookieState(state, days=TTL_DAYS){
const d = new Date(); d.setTime(d.getTime()+days*864e5);
const secure = location.protocol==="https:"?"; Secure":"";
const meta = { v: POLICY_VERSION, ts: Date.now() };
document.cookie = `${COOKIE_NAME}=${serializeCookie(state, meta)}; Expires=${d.toUTCString()}; Path=/; SameSite=Lax${secure}`;
}
function getCookieRaw(){
const m = document.cookie.split(";").map(c=>c.trim()).find(c=>c.startsWith(COOKIE_NAME+"="));
return m ? m.split("=",2)[1] : null;
}
function parseCookie(str){
const s = {...DEFAULTS, v:null, ts:null};
if(!str) return s;
str.split(",").forEach(p=>{
const [k,v]=p.split(":");
if(!k||!v) return;
if(KEYS.includes(k)) s[k]=(v==="yes"?"yes":"no");
else if(k==="v") s.v=v;
else if(k==="ts") s.ts=Number(v)||null;
});
s.functionality="yes";
return s;
}
const readState = () => parseCookie(getCookieRaw());
const hasChoice = () => { const s=readState(); return s.consent==="yes" && s.v===POLICY_VERSION; };
const stateOnly = s => ({consent:s.consent,functionality:"yes",analytics:s.analytics,advertisement:s.advertisement,personalization:s.personalization});
function deleteCookie(name){
const host = location.hostname;
const parts = host.split(".");
const domains = [null, host];
for(let i=1;i<parts.length-1;i++) domains.push("."+parts.slice(i).join("."));
domains.push("."+host);
domains.forEach(dom=>{
document.cookie = `${name}=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/` + (dom?`; Domain=${dom}`:"");
});
}
function purgeRejectedCookies(state){
const names = document.cookie.split(";").map(c=>c.trim().split("=")[0]).filter(Boolean);
Object.keys(CATEGORY_COOKIES).forEach(cat=>{
if(state[cat]==="yes") return;
names.forEach(n=>{ if(CATEGORY_COOKIES[cat].some(rx=>rx.test(n))) deleteCookie(n); });
});
}
function toConsent(state){
const g = v => v==="yes" ? "granted" : "denied";
return {
"analytics_storage": g(state.analytics),
"ad_storage": g(state.advertisement),
"ad_user_data": g(state.advertisement),
"ad_personalization": g(state.advertisement),
"personalization_storage": g(state.personalization),
"functionality_storage": "granted",
"security_storage": "granted"
};
}
function updateConsentMode(action, state){
window.dataLayer = window.dataLayer || [];
if (typeof gtag !== "function") {
window.gtag = function(){ dataLayer.push(arguments); };
}
gtag("consent","update", toConsent(state));
gtag("set","ads_data_redaction", state.advertisement !== "yes");
window.dataLayer.push({
event: "gtm_consent_update",
consent_source: "banner",
consent_action: action, // accept_all | reject_all | accept_selected
consent: {...state},
consent_raw: getCookieRaw()
});
}
function applyDecision(action, state, overlay){
setCookieState(state);
purgeRejectedCookies(state);
updateConsentMode(action, state);
closeModal(overlay);
}
let lastFocus = null;
function closeModal(ov){
ov.remove();
document.body.style.overflow = "";
if(lastFocus && lastFocus.focus) lastFocus.focus();
}
function build(initial){
if(document.getElementById("cb-overlay")) return;
lastFocus = document.activeElement;
const ov=document.createElement("div");
ov.id="cb-overlay";
ov.innerHTML=`
<div id="cb-modal" role="dialog" aria-modal="true" aria-labelledby="cb-title">
<div class="cb-top" role="tablist">
<div class="cb-tab active" data-tab="consents" role="tab" tabindex="0" aria-selected="true">${UI.text.tabs[0]}</div>
<div class="cb-tab" data-tab="details" role="tab" tabindex="0" aria-selected="false">${UI.text.tabs[1]}</div>
<div class="cb-tab" data-tab="info" role="tab" tabindex="0" aria-selected="false">${UI.text.tabs[2]}</div>
</div>
<div class="cb-body">
<div id="pane-consents">
<h3 class="cb-title" id="cb-title">${UI.text.title}</h3>
<p class="cb-desc">${UI.text.desc}</p>
</div>
<div id="pane-details" style="display:none">
<p class="cb-desc">${UI.text.detailsIntro}</p>
<div class="cb-list">
${UI.detailsRows.map(([label,key,lock,desc])=>`
<div class="cb-li">
<div class="cb-left">
<strong id="cb_lbl_${key}">${label}</strong>
${desc?`<p class="cb-sub">${desc}</p>`:""}
</div>
<div class="cb-right">
<label class="cb-switch ${lock?"disabled":""}">
<input type="checkbox" id="cb_${key}" aria-labelledby="cb_lbl_${key}" ${initial[key]==="yes"?"checked":""} ${lock?"disabled":""}>
<span class="cb-slider"></span>
</label>
</div>
</div>`).join("")}
</div>
</div>
<div id="pane-info" class="cb-info" style="display:none">${UI.text.infoHTML}</div>
</div>
<div class="cb-actions center" id="actions-consents">
<button class="cb-btn ghost" id="btn-reject">${UI.text.rejectAll}</button>
<button class="cb-btn ghost" id="btn-customize">${UI.text.customize}</button>
<button class="cb-btn primary" id="btn-accept">${UI.text.acceptAll}</button>
</div>
<div class="cb-actions end" id="actions-details" style="display:none">
<button class="cb-btn ghost" id="btn-reject-2">${UI.text.rejectAll}</button>
<button class="cb-btn primary" id="btn-save">${UI.text.save}</button>
</div>
</div>`;
document.body.appendChild(ov);
document.body.style.overflow = "hidden";
const tabs=ov.querySelectorAll(".cb-tab");
const panes={consents:ov.querySelector("#pane-consents"),details:ov.querySelector("#pane-details"),info:ov.querySelector("#pane-info")};
const acts={consents:ov.querySelector("#actions-consents"),details:ov.querySelector("#actions-details")};
function showTab(which){
tabs.forEach(x=>{ x.classList.remove("active"); x.setAttribute("aria-selected","false"); });
const t=[...tabs].find(t=>t.dataset.tab===which); t.classList.add("active"); t.setAttribute("aria-selected","true");
Object.keys(panes).forEach(k=>panes[k].style.display = k===which ? "block" : "none");
acts.consents.style.display = which==="consents" ? "flex":"none";
acts.details.style.display = which==="details" ? "flex":"none";
}
tabs.forEach(t=>{
t.addEventListener("click",()=>showTab(t.dataset.tab));
t.addEventListener("keydown",e=>{ if(e.key==="Enter"||e.key===" "){ e.preventDefault(); showTab(t.dataset.tab); } });
});
const reject = ()=>applyDecision("reject_all",
{consent:"yes",functionality:"yes",analytics:"no",advertisement:"no",personalization:"no"}, ov);
ov.querySelector("#btn-accept").addEventListener("click",()=>{
applyDecision("accept_all",
{consent:"yes",functionality:"yes",analytics:"yes",advertisement:"yes",personalization:"yes"}, ov);
});
ov.querySelector("#btn-reject").addEventListener("click",reject);
ov.querySelector("#btn-reject-2").addEventListener("click",reject);
ov.querySelector("#btn-customize").addEventListener("click",()=>showTab("details"));
ov.querySelector("#btn-save").addEventListener("click",()=>{
const val=k=>(ov.querySelector("#cb_"+k)?.checked?"yes":"no");
applyDecision("accept_selected",{
consent:"yes",
functionality:"yes",
analytics:val("analytics"),
advertisement:val("advertisement"),
personalization:val("personalization")
}, ov);
});
ov.addEventListener("keydown",e=>{ if(e.key==="Escape" && hasChoice()) closeModal(ov); });
const focusables = ()=>[...ov.querySelectorAll('button, [tabindex="0"], input:not([disabled]), a[href]')].filter(el=>el.offsetParent!==null);
ov.addEventListener("keydown",e=>{
if(e.key!=="Tab") return;
const f=focusables(); if(!f.length) return;
const first=f[0], last=f[f.length-1];
if(e.shiftKey && document.activeElement===first){ e.preventDefault(); last.focus(); }
else if(!e.shiftKey && document.activeElement===last){ e.preventDefault(); first.focus(); }
});
ov.querySelector("#btn-reject").focus({preventScroll:true});
}
function addLauncher(){
if(document.getElementById("custom-button")) return;
const btn=document.createElement("button");
btn.id="custom-button"; btn.setAttribute("aria-label","Zmień lub wycofaj zgody na pliki cookie");
btn.innerHTML=`<span class="cb-ico-wrap">
<svg class="cb-ico" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" aria-hidden="true" focusable="false">
<path fill="#ffffff" d="M257.5 27.6c-.8-5.4-4.9-9.8-10.3-10.6c-22.1-3.1-44.6.9-64.4 11.4l-74 39.5C89.1 78.4 73.2 94.9 63.4 115L26.7 190.6c-9.8 20.1-13 42.9-9.1 64.9l14.5 82.8c3.9 22.1 14.6 42.3 30.7 57.9l60.3 58.4c16.1 15.6 36.6 25.6 58.7 28.7l83 11.7c22.1 3.1 44.6-.9 64.4-11.4l74-39.5c19.7-10.5 35.6-27 45.4-47.2l36.7-75.5c9.8-20.1 13-42.9 9.1-64.9c-.9-5.3-5.3-9.3-10.6-10.1c-51.5-8.2-92.8-47.1-104.5-97.4c-1.8-7.6-8-13.4-15.7-14.6c-54.6-8.7-97.7-52-106.2-106.8zM208 144a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM144 336a32 32 0 1 1 64 0 32 32 0 1 1 0-64zm224-64a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/>
</svg>
</span>`;
btn.addEventListener("click",()=>window.cookieBanner.open());
document.body.appendChild(btn);
}
window.cookieBanner={
open:()=>build(stateOnly(hasChoice()?readState():DEFAULTS)),
reset:()=>{ setCookieState({...DEFAULTS}); build(stateOnly(DEFAULTS)); },
get:()=>{ const s=readState(); return hasChoice()? s : {...stateOnly(DEFAULTS), v:s.v, ts:s.ts}; },
getRaw:()=>getCookieRaw()
};
function init(){
addLauncher();
if(!hasChoice()) build(stateOnly(DEFAULTS));
}
if(document.readyState==="complete") init();
else window.addEventListener("load",init);
})();
</script>Kod zmiennej dla reklam (advertisement)
function () {
function getConsentCookie() {
var name = 'consent='; // Nazwa ciasteczka ze zrzutu ekranu
var decodedCookie = decodeURIComponent(document.cookie); // Dekodowanie znaków specjalnych
var parts = decodedCookie.split(';');
for (var i = 0; i < parts.length; i++) {
var c = parts[i];
// Usuwanie spacji wiodących (alternatywa dla pętli while)
c = c.trim();
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
var v = getConsentCookie();
// Sprawdzamy zgodę
if (v.indexOf('advertisement:yes') > -1) {
return 'granted';
}
// Sprawdzamy odmowę
if (v.indexOf('advertisement:no') > -1) {
return 'denied';
}
// Domyślna wartość
return 'denied';
}Kod zmiennej dla analityki (analytics)
function () {
function getConsentCookie() {
var name = 'consent='; // Nazwa ciasteczka ze zrzutu ekranu
var decodedCookie = decodeURIComponent(document.cookie); // Dekodowanie znaków specjalnych
var parts = decodedCookie.split(';');
for (var i = 0; i < parts.length; i++) {
var c = parts[i];
// Usuwanie spacji wiodących (alternatywa dla pętli while)
c = c.trim();
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
var v = getConsentCookie();
// Sprawdzamy zgodę
if (v.indexOf('analytics:yes') > -1) {
return 'granted';
}
// Sprawdzamy odmowę
if (v.indexOf('analytics:no') > -1) {
return 'denied';
}
// Domyślna wartość
return 'denied';
}Kod zmiennej dla funkcjnych (functionality)
function () {
function getConsentCookie() {
var nameA = 'consent=';
var nameB = 'cookieyes-consent=';
var decodedCookie = decodeURIComponent(document.cookie); // Dekodowanie znaków
var parts = decodedCookie.split(';');
for (var i = 0; i < parts.length; i++) {
var c = parts[i].trim();
if (c.indexOf(nameA) === 0) return c.substring(nameA.length, c.length);
if (c.indexOf(nameB) === 0) return c.substring(nameB.length, c.length);
}
return '';
}
var v = getConsentCookie();
// Sprawdzamy zgodę
if (v.indexOf('functionality:yes') > -1) {
return 'granted';
}
// Sprawdzamy odmowę
if (v.indexOf('functionality:no') > -1) {
return 'denied';
}
// Domyślna wartość
return 'denied';
}Kod zmiennej dla personaliacji (personalization)
function () {
function getConsentCookie() {
var nameA = 'consent=';
var nameB = 'cookieyes-consent=';
var decodedCookie = decodeURIComponent(document.cookie); // Dekodowanie znaków
var parts = decodedCookie.split(';');
for (var i = 0; i < parts.length; i++) {
var c = parts[i].trim();
if (c.indexOf(nameA) === 0) return c.substring(nameA.length, c.length);
if (c.indexOf(nameB) === 0) return c.substring(nameB.length, c.length);
}
return '';
}
var v = getConsentCookie();
// Sprawdzamy zgodę
if (v.indexOf('personalization:yes') > -1) {
return 'granted';
}
// Sprawdzamy odmowę
if (v.indexOf('personalization:no') > -1) {
return 'denied';
}
// Domyślna wartość
return 'denied';
}

