Stop med at fake dit cookie-banner – byg det rigtigt første gang

Stop med at fake dit cookie-banner - byg det rigtigt første gang

Du snyder dig selv, hvis dit cookie-banner bare er pynt

De fleste små websites har et cookie-banner, der i praksis er ren teater.

Banneret popper op, men scripts og cookies fyrer løs i baggrunden, uanset om brugeren klikker “Accepter” eller bare prøver at finde krydset.

Problemet er ikke kun, at det er træls UX. Det kan også give dig reel risiko for en påtale fra Datatilsynet, hvis nogen kigger nærmere på dit site.

Det her er ikke juridisk rådgivning (tal med en jurist, hvis du skal være helt skudsikker), men jeg gennemgår, hvordan du som udvikler eller website-ejer kan bygge et teknisk fornuftigt cookie-setup, der ikke skriger “for-sjov-banner”.

Hvad betyder “uden bøde” i praksis

“Cookie-banner uden bøde” lyder lidt som clickbait, men lad os oversætte det til noget brugbart.

Risiko og ansvar, kort fortalt

Du har ansvar for de cookies, dit site sætter. Også dem fra tredjeparts scripts som Google Analytics, Facebook Pixel, YouTube embeds osv.

Når du viser et cookie-banner, forventer Datatilsynet grundlæggende tre ting:

  • At samtykke er frivilligt (ingen tvang eller snedige dark patterns)
  • At det er informeret (brugeren kan forstå, hvad de siger ja til)
  • At det er forudgående (ingen samtykkekrævende cookies før “ja”)

Hvis du fejler på især det sidste punkt, er du i risikozonen. Det er også her, de fleste tekniske fejl sker.

Typiske fejl jeg ser i kodebaser

De samme mønstre går igen:

  • Google Analytics loader i <head> som det første, uanset samtykke
  • YouTube embeds sætter tracking cookies, allerede når siden loader
  • “Accepter” er en stor farvet knap, mens “Afvis” er et gråt tekstlink begravet i hjørnet
  • Cookie-banneret kan ikke genåbnes, så brugeren reelt ikke kan ændre mening

Vi fokuserer nu på det tekniske: hvordan du undgår, at der bliver sat samtykkekrævende cookies, før brugeren rent faktisk har givet samtykke.

Hvad kræver et cookie-banner typisk for at være nogenlunde compliant

Jeg siger bevidst “nogenlunde”, for det juridiske ideal og virkeligheden på små sites matcher sjældent 100 %.

Men som tommelfingerregel bør dit banner som minimum kunne:

  • Skelne mellem nødvendige cookies og andre typer
  • Give klart valg mellem at acceptere alle, afvise alle eller vælge nogle kategorier
  • Vise en forståelig forklaring på, hvad de forskellige kategorier betyder
  • Gemme brugerens valg i en nødvendig cookie (ironisk, men lovligt)
  • Tilbyde en måde at ændre samtykke senere (f.eks. via et lille ikon eller link i footer)

Det vigtige er ikke fancy design. Det er:

  • Ingen statistik/marketing-cookies før accept
  • Nem adgang til at sige både ja, nej og “tilpas”

Cookie-kategorier forklaret: nødvendige, statistik, marketing

Hvis du vil bygge det her teknisk, skal du have en enkel mental model for kategorier.

Nødvendige cookies

Det er cookies, der skal til, for at sitet overhovedet fungerer.

Eksempler:

  • Session ID til login
  • Cookie til at huske, at brugeren er logget ind
  • Cookie til at huske, hvad der ligger i en indkøbskurv
  • Cookie til at gemme selve cookie-samtykket

Disse må du typisk sætte uden samtykke. Men beskyt dem stadig, og lad være med at smide alt muligt andet i den kategori for bekvemmelighedens skyld.

Statistik / analyse

Det er alt, der måler adfærd, sidevisninger, events osv.

Eksempler:

  • Google Analytics, Matomo, Plausible (afhængig af opsætning)
  • Heatmaps og recordings (Hotjar m.fl.)
  • Egne tracking-scripts, der gemmer bruger-id eller lignende

De kræver typisk samtykke, hvis der sættes cookies eller bruges personlig data. Der findes cookiefri analytics, men mange standardopsætninger af GA4 kræver samtykke. Tjek dokumentationen, og dobbelttjek i browserens devtools.

Marketing

Alt, hvad der handler om annoncering, retargeting eller social media-tracking.

