Instrukcja użycia→ Wklej poniższy skrypt w sekcji <head> na stronie internetowej
→ W GTM skorzystaj z szablonu Consent Mode (gtm-templates-simo-ahava)
→ Użyj poniższych zmiennych, aby przechwycić status zgód
→ Dostosuj tag oraz zgody Consent Mode do ustawień w GYM
Szczegółową instrukcję znajdziesz tutaj.
Spis treści
Skrypt bannera
<style id="cb-styles">
/* ===================== STYLE (akcent: #1960BF) ===================== */
:root{ --cb-ico-scale:1.30; } /* powiększanie samej ikonki ciasteczka */
#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 a{ color:#1960BF; font-weight:800; text-decoration:none; border-bottom:2px solid #1960BF; padding-bottom:2px; }
.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; }
/* Suwak */
.cb-switch{ position:relative; width:56px; height:32px; }
.cb-switch input{ display:none; }
.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: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%; } }
/* ===== LAUNCHER (ciasteczko) – stałe kółko, rośnie tylko ikona ===== */
#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; /* klip ikony gdy będzie większa */
}
#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>
(function(){
const COOKIE_NAME = "consent";
const TTL_DAYS = 180;
const UI = {
text: {
tabs:["Zgody","Szczegóły","Informacje"],
title:"Używam plików cookie",
desc:'Wykorzystuje pliki cookies do zapewnienia bezpieczeństwa, celów analitycznych i ulepszania naszej strony internetowej. Kliknij "Dostosuj", jeśli chcesz wybrać preferowane przez Ciebie pliki cookie.',
detailsIntro:"Dostosuj, które kategorie plików cookie mają być włączone:",
acceptAll:"Akceptuj wszystkie",
rejectAll:"Odrzuć wszystkie",
customize:"Dostosuj",
save:"Akceptuj wybrane",
infoHTML:'Więcej informacji znajdziesz w naszej <a href="/polityka-prywatnosci/" target="_blank" rel="nofollow">polityce prywatności</a>.'
},
detailsRows:[
["Funkcyjne (zawsze włączone)","functionality",true,"Pliki cookie konieczne do działania strony i nie przechowują danych pozwalających na identyfikację."],
["Analityczne","analytics",false,"Służą do zrozumienia zachowania użytkowników (np, liczba wizyt, źródła ruchu)."],
["Reklamowe","advertisement",false,"Służą do personalizacji reklam oraz analizy skuteczności kampanii."],
["Personalizacyjne","personalization",false,"Służą do dopasowania treści i interfejsu do użytkownika (np. zapamiętywanie preferencji, rekomendacje)."]
]
};
const KEYS = ["consent","functionality","analytics","advertisement","personalization"];
const DEFAULTS = {
consent:"no",
functionality:"yes",
analytics:"yes",
advertisement:"yes",
personalization:"yes"
};
function serializeState(state){
return KEYS.map(k => `${k}:${state[k]}`).join(",");
}
function setCookieState(state, days=TTL_DAYS){
const d = new Date(); d.setTime(d.getTime()+days*864e5);
const secure = location.protocol==="https:"?"; Secure":"";
document.cookie = `${COOKIE_NAME}=${serializeState(state)}; 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};
if(!str) return s;
str.split(",").forEach(p=>{
const [k,v]=p.split(":");
if(k&&v&&KEYS.includes(k)) s[k]=(v==="yes"?"yes":"no");
});
s.functionality="yes";
return s;
}
const readState = () => parseCookie(getCookieRaw());
const hasChoice = () => readState().consent==="yes";
function pushDL(action, state){
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "button_consent_click",
action,
consent: {...state},
consent_raw: serializeState(state),
timestamp: new Date().toISOString()
});
}
function build(initial){
const ov=document.createElement("div");
ov.id="cb-overlay";
ov.innerHTML=`
<div id="cb-modal">
<div class="cb-top">
<div class="cb-tab active" data-tab="consents">${UI.text.tabs[0]}</div>
<div class="cb-tab" data-tab="details">${UI.text.tabs[1]}</div>
<div class="cb-tab" data-tab="info">${UI.text.tabs[2]}</div>
</div>
<div class="cb-body">
<div id="pane-consents">
<h3 class="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>${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}" ${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 primary" id="btn-save">${UI.text.save}</button>
</div>
</div>`;
document.body.appendChild(ov);
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"));
[...tabs].find(t=>t.dataset.tab===which).classList.add("active");
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)));
ov.querySelector("#btn-accept").addEventListener("click",()=>{
const s={consent:"yes",functionality:"yes",analytics:"yes",advertisement:"yes",personalization:"yes"};
setCookieState(s);
ov.remove();
setTimeout(()=>pushDL("accept_all", s),500);
});
ov.querySelector("#btn-reject").addEventListener("click",()=>{
const s={consent:"yes",functionality:"yes",analytics:"no",advertisement:"no",personalization:"no"};
setCookieState(s);
ov.remove();
setTimeout(()=>pushDL("reject_all", s),500);
});
ov.querySelector("#btn-customize").addEventListener("click",()=>showTab("details"));
ov.querySelector("#btn-save").addEventListener("click",()=>{
const val=k=>(ov.querySelector("#cb_"+k)?.checked?"yes":"no");
const s={
consent:"yes",
functionality:"yes",
analytics:val("analytics"),
advertisement:val("advertisement"),
personalization:val("personalization")
};
setCookieState(s);
ov.remove();
setTimeout(()=>pushDL("accept_selected", s),500);
});
}
function addLauncher(){
if(document.getElementById("custom-button")) return;
const btn=document.createElement("button");
btn.id="custom-button"; btn.setAttribute("aria-label","Zmień zgody");
/* to SAMO ciasteczko – tylko opakowane, by można było je skalować niezależnie od kółka */
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(readState()),
reset:()=>{ setCookieState({...DEFAULTS,consent:"no"}); build(readState()); },
get:()=>readState(),
getRaw:()=>getCookieRaw()
};
window.addEventListener("load",()=>{
addLauncher();
if(!hasChoice()) build(readState());
});
})();
</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';
}