Skip to content

Zgody pod kontrolą - czyli praktyczne wdrożenie Klaro

Published: at 16:22

Po co nam to całe zarządzanie zgodami?

Świat internetu dynamicznie się zmienia, a przepisy dotyczące ochrony danych, jak słynne GDPR, wymuszają na właścicielach stron internetowych transparentność w kwestii zbierania danych. Zarządzanie zgodami to już nie opcja, a konieczność. Pozwala to nie tylko uniknąć konsekwencji prawnych, ale także budować zaufanie użytkowników, którzy coraz bardziej cenią sobie prywatność w sieci

Spis treści

Rozwiń spis treści

Co to Klaro?

Klaro to narzędzie, które pomaga stronom internetowym w tym całym procesie zarządzania zgodami. Działa to tak, że gdy wchodzisz na stronę, Klaro wyświetla Ci okienko, w którym możesz zdecydować, na co się zgadzasz, a na co nie.

Pewnie widziałeś je przy pierwszej wizycie na moim blogu - możesz też otworzyć je ponownie klikając tutaj. Możesz wyrazić zgodę na wszystkie rodzaje śledzenia, odrzucić je wszystkie, albo wybrać konkretne opcje.

Klaro ułatwia stronom spełnienie wymogów GDPR i innych przepisów dotyczących prywatności, a użytkownikom daje kontrolę nad tym, jakie dane o nich są zbierane. To takie narzędzie, które pomaga zachować równowagę między potrzebami strony, a prawami użytkowników.

Jak dodać Klaro do swojej strony

Aby zintegrować Klaro ze swoją stroną internetową, potrzebujesz wykonać kilka kroków:

  1. Pobierz pliki Klaro: Możesz pobrać Klaro z oficjalnej strony lub użyć menedżera pakietów, takiego jak npm. Interesuje Cię plik .js oraz .css ze stylami.
  2. Dołącz pliki CSS i JS: W sekcji head swojej strony dodaj link do pliku css Klaro, który odpowiada za wygląd okna zgody, oraz tagi script do pliku z konfiguracją Klaro i samego skryptu. Koniecznie w tej kolejności. Przykładowo u mnie wygląda to tak:
<!-- Klaro -->
<script defer type="text/javascript" src="/klaro/config.js"></script>
<link rel="stylesheet" href="/klaro/klaro.css" />
<script defer type="text/javascript" src="/klaro/klaro-no-css.js"></script>
  1. W pliku konfiguracji np. config.js dodaj wszystkie usługi, które zbierają lub wysyłają dane Twoich użytkowników, a także ustawiają ciasteczka. W tym samym pliku ustawisz też podstawowe funkcje Klaro.

Zalecane ustawienia dla Klaro

mustConsent: true,

Wymusza okienko, które zasłania content i wymusza wybór zgody lub jej brak. Pamiętaj, że odmowa często jest lepsza niż brak jakiejkowiek zgody.

hideDeclineAll: false,

W przypadku ustawienia na false da możliwość szybkiego wyłączenia wszystkich usług. Nie traktuj moich zaleceń jako wykładni prawniczej, ale wielu ekspertów twierdzi, że użytkownik pownien mieć tak samo prostą drogę od odrzucenia, jak do akceptacji wyborów.

acceptAll: true,

Podobnie jak wyżej - tylko tym razem dajemy możliwość szybkiej akceptacji wszystkich usług.

default: false,

Stan usług przed wyrażeniem zgody. Domyślnie polecam false - czyli niekatywne usługi. Jeśli jednak chcesz je uruchomić możesz, to też zrobić indywidualnie dla każdej usługi z osobna.

// Styling with theme
  styling: {
    theme: ["dark"],
  },
  // Set Polish as default language
  lang: "pl",

Ustawienia wyglądu i domyślnego języka. Postaraj się, aby okienko nie zlewało się z resztą strony. Do dyspozycji masz również tłumaczenia usług i jęzka okienka dialogowego jeśli Twoja strona obsługuje więcej niż jeden język.

Jak ustawić prawidłowo usługi w Klaro?