Eksempler:

  • Facebook Pixel / Meta Pixel
  • Google Ads remarketing tags
  • LinkedIn Insight Tag
  • Tracking via embedded videoer eller widgets, der taler med tredjeparter

Her skal du regne med, at der klart skal samtykke til.

Trin-for-trin: kortlæg cookies på dit site

Før du kan bygge noget smart, skal du vide, hvad du har med at gøre.

1. Brug browserens devtools

Den hurtigste metode:

  1. Åbn dit site i Chrome
  2. Højreklik, vælg “Inspicer”
  3. Gå til fanen Application
  4. Under “Storage” vælg “Cookies” → dit domæne

Her ser du en liste over cookies, mens du klikker rundt. Du kan sortere på navn, domain osv.

2. Notér cookies og kilde

Lav en lille tabel, fx i et spreadsheet:

  • Navn (f.eks. _ga)
  • Domæne
  • Udbyder (gæt ud fra navn eller søg på det)
  • Formål (statistik, marketing, login osv.)
  • Hvor i koden sættes den? (GA-script, plugin, embed osv.)

Du kan også bruge et værktøj eller en cookie-scanner, men jeg vil anbefale mindst én manuel tur gennem devtools, så du selv ser mønstrene.

3. Marker hvad der kræver samtykke

Nu kommer beslutningen:

  • Er den teknisk nødvendig for funktion? Så i “Nødvendige”.
  • Ellers: typisk “Statistik” eller “Marketing”.

Hvis du er i tvivl om en cookie, så behandl den som samtykkekrævende, indtil en jurist har sagt andet.

Trin-for-trin: blokér tracking indtil samtykke

Nu til den del, de fleste skipper: at udsætte scripts, indtil brugeren har sagt ja.

Grundidé: scripts må ikke køre automatisk

Standardmønstret for at blokere er:

  1. Erstat <script src="..."> med en “passiv” version (f.eks. med type="text/plain" og et data-atribut)
  2. Når brugeren giver samtykke, aktiverer du de relevante scripts via JavaScript

Eksempel: simpel manual blokering

Forestil dig, at du normalt har noget i stil med:

<!-- Google Analytics (ikke korrekt endnu) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXX');
</script>

Det her loader GA uanset samtykke. I stedet kan du gøre:

<!-- Blokeret GA indtil statistik-samtykke -->
<script type="text/plain" data-cookie-category="statistik" 
        src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>

<script type="text/plain" data-cookie-category="statistik">
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}  
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXX');
</script>

Nu kører de scripts ikke automatisk, fordi browseren ignorerer type="text/plain" som kode.

Aktivér scripts når samtykke gives

Når brugeren klikker “Accepter statistik”, kan du have en lille funktion, der aktiverer de relevante scripts.

function enableScriptsForCategory(category) {
  const scripts = document.querySelectorAll(
    'script[type="text/plain"][data-cookie-category="' + category + '"]'
  );

  scripts.forEach((script) => {
    const s = document.createElement('script');

    if (script.src) {
      s.src = script.src;
      s.async = script.async;
    } else {
      s.textContent = script.textContent;
    }

    // Kopier evt. andre attributes hvis nødvendigt
    document.head.appendChild(s);
  });
}

Når dit banner registrerer samtykke, kalder du f.eks.:

enableScriptsForCategory('statistik');

Og kun dér. Ikke før.

Simple data-struktur til samtykke

Du kan gemme samtykket i en cookie eller localStorage. F.eks.:

const consentKey = 'cookieConsentV1';

function saveConsent(consent) {
  // consent: { necessary: true, statistics: true/false, marketing: true/false }
  document.cookie = `${consentKey}=${encodeURIComponent(JSON.stringify(consent))};` +
                    'path=/;max-age=' + 60*60*24*180; // 180 dage
}

function loadConsent() {
  const match = document.cookie.match(new RegExp(consentKey + '=([^;]+)'));
  if (!match) return null;
  try {
    return JSON.parse(decodeURIComponent(match[1]));
  } catch (e) {
    return null;
  }
}

På side-load kan du:

const consent = loadConsent();
if (consent) {
  if (consent.statistics) enableScriptsForCategory('statistik');
  if (consent.marketing) enableScriptsForCategory('marketing');
} else {
  // Vis banneret
}

Det er den tekniske kerne: ingen scripts fra de kategorier, der ikke har samtykke endnu.

Google Tag Manager og Consent Mode v2

Hvis du bruger Google Tag Manager (GTM), får du både en genvej og en ekstra faldgrube.

Grundbegreber

