Udzielania zgody na śledzenie przez Google Tag Manager

Strona główna » Różne » Udzielania zgody na śledzenie przez Google Tag Manager

Jeśli prowadzisz stronę sprzedażową lub pracujesz z danymi w eCommerce, to wdrożenie mechanizmu zarządzania zgodami (consent) jest dziś obowiązkiem zarówno prawnym, jak i praktycznym.

Ten artykuł pokaże Ci krok po kroku, jak bezpłatnie wdrożyć baner zgód na WordPressie i poprawnie połączyć go z Google Tag Manager – tak, aby Twoje tagi działały zgodnie z wyborem użytkownika.

Wdrożenie mechanizmu zarządzania zgodami to klucz do legalnej analityki – chroni prywatność i buduje zaufanie klientów.

Skrót (TL;DR)

→ Zainstaluj darmowy baner zgód w WordPress i ustaw domyślny stan na denied.
→ W GTM wdroż Consent Mode, użyj zmiennych (opartych na ciasteczkach) i przypisz zgody do tagów.
Zweryfikuj swoje ustawienia dokonując testów.

Darmowy eBook Google Analytics 4

    Video tutorial

    Kwestie prawne i ograniczenia

    Zanim przejdziemy do technicznych działań, warto uświadomić sobie dwie rzeczy:

    • Nie jestem prawnikiem – wskazówki techniczne w tym artykule nie zastąpią porady prawnej. Jeśli chcesz mieć pewność co do zgodności z lokalnymi przepisami (np. UODO w Polsce, RODO/ GDPR), skonsultuj się z prawnikiem.
    • Płatne vs darmowe rozwiązania – na rynku istnieją gotowe, rozbudowane rozwiązania (Cookiebot, CookieYes, itp.), ale często są płatne w modelu abonamentowym. Wiele sklepów eCommerce może z powodzeniem skorzystać z darmowego rozwiązania, o ile rozumie jego ograniczenia (brak ewidencji zgód, brak automatycznego skanu ciasteczek, ręczne uzupełnianie polityki cookies itp.).
    Zrzut ekranu przedstawiający plany cenowe Cookiebot
    Zrzut ekranu przedstawiający plany cenowe Cookiebot

    Darmowe rozwiązanie, które pokażę, jest wystarczające dla mniejszych eCommerce, które chcą uniknąć comiesięcznych opłat, ale rozumieją ryzyko i ograniczenia.

    Zrzut ekranu przedstawiający baner informujący o użyciu plików cookie
    Zrzut ekranu przedstawiający baner informujący o użyciu plików cookie

    Jeśli prowadzisz duży serwis eCommerce z wieloma źródłami ruchu i intensywnymi kampaniami reklamowymi, rozważ jednak komercyjne rozwiązanie.

    Wtyczki, które warto zainstalować

    Polecam zainstalować dwie wtyczki do przeglądarki.

    Cookie Editor – służy do przeglądania ciasteczek na stronie; bardzo pomocne przy testach i dokumentacji do polityki prywatności. 

    Zrzut ekranu przedstawiający wtyczkę Cookie-Editor w Chrome Web Store
    Zrzut ekranu przedstawiający wtyczkę Cookie-Editor w Chrome Web Store

    Consent Mode Inspector – pokazuje stan zgód: default state i update state (granted/denied). Przydaje się do szybkich testów poprawności wdrożenia.

    Zrzut ekranu przedstawiający wtyczkę Consent Mode Inspector w Chrome Web Store
    Zrzut ekranu przedstawiający wtyczkę Consent Mode Inspector w Chrome Web Store

    Rozszerzenia w przeglądarce usprawnią cały proces testowania i debugowania.

    Zrozumienie rodzajów zgód

    Musisz wiedzieć, jakie rodzaje zgód będziesz obsługiwać, ponieważ w GTM przypisujemy rodzaje zgód do tagów.

    Oto najważniejsze typy (terminologia zgodna z Google):

    • analytics_storage – zgoda na zapisywanie danych analitycznych (np. GA4, statystyki odwiedzin)
    • ad_storage – zgoda na zapisywanie danych reklamowych (np. remarketing w Google Ads).
    • ad_user_data – zgoda na wysyłanie danych użytkownika do systemów reklamowych Google.
    • ad_personalization – zgoda na personalizację reklam (dopasowanie treści reklam do użytkownika).
    • personalization_storage – zgoda na zapisywanie danych do personalizacji treści/ustawień strony.

    W praktyce podzielimy zgody na grupy:

    • Niezbędne: functionality_storage (działanie strony).
    • Analityczne: analytics_storage.
    • Marketingowe / reklamowe: ad_storage, ad_user_data, ad_personalization.
    • Personalizacyjne: personalization_storage.

    Dzięki temu w Google Tag Manager będziemy mogli przypisać, które tagi mają się odpalać tylko przy danej zgodzie.

    Dodanie darmowego bannera zgód na WordPress

    W pierwszej kolejności zainstaluj wtyczkę na WordPress, do wklejania kodu w head/footer. Może to być wtyczka „Header Footer Code Manager”.

    Zrzut ekranu przedstawiający instalację wtyczki Header Footer Code Manager na WordPress
    Zrzut ekranu przedstawiający instalację wtyczki Header Footer Code Manager na WordPress

    W panelu wtyczki dodaj nowy snippet (Add New Snippet). Nadaj mu nazwę, np. „Consent Mode”.

    Zrzut ekranu przedstawiający konfigurację nowego snippetu w WordPressie
    Zrzut ekranu przedstawiający konfigurację nowego snippetu w WordPressie

    Wklej poniższy skrypt w sekcji „Snippet / Code”

    Kod bannera

    Instrukcja
    <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>

    Zapisz snippet i opublikuj. Przejdź na stronę i sprawdź, czy pojawiła się ikona ciasteczka i baner.

    Zrzut ekranu przedstawiający wstawianie kodu JavaScript Conent Mode na WordPress
    Zrzut ekranu przedstawiający wstawianie kodu JavaScript Conent Mode na WordPress

    Baner, który proponuję, jest minimalistyczny, ale funkcjonalny: ma opcję „Akceptuj wszystkie”, „Odrzuć wszystkie” oraz „Dostosuj” – gdzie użytkownik może włączyć / wyłączyć grupy zgód (functionality, analytics, advertisement, personalization).

    Zrzut ekranu przedstawiający ustawienia akceptacji plików cookie w przeglądarce
    Zrzut ekranu przedstawiający ustawienia akceptacji plików cookie w przeglądarce

    Użytkownik może zapisać wybór w ciasteczku „consent”, którego wartość zawiera tekstowy zapis stanu zgód (yes/no dla każdej grupy). To właśnie będziemy potem zaczytywać w GTM.

    Zrzut ekranu przedstawiający edytor plików cookie pochodzącego z bannera cookies
    Zrzut ekranu przedstawiający edytor plików cookie pochodzącego z bannera cookies

    Ustawienia w Google Tag Manager

    Teraz pora na połączenie bannera z tagami śledzącymi. Do tego celu wykorzystamy Google Tag Managera.

    Dodanie szablonu Consent Mode

    W GTM przejdź do zakładki „Szablony” (Templates) – wybierz „Galeria”. Wyszukaj „Consent Mode” (autor: Simo Ahava) i dodaj go do obszaru roboczego.

    Zrzut ekranu przedstawiający wybór typu tagu w Google Tag Manager z szablonów rozwiązań
    Zrzut ekranu przedstawiający wybór typu tagu w Google Tag Manager z szablonów rozwiązań

    Utwórz dwa tagi:

    • consent mode – default: będzie uruchamiany przy załadowaniu kontenera (stan początkowy – deny)
    • consent mode – update: będzie uruchamiany, gdy zmieni się zgoda użytkownika (np. kliknięcie w baner).

    Ustaw regułę dla tagu default: „Consent Initialization – All Pages” (czyli ma działać przy każdej wczytanej stronie).

    Zrzut ekranu przedstawiający ustawienia tagu Consent Mode - Default w Google Tag Manager
    Zrzut ekranu przedstawiający ustawienia tagu Consent Mode – Default w Google Tag Manager

    Skopiuj tag i utwórz wersję update, do której później dopiszesz regułę uruchamiania przy zmianie zgody.

    Zrzut ekranu przedstawiający ustawienia tagu Consent Mode - Update w Google Tag Manager
    Zrzut ekranu przedstawiający ustawienia tagu Consent Mode – Update w Google Tag Manager

    Sprawdz działanie tagów. Ustaw w Consent Mode – update wszystko na „granted”.

    Zrzut ekranu przedstawiający ustawienia trybu zgody w Google Tag Manager
    Zrzut ekranu przedstawiający ustawienia trybu zgody w Google Tag Manager

    Następnie wejdź w tryb poglądu Google Tag Managera i sprawdź co pokazała wtyczka.

    Zrzut ekranu przedstawiający ustawienia zgód w Consent Mode Inspector
    Zrzut ekranu przedstawiający ustawienia zgód w Consent Mode Inspector

    Włączenie opcji uzyskiwania zgód w ustawieniach kontenera

    Aby móc przypisywać zgody do tagów, w ustawieniach kontenera w GTM musisz włączyć przegląd ustawień uzyskania zgody.

    Przejdź do Administracja (Admin) → Ustawienia kontenera (Container Settings). W dolnej części włącz „Włącz przegląd ustawień uzyskania zgody (beta)„. Zapisz zmiany.

    Zrzut ekranu przedstawiający ustawienia dodatkowe kontenera w Google Tag Manager
    Zrzut ekranu przedstawiający ustawienia dodatkowe kontenera w Google Tag Manager

    Po tej zmianie w widoku tagu zobaczysz ikonę tarczy, która umożliwia przypisywanie typów zgód (wbudowane / dodatkowe). Dzięki temu GTM blokuje lub pozwala na odpalenie tagu w zależności od zgody użytkownika.

    Zrzut ekranu przedstawiający interfejs Menedżera tagów z listą tagów
    Zrzut ekranu przedstawiający interfejs Menedżera tagów z listą tagów

    Ustawienie zmiennych, które odczytują ciasteczko consent

    Ciasteczko „consent” zawiera informacje w formacie tekstowym (np. analytics=yes, advertisement=no, personalization=yes).

    Musimy w GTM przygotować zmienne, które odczytają poszczególne wartości i zwrócą „granted” lub „denied” (to są wartości akceptowane przez tag consent mod).

    W GTM wejdź w Zmienne -> Nowa zmienna zdefiniowana przez użytkownika. Wybierz typ „Niestandardowy kod JavaScript (Custom JavaScript)”.

    Zrzut ekranu przedstawiający wybór Niestandardowego kodu JavaScript jako zmiennej w Google Tag Manager
    Zrzut ekranu przedstawiający wybór Niestandardowego kodu JavaScript jako zmiennej w Google Tag Manager

    Wklej fragment kodu JavaScript, który odczytuje ciasteczko consent i sprawdza np. wartość dla „advertisement”. Jeśli wartość to „yes”, zwróć „granted”, jeśli „no” – „denied”.

    Kod zmiennej dla reklam (advertisement)

    Instrukcja
    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)

    Instrukcja
    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)

    Instrukcja
    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)

    Instrukcja
    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';
    }

    Nazwij zmienne w następujący sposób:

    • cjs – cookie-advertisement-status,
    • cjs – cookie-analytics-status,
    • cjs – cookie-functionality-status.
    • cjs – cookie-personalization-status.
    Zrzut ekranu przedstawiający implementację niestandardowego kodu JavaScript w Google Tag Manager
    Zrzut ekranu przedstawiający implementację niestandardowego kodu JavaScript w Google Tag Manager
    Zrzut ekranu przedstawiający niestandardowe zmienne JavaScript w Google Tag Manager
    Zrzut ekranu przedstawiający niestandardowe zmienne JavaScript w Google Tag Manager

    Dzięki nim będziemy mogli dynamicznie ustawiać stan zgód w tagu consent update (w miejscu, gdzie w GTM można wskazać zmienną zamiast stałej wartości).

    Zrzut ekranu przedstawiający wartości niestandardowych zmiennych JavaScript w Google Tag Manager
    Zrzut ekranu przedstawiający wartości niestandardowych zmiennych JavaScript w Google Tag Manager

    Połączenie zmiennych z tagiem Consent Mode – update

    Wróć do tagu „consent mode – update” i w jego ustawieniach zmień wartości poszczególnych zgód tak, aby odczytywały nasze zmienne CJS. Przykład:

    • ad_storage – zmienna „cjs – cookie-advertisement-status”,
    • ad_user_data – zmienna „cjs – cookie-advertisement-status”,
    • analytics_storage – zmienna „cjs – cookie-analytics-status”,
    • ad_personalization – zmienna „cjs – cookie-personalization-status”.
    Zrzut ekranu przedstawiający ustawienia trybu zgody w Google Tag Manager dla tagu Consent Mode - Update
    Zrzut ekranu przedstawiający ustawienia trybu zgody w Google Tag Manager dla tagu Consent Mode – Update

    Dla „Other signals” można zostawić zgody na „granted”.

    W ten sposób tag consent update będzie się dynamicznie dostosowywał do wyboru użytkownika: jeśli ciasteczko pokaże „yes” dla analytics, GTM ustawi analytics jako granted; jeśli „no”, to denied.

    Uwaga: Default zawsze powinien być ustawiony na denied (czerwony). Tylko update ma brać wartość z ciasteczek. Dzięki temu mamy zasadę „privacy by default”.

    Zrzut ekranu przedstawiający ustawienia trybu zgody w Google Tag Manager dla tagu Consent Mode - Default
    Zrzut ekranu przedstawiający ustawienia trybu zgody w Google Tag Manager dla tagu Consent Mode – Default

    Reguły wyzwalania update – reagowanie na kliknięcie w banner

    Musisz zadbać o dwa scenariusze:

    • Użytkownik pierwszy raz wchodzi na stronę – baner pojawia się i mamy default = denied; po akceptacji powinien uruchomić się update.
    • Użytkownik zmienia zdanie podczas sesji – kliknięcie w baner powinno zaktualizować stan zgód (update).

    Aby to zrobić, w pierwszej kolejności w trybie podglądu GTM sprawdź, jakie eventy generuje baner. W przykładzie jest to event typu custom: button_consent_click.

    Zrzut ekranu przedstawiający wydarzenie button_consent_click w Google Tag Manager
    Zrzut ekranu przedstawiający wydarzenie button_consent_click w Google Tag Manager

    W GTM utwórz nową regułę (Trigger) typu „Zdarzenie niestandardowe (Custom Event)” i jako nazwę wpisz dokładnie nazwę eventu wygenerowaną przez baner.

    Zrzut ekranu przedstawiający ustawienia niestandardowej reguły w Google Tag Manager
    Zrzut ekranu przedstawiający ustawienia niestandardowej reguły w Google Tag Manager

    Przypisz tę regułę jako dodatkowy wyzwalacz do tagu „Consent Mode – Update”. Dzięki temu tag update będzie wywoływany zarówno przy załadowaniu strony, jak i przy kliknięciu przez użytkownika.

    Zrzut ekranu przedstawiający reguły uruchamiania tagu Consent Mode - Update w Google Tag Manager
    Zrzut ekranu przedstawiający reguły uruchamiania tagu Consent Mode – Update w Google Tag Manager

    Teraz gdy użytkownik kliknie „Akceptuj wszystkie”, wygenerowany event uruchomi tag update oraz od razu ustawi odpowiednie zgody w GTM.

    Zrzut ekranu przedstawiający zgody w Consent Mode Inspector
    Zrzut ekranu przedstawiający zgody w Consent Mode Inspector

    Przypisywanie zgód do tagów

    W sekcji tagów, kliknij w ikonkę tarczy i przejdź do „Przgląd ustawień uzyskiwania zgody”.

    Zrzut ekranu przedstawiający przegląd ustawień uzyskiwania zgody w Google Tag Manager
    Zrzut ekranu przedstawiający przegląd ustawień uzyskiwania zgody w Google Tag Manager

    Następnie:

    • Dla tagów związanych z Consent Mode – ustaw „Brak wymogu uzyskania dodatkowej zgody”, ponieważ są one za to odpowiedzialne,
    • Dla tagów Google – ustaw „Brak wymogu uzyskania dodatkowej zgody”, ponieważ tagi Google mają wbudowaną obsługę consent,
    • Dla tagów niegooglowskich – wybierz opcję „Dodatkowa zgoda na uruchomienie tagu” i dodaj wymagane typy zgód (ad_storage, analytics, personalization w zależności od tagu).
    Zrzut ekranu przedstawiający edycję zgód dla tagów w Google Tag Manager
    Zrzut ekranu przedstawiający edycję zgód dla tagów w Google Tag Manager

    Po tej czynności, wszystkie tagi powinny znajdować się w sekcji „Skonfigurowano uzyskiwania zgody”.

    Zrzut ekranu przedstawiający listę zgód dla tagów w Google Tag Manager
    Zrzut ekranu przedstawiający listę zgód dla tagów w Google Tag Manager

    Teraz jeśli użytkownik nie wyraził zgody na reklamy, Facebook Pixel nie będzie uruchomiony.

    Dla Google Analytics natomiast, jeśli zgoda na analytics nie została dana, GTM wyśle zanonimizowane pingi (advanced consent mode), które pozwalają Google modelować dane bez pełnej identyfikacji – to legalne i użyteczne, ale trzeba o tym pamiętać przy interpretacji danych eCommerce.

    Zrzut ekranu przedstawiający odpalenie tagu Google Analytics w sposób zanonimizowany (advanced consent mode)
    Zrzut ekranu przedstawiający odpalenie tagu Google Analytics w sposób zanonimizowany (advanced consent mode)

    Zdarzenie page_view dla tagów niegooglowskich

    Jeden problem, który pojawił się w praktyce: gdy użytkownik wchodzi pierwszy raz na stronę i akceptuje baner, page_view dla Facebooka może nie zostać wysłany, ponieważ tag próbował się uruchomić jeszcze przed zarejestrowaniem updatu zgody.

    Aby to rozwiązać, w tagu „consent mode – update” włącz opcję „Push Data Layer Event” – czyli po wykonaniu update tag wygeneruje event w warstwie danych, np. gtm_constant_update.

    Zrzut ekranu przedstawiający ustawienia Consent Mode w Google Tag Manager
    Zrzut ekranu przedstawiający ustawienia Consent Mode w Google Tag Manager

    W GTM utwórz trigger (regułę) typu Custom Event z nazwą dokładnie taką jak wygenerowany event (gtm_constant_update).

    Zrzut ekranu przedstawiający konfigurację reguły związaną z consent update w Google Tag Manager
    Zrzut ekranu przedstawiający konfigurację reguły związaną z consent update w Google Tag Manager

    Dla tagów niegooglowskich, które wyświetlają się na każdej podstronie (np. FB Pixel – PageView) zmień regułę odpalenia: zamiast All Pages użyj tego custom eventu.

    W ten sposób page_view dla Facebooka będzie wysłany dopiero po zaktualizowaniu zgód – czyli po akceptacji przez użytkownika.

    Zrzut ekranu przedstawiający ustawienia zdarzenia PageView Facebook Pixel w zależnosci od zgody na śledzenie
    Zrzut ekranu przedstawiający ustawienia zdarzenia PageView Facebook Pixel w zależnosci od zgody na śledzenie

    W efekcie: kolejność działań jest następująca:

    • użytkownik akceptuje zgodę,
    • tag consent update uruchamia się i pushuje event „gtm_constant_update”,
    • tag FB Pixel – PageView nasłuchuje eventu i dopiero wtedy się odpala.
    Zrzut ekranu przedstawiający uruchomione tagu PageView Facebook Pixel w Google Tag Manager
    Zrzut ekranu przedstawiający uruchomione tagu PageView Facebook Pixel w Google Tag Manager

    Dzięki temu nie zgubimy PageView i jednocześnie nie złamiemy preferencji użytkownika.

    Sprawdzenie i testowanie rozwiązań

    Poniżej podsumowująca lista kontrolna, którą warto na końcu sprawdzić:

    • Baner wyświetla się poprawnie na wszystkich typach urządzeń.
    • Domyślny stan (default) zgód to denied.
    • Wykonano testy: akceptuj wszystkie, odrzuć wszystkie, akceptuj wybrane i zmiana decyzji w trakcie sesji.
    • Po akceptacji ciasteczko consent przyjmuje wartości yes dla odpowiednich grup.
    • Tag consent update odczytuje wartości ciasteczka przez zmienne z Google Tag Manager i ustawia granted/denied.
    • Tagi Google (np. Google Analytics, Google Ads) działają z consent mode (anonimowe pingi, gdy brak zgody).
    • Tagi niegooglowskie typu wyświetlenie strony (np. Facebook PageView) odpalają się dopiero po gtm_constant_update (jeśli użytkownik zaakceptował).
    • Wszystkie zdarzenia eCommerce (add_to_cart, purchase) są wysyłane zgodnie z oczekiwaniami i state zgód.

    Użyj rozszerzeń Cookie Editor i Consent Mode Inspector do szybkiego podglądu stanu zgód i wartości ciasteczek. Sprawdzaj też DebugView w Google Analytics (tryb debugowania) dla weryfikacji wysyłanych zdarzeń.

    Zrzut ekranu przedstawiający ustawienia zgód w Consent Mode Inspector
    Zrzut ekranu przedstawiający ustawienia zgód w Consent Mode Inspector

    Publikacja kontenera i monitorowanie

    Gdy jesteś pewien, że wszystko działa poprawnie w trybie podglądu i testy przechodzą pomyślnie, opublikuj kontener Google Tag Managera.

    Zrzut ekranu przedstawiający proces przesyłania zmian w Google Tag Manager
    Zrzut ekranu przedstawiający proces przesyłania zmian w Google Tag Manager

    Po publikacji monitoruj dane w Google Analytics i narzędziach reklamowych przez kolejne dni. Sprawdź, czy modelowane dane (w GA) są zgodne z oczekiwaniami oraz czy konwersje eCommerce nadal są raportowane poprawnie.

    Podsumowanie

    Wdrożenie consent mode na stronie WordPress i integracja z Google Tag Manager to proces techniczny, który wymaga uwagi i testów. Dobre wdrożenie mechanizmu zgód to inwestycja, która minimalizuje ryzyko problemów prawnych i organizacyjnych.

    Najczęściej zadawane pytania (FAQ)

    Czy wdrożenie Consent Mode na WordPressie wymaga płatnych wtyczek typu Cookiebot?

    Nie, skuteczne wdrożenie mechanizmu zgód można zrealizować bez miesięcznych abonamentów, wykorzystując niestandardowe skrypty i GTM. Płatne narzędzia oferują wygodę, ale darmowe rozwiązania dają pełną kontrolę i oszczędność, o ile są poprawnie skonfigurowane technicznie.

    Podejmując współpracę ze mną, wdrażam dedykowane, bezpłatne rozwiązanie oparte na kodzie, które uwalnia Cię od stałych kosztów licencyjnych.

    LSI: darmowy banner cookies, wtyczki WordPress, Cookiebot alternatywa, skrypt Java Script, oszczędność budżetu

    Dlaczego wdrożenie Consent Mode v2 jest krytyczne dla analityki eCommerce?

    Bez Consent Mode Google blokuje ciasteczka reklamowe i analityczne użytkowników odrzucających zgody, co powoduje drastyczne luki w danych. Wdrożenie tego trybu pozwala na legalne przesyłanie sygnałów (pingów) bez danych osobowych, co umożliwia modelowanie brakujących konwersji.

    W ramach współpracy ze mną konfiguruję tryb Advanced, abyś odzyskiwał dane o sprzedaży dzięki modelowaniu behawioralnemu.

    LSI: Consent Mode v2, modelowanie danych, luki w analityce, RODO, utrata konwersji, pingi bez cookies

    Jak poprawnie skonfigurować tagi Consent Mode w Google Tag Manager?

    Kluczem jest rozdzielenie inicjalizacji na dwa etapy: „Default” (domyślna blokada) oraz „Update” (aktualizacja po decyzji). Błąd w kolejności ładowania tych tagów sprawia, że strona albo nie zbiera danych wcale, albo łamie prawo, uruchamiając śledzenie przed zgodą.

    Korzystając z mojej pomocy, otrzymujesz bezbłędną strukturę tagów zapewniającą zasadę „privacy by default” przy zachowaniu ciągłości danych.

    LSI: tag inicjalizacji, Consent Initialization, tag Update, privacy by default, sekwencja tagów GTM

    W jaki sposób GTM odczytuje decyzje użytkownika z niestandardowego bannera?

    GTM nie „widzi” bannera automatycznie; potrzebuje zmiennych JavaScript, które tłumaczą tekstowe wartości ciasteczka (np. „marketing:yes”) na standard zrozumiały dla Google („granted”). Bez tego „tłumacza” system nie wie, które tagi uruchomić.

    Współpracując ze mną, przygotowuję precyzyjne skrypty parsujące ciasteczka, które eliminują błędy interpretacji zgód.

    LSI: zmienne niestandardowe JS, parsowanie cookies, status granted denied, mapowanie zgód, ad_storage

    Czym różni się konfiguracja tagów Google od tagów Facebooka w kontekście zgód?

    Tagi Google (GA4, Ads) mają wbudowaną logikę Consent Mode i same dostosowują swoje zachowanie. Tagi podmiotów trzecich, jak Meta Pixel czy LinkedIn Insight Tag, nie mają tej funkcji – musisz ręcznie zablokować ich uruchomienie w GTM do momentu uzyskania konkretnej zgody.

    Podejmując współpracę ze mną, przeprowadzam audyt wszystkich tagów, aby Meta Pixel nie naruszał RODO i nie narażał Cię na kary.

    LSI: Additional Consent Checks, Meta Pixel RODO, blokowanie tagów, analityka podmiotów trzecich, ad_personalization

    Dlaczego Facebook Pixel nie zlicza PageView przy pierwszym wejściu na stronę?

    To tzw. „race condition” – tag Pixela próbuje odpalić się szybciej, niż GTM zdąży przetworzyć zgodę użytkownika. Rozwiązaniem jest opóźnienie tagu PageView i wyzwolenie go dopiero po zdarzeniu aktualizacji zgód (custom event), a nie na standardowe „All Pages”.

    W ramach współpracy ze mną tworzę szczelną sekwencję zdarzeń, która eliminuje utratę danych przy pierwszym kontakcie z marką.

    LSI: race condition, gtm_constant_update, utrata danych PageView, sekwencjonowanie zdarzeń, Data Layer push

    Jak zweryfikować, czy wdrożenie Consent Mode działa poprawnie?

    Samo zniknięcie bannera to za mało. Należy sprawdzić w konsoli developera lub trybie podglądu GTM, czy po odrzuceniu zgód statusy „ad_storage” i „analytics_storage” faktycznie zmieniają się na „denied”. Częstym błędem jest wizualna iluzja działania przy braku faktycznej blokady.

    Korzystając z mojej pomocy, otrzymujesz raport weryfikacyjny z narzędzi debugujących, potwierdzający szczelność i legalność systemu.

    LSI: debugowanie GTM, Consent Mode Inspector, weryfikacja wdrożenia, audyt analityki, statusy ciasteczek

    Czy wpis był dla Ciebie pomocny?

    Średnia ocena 5 / 5. Liczba ocen: 4

    Dodaj komentarz