Narzędzie daje nam możliwość szczegółowego ustawiania usług. Polecam zapoznanie się z przykładowym plikiem config.js od Klaro lub moją implementacją, żeby poznać szczegóły. Poniżej znajdziesz wskazówki jak wykorzystać mechanizmy Klaro, aby uruchamiać narzędzia z odpowiednim trybem zgody.

Ciasteczka

Dla każdej usługi definiujemy ciastka, które w przypadku braku zgody Klaro ma zablokować. Przykładowo dla Google Analytics zrobimy to w ten sposób:

cookies: [/^_ga/, /^_gid/, /^_gat/, /^_gtag/],

Google Analytics 4

W zależności od decyzji użytkownika będziemy uruchamiać skrypt wariantem uzależnionym od decyzji i wykorzystywać tryb consent mode od Google.

onDecline: `
        console.log("Google Analytics service has been declined by the user.");
        var gtagScript = document.createElement("script");
        gtagScript.src = "https://www.googletagmanager.com/gtag/js?id=${GA_ID}";
        document.head.appendChild(gtagScript);
        window.dataLayer = window.dataLayer || [];
        function gtag() {
        dataLayer.push(arguments);
        }
        // Najpierw ustawiamy domyślne zgody
        gtag("consent", "default", {
        ad_storage: "denied",
        ad_user_data: "denied",
        ad_personalization: "denied",
        analytics_storage: "denied",
        });
        // Następnie inicjalizujemy GA4
        gtag("js", new Date());
        gtag("config", "${GA_ID}");`,
onAccept: `
        console.log("Google Analytics service has been accepted by the user.");
        var gtagScript = document.createElement("script");
        gtagScript.src = "https://www.googletagmanager.com/gtag/js?id=${GA_ID}";
        document.head.appendChild(gtagScript);
        window.dataLayer = window.dataLayer || [];
        function gtag() {
        dataLayer.push(arguments);
        }
        // Najpierw ustawiamy domyślne zgody
        gtag("consent", "default", {
        ad_storage: "denied",
        ad_user_data: "denied",
        ad_personalization: "denied",
        analytics_storage: "granted",
        });
        // Następnie inicjalizujemy GA4
        gtag("js", new Date());
        gtag("config", "${GA_ID}");`,

Microsoft Clarity

Podobnie możemy wykozystać mechanizm zgód dostępny dla Microsoft Clarity i wywołać go z odpowiednim parametrem.

onDecline: `
        //console.log("Microsoft Clarity service has been declined by the user.");
        (function(c,l,a,r,i,t,y){
          c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
          t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
          y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
        })(window, document, "clarity", "script", "${CLARITY_ID}");
        window.clarity("consent", false);
        //console.log("Clarity consent revoked");`,
onAccept: `
        //console.log("Microsoft Clarity service has been accepted by the user.");
        (function(c,l,a,r,i,t,y){
          c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
          t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
          y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
        })(window, document, "clarity", "script", "${CLARITY_ID}");
        window.clarity("consent");
        //console.log("Clarity consent granted");`,

Czy Klaro jest zgodne z GDPR/RODO?

Klaro pozwala na zarządzanie narzędziami marketingowymi i analitycznymi, ale domyślnie brakuje mu jednej funkcji, która jest wymagana do pełnej zgodności z przepisami.

Niestety Klaro nie zapisuje nigdzie historii decyzji dotyczących zgód, więc samodzielnie nie jest narzędiem, które zapewni nam pełną zgodność.

Oczywiście mam na to swoje rozwiązanie! 🥳

Zapisuj zgody Klaro, dla pełnej zgodności GDPR/RODO

Co zrobić, aby zapisać zgody?

Potrzebujemy 3 dodatkowych elementów:

  1. Kodu, który uruchomimy na evencie zmiany uprawnień.
  2. Mechanizmu zapisu w chmurze - wykorzystamy Cloudflare Workers.
  3. Bazy danych - tu wykorzystamy D1 od Cloudflare, które pozwala nam za darmo trzymać do 5GB danych, a w razie potrzeby użyjemy komend SQL do wyszukiwania czy czyszczenia bazy.