GTM har:

  • Tags (dine scripts)
  • Triggers (hvornår scripts fyres)
  • Variables (data, inkl. consent-states)

Google Consent Mode v2 giver dig mulighed for at fortælle Googles scripts, om brugeren har givet samtykke til f.eks. ad_storage og analytics_storage.

Typisk mønster med GTM + consent

Et nøgternt setup kunne være:

  1. Du loader GTM med minimalt script i <head>.
  2. Inden GTM initialiseres fuldt, sætter du default consent til “den mest restriktive”.
  3. Dit cookie-banner opdaterer consent-states via gtag('consent', ...) eller via dataLayer.
  4. Tags i GTM er konfigureret til først at fyre, når der er givet samtykke.

Eksempel på Consent Mode v2 init

I din template (før GA/GTM går amok):

<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}  

  gtag('consent', 'default', {
    'ad_storage': 'denied',
    'analytics_storage': 'denied',
    'ad_personalization': 'denied',
    'ad_user_data': 'denied'
  });
</script>

Når brugeren accepterer statistik, kan du f.eks. gøre:

gtag('consent', 'update', {
  'analytics_storage': 'granted'
});

Og for marketing:

gtag('consent', 'update', {
  'ad_storage': 'granted',
  'ad_personalization': 'granted',
  'ad_user_data': 'granted'
});

Vigtigt: dine GTM-tags skal være sat op til at respektere consent. Tjek GTM UI for consent-indstillinger for hver tag.

Hvis du vil læse mere om ansvarlig opsætning og debugging generelt, kan det være nyttigt at kombinere det med basale værktøjer som versionsstyring i Git, så du har styr på ændringer i dit tracking-setup.

Teksteksempler til dit cookie-banner

Teksten behøver ikke være poetisk. Den skal bare være klar.

Hovedtekst

Vi bruger cookies til at få siden til at virke og til at måle trafik, 
for at kunne forbedre vores indhold. Du kan sige nej til statistik 
og marketing, og siden vil stadig fungere.

Knapper

Et enkelt setup med tre valg:

  • Accepter alle
  • Afvis ikke-nødvendige
  • Vælg cookies

“Afvis” skal være lige så tydelig som “Accepter”. Ingen skjult, grå 10 px tekst i hjørnet.

Kategoribeskrivelser

Eksempler:

  • Nødvendige: “Tekniske cookies, der får siden til at fungere, f.eks. login og dine valg her i banneret. Disse kan ikke fravælges.”
  • Statistik: “Hjælper os med at forstå, hvordan siden bliver brugt, så vi kan forbedre indhold og funktioner. Vi anonymiserer så vidt muligt data.”
  • Marketing: “Bruges til at vise mere relevante annoncer og måle effekten af kampagner på tværs af hjemmesider og sociale medier.”

Du kan evt. linke til en mere detaljeret cookiepolitik, hvor du lister konkrete cookies, f.eks. via en underside bygget som andre simple sider i dit CMS. Hvis du ikke er vant til at bygge sider endnu, kan en intro til HTML-grundlæggende være en god start.

Test-checkliste: sætter du cookies før samtykke?

Det her er den del, mange springer over. Men uden test ved du reelt ikke, om du er tæt på “uden bøde” eller bare håber.

Basis-test i devtools

  1. Åbn dit site i inkognito-vindue.
  2. Åbn devtools → Application → Cookies.
  3. Reload siden, uden at interagere med banneret.

Nu tjekker du:

  • Er der kun nødvendige cookies? (login, samtykke, tekniske)
  • Eller ser du GA-cookies (_ga, _gid osv.), markedsføringscookies eller tredjepartsdomæner?

Hvis der ligger statistik/marketing-cookies allerede nu, er der noget galt i din blokering.

Test forskellige valg

Gør tre runder:

  1. Klik “Afvis” alt ikke-nødvendigt. Reload siden. Tjek cookies.
  2. Klik “Accepter kun nødvendige” / tilsvarende. Reload og tjek.
  3. Klik “Accepter alle”. Reload og tjek, at statistik/marketing nu er sat.

På runde 1 og 2 bør du kun se nødvendige cookies. På runde 3 skal du se de ekstra.

Test specifikke integrationer

Nogle steder er ekstra tricky:

  • YouTube embeds: Mange <iframe>-embeds sætter cookies, så snart de loader.
  • Sociale knapper: Facebook like/Share, LinkedIn-knapper osv.
  • Chat-widgets: Intercom, Zendesk, HubSpot m.fl.

Ofte skal du enten:

  • Bruge “nocookie”-varianter (f.eks. youtube-nocookie.com)
  • Lazy-loade embeds først, når brugeren klikker “Spil video” eller lignende
  • Pakke dem ind i samme samtykkelogik som dine andre scripts

En god teknik er at vise et placeholder-element i stedet for en rigtig video, indtil brugeren enten giver marketing-samtykke generelt eller klikker “Spil video (accepter marketing-cookies)”. Ja, det er tungere UX, men det er ærlig UX.

Sådan kan du bygge videre

Når du har et simpelt, fungerende setup, kan du udvide i små skridt.

Idéer til næste niveau

  • Lav en lille “Cookie-indstillinger”-komponent i din footer, der åbner banneret igen
  • Versionér dit consent-schema (f.eks. cookieConsentV2), når du tilføjer nye kategorier
  • Lav en lille debug-visning i dev env, hvor du kan se current consent-state live
  • Saml al cookie- og samtykkelogik i én modul-fil i din kodebase, så du ikke skal rode i templates hver gang

Hvis du arbejder mere struktureret med frontend, kan du kombinere det med komponent-baserede frameworks og generel JavaScript-arkitektur, så dit cookie-setup føles som en naturlig del af resten af koden.

Afslutning

Et cookie-banner “uden bøde” handler i høj grad om én ting: at du faktisk tager brugerens valg alvorligt i din kode.

Ikke med et ekstra lag tekst og grafik, men med reelt betingede scripts, der venter på samtykke, før de kører.

Hvis dit banner bare er pynt oven på uændret tracking-kode, er det ærligt talt mere uærligt end slet ikke at have et banner.

Load ikke scripts direkte i head eller som inline kode. Brug en container eller data-attributter som placeholder og indsæt script-tagget dynamisk først når brugeren accepterer, eller brug en tag-manager med indbygget samtykkestyring; sørg for også at forhindre inline initialiseringer og callback-funktioner indtil samtykke foreligger.
Identificer og slet de cookies programmatisk når brugeren afviser eller nulstiller samtykke, og forhindre samtidig at de samme scripts genopretter dem uden nyt samtykke. Vær opmærksom på, at data allerede sendt til tredjepart ofte ikke kan trækkes tilbage, så dokumenter og log hvad der er sket til revision.
Brug browserens devtools til at overvåge Storage og Network ved kold load og i inkognito, og opsæt automatiserede tests med værktøjer som Puppeteer eller Cypress der tjekker for fravær af tracking-requests. Gem testresultater eller screenshots som dokumentation, og gentag test ved deploy og efter ændringer i tredjeparts-scripts.
Erstat direkte embeds med en klik-til-aktiver placeholder eller brug privacy-enhanced indstillinger (fx youtube-nocookie) og kun indlæs det faktiske iframe efter samtykke. På den måde undgår du at tredjepart sætter cookies når siden loader, samtidig med at brugeren selv vælger at aktivere indholdet.

Sara Vestergaard er selvlært kode-nørd, der stille og roligt er gået fra at rode med en enkelt HTML-side til at bygge små værktøjer, scripts og hjemmesider til sig selv og vennerne. Hun startede med at lave en simpel band-hjemmeside som teenager og opdagede, hvor tilfredsstillende det er, når noget, du har skrevet, pludselig lever på skærmen.

For Sara handler kodning ikke om store ord eller imponerende titler, men om meget konkrete problemer: den kedelige opgave, der tager for lang tid, den ven der mangler en lille porteføljeside, eller den liste, der burde sortere sig selv. Hun elsker at pille ting fra hinanden – også kode – for at se, hvad der egentlig foregår, og hun har brugt utallige aftener på at google fejlbeskeder, teste små eksempler og langsomt bygge sin forståelse op.

På Coding Class deler hun den tilgang videre. Hun skriver til dig, der gerne vil lære at kode ved at gøre det i praksis: små projekter, korte kodebidder og forklaringer, der hænger sammen med det, du faktisk sidder med på skærmen. Hun skærer ind til benet, viser typiske fejl og deres løsninger og giver altid et forslag til, hvordan du kan bygge en tand videre, når grundideen først virker.

Når hun ikke skriver til Coding Class eller nørkler med nye små projekter, hænger Sara på klatrevæggen, vander sine altanplanter eller spiller gamle Nintendo-spil. Men hun ender næsten altid tilbage ved tasterne – for der er altid endnu en lille ting, der kunne være smartere, hurtigere eller bare lidt sjovere at bruge.

Send kommentar

You May Have Missed