Monitorowania zmian i wysyłka stanu zgód

Do tego potrzebne nam będzie parę dodatkowych linijek kodu, które dodamy w pliku config.js. Do identyfikacji urządzenia stworzymy sobie dodatkowe ciastko klaro-uuid, które zapiszemy u użytkownika. Dzięki temu w razie wątpliwości, jesteśmy w stanie połączyć urządzenie z zapisami w logu.

function getOrCreateKlaroUUID() {
  const existing = getCookie("klaro-uuid");
  if (existing) return existing;

  const newUUID = crypto.randomUUID();
  document.cookie = `klaro-uuid=${newUUID}; path=/; max-age=31536000; SameSite=Lax; Secure`;
  return newUUID;
}

Dalej skorzystamy z mechanizmu klaro.getManager() i zmianach zgód wyślemy informację na nasz mechanizm zapisujący.

document.addEventListener("DOMContentLoaded", function () {
  const manager = klaro.getManager();
  manager.watch({
    update: function (manager, eventType, data) {
      if (eventType === "saveConsents") {
        const { changes, consents, type } = data;
        const uuid = getOrCreateKlaroUUID();

        fetch("https://consent-logger.twojadres.workers.dev/", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            uuid,
            consents,
            page: window.location.href,
            timestamp: new Date().toISOString(),
          }),
        });
      }
    },
  });
});

Wysyłamy:

Baza D1 do przechowywania logów zgód

Tworzymy bazę danych, w której w uporządkowany sposób zapiszemy wszystkie informacje.

KolumnaTypOpis
idINTEGER✅ Klucz główny
uuidTEXT✅ Unikalny identyfikator użytkownika (generowany w ciastku klaro-uuid)
serviceTEXT✅ Nazwa usługi z konfiguracji Klaro (np. googleAnalytics, microsoftClarity)
stateINTEGER✅ Stan zgody: 1 (zaakceptowano) lub 0 (odrzucono)
pageTEXT✅ Adres strony, na której zapisano zmianę zgody
ipTEXT✅ Adres IP klienta (cf-connecting-ip)
user_agentTEXT✅ Informacja o przeglądarce / urządzeniu
created_atTEXT✅ Data i godzina w formacie ISO (YYYY-MM-DDTHH:MM:SSZ)

Gotowe? Możemy przystąpić do utworzenia workera, który zapisze nasze dane.

Połączenie D1 i workera

Kluczowa operacja, to połączenie workera z bazą danych. Po nadaniu nazwy i utworzeniu, przejdź do zakładki Settings -> Bindings -> i tam ustaw połączenie np. z nazwą DB. Tą nazwę wykorzystamy w kodzie workera.

Połączenie workera z bazą SQL

Zapis do bazy

Za pomocą prostego kodu definiujemy zasady CORS i dla requestów typu POST dokonujemy zapisów w naszej bazie. Poniżej kluczowy element.

// consents to obiekt typu: { service1: true, service2: false }
const inserts = Object.entries(consents).map(([service, state]) => {
  return env.DB.prepare(
    `
          INSERT INTO consent_logs 
            (uuid, service, state, page, ip, user_agent, created_at)
          VALUES (?, ?, ?, ?, ?, ?, ?)
        `
  ).bind(uuid, service, state ? 1 : 0, page, ip, userAgent, timestamp);
});

Całość pliku tutaj: worker.js

Finalnie w bazie wygląda to tak:

Zapis logu zgód w bazie D1 Cloudflare

A logi możemy szybko znaleźć np. przez konsolę:

SELECT *
FROM consent_logs
WHERE uuid = 'cba24d89-7b51-48a8-9b0d-51532309f9d7'
ORDER BY created_at DESC;

I to wszystko! Mamy dzięki temu pełną zgodność z przepisami dzięki zapisanej historii zgód.

Jeśli interesują Cię takie treści koniecznie zapisz się do mojego substacka, będę tam na bieżąco informował o moich nowych wpisach.

Zobacz też: Jak poprawnie obsłużyć Microsoft Clarity z Consent Magic?

Zmień ustawienia prywatności Built with Astro