Topics

Wie ich ein GDPR-konformes Cookie-Consent-Management (CMP) selbst entwickelt habe

  • column

Vor Kurzem haben wir zur Einhaltung von DSGVO und ePrivacy ein schlankes, eigenes CMP (Consent-Management-Tool) entwickelt. Normalerweise greift man hier zu einem SaaS-Produkt. In diesem Beitrag erläutern wir, warum wir es selbst gebaut haben und wie wir dabei vorgegangen sind.

Cookie-Einwilligungen sind für Websites, die sich an internationale Zielgruppen richten, mittlerweile unumgänglich. Die DSGVO der EU ist das bekannteste Beispiel, doch auch in den USA nimmt die Zahl der bundesstaatlichen Datenschutzgesetze von Jahr zu Jahr zu. Das Messen und Ausspielen von Werbe-Tags ohne vorherige Einwilligung ist daher nicht mehr selbstverständlich.

In der EU ist es aufgrund der DSGVO und der ePrivacy-Richtlinie untersagt, nicht notwendige Cookies wie Google Analytics 4 oder Google Ads zu setzen oder Nutzungsdaten an Dritte zu übermitteln, bevor eine Einwilligung vorliegt. Ein Banner, das ein "Schließen" als Zustimmung wertet, ist ebenso unzulässig wie ein Widerruf, der deutlich umständlicher ist als die Zustimmung.

Diese Regelungen gelten auch für Anbieter außerhalb der EU, sofern sie Dienste gezielt an Personen in der EU richten oder deren Verhalten beobachten. Japanische Websites, die eine englische Version anbieten, international Dienste bereitstellen oder Remarketing-Anzeigen schalten, können also betroffen sein, selbst wenn sie keine Niederlassung in der EU haben.

Hinzu kommen Anforderungen von Google. Für Google-Werbefunktionen bei Besuchern aus der EU ist die Unterstützung von Consent Mode v2 zwingend erforderlich. Werden die Einwilligungsstatus nicht korrekt an Google übermittelt, funktionieren Messung und Remarketing nicht. In Japan verpflichtet zudem die Änderung des Telekommunikationsunternehmensgesetzes von 2023 zur Regelung der "externen Übermittlung" dazu, offenzulegen, welche Informationen an welche Dienste gesendet werden.

Benötigt wird also ein System, das die folgenden drei Anforderungen gleichzeitig erfüllt:

  1. Ermittlung des Standorts der Besucher; in der EU und vergleichbaren Regionen werden bis zur Einwilligung keinerlei Tags aktiviert
  2. Korrekte Übermittlung des Einwilligungsstatus an Google Consent Mode sowie eine jederzeit verfügbare Möglichkeit zum Widerruf
  3. Veröffentlichung einer Übersicht (Richtlinie) über externe Empfänger und Cookies, die dauerhaft mit der tatsächlichen Datenübertragung übereinstimmt

Warum wir kein fertiges Consent-Management-Tool eingesetzt haben

Die Gründe sind drei.

  • Konflikte bei den Tags.
    Wir wollten vermeiden, dass ein externes Consent-Management-Skript mit GTM, Werbe-Tags und SPA-Navigation kollidiert und dadurch sogar Conversions von Nutzern verloren gehen, die bereits zugestimmt haben
  • Die zu steuernden Tags sind fest definiert.
    Unsere Messung und Werbung basiert nahezu vollständig auf Google-Diensten (GTM / GA4 / Google Ads). Da feststeht, welche Tags zu steuern sind, braucht es nicht die Komplexität eines universellen Tools
  • Passt zu unseren Stärken.
    Frontend-Implementierung und Accessibility gehören zu unseren Kernkompetenzen. Eine schlanke, prüfbare Lösung selbst zu entwickeln, deckt genau die benötigten Funktionen ab

Grundsatz: In Japan Hinweis, international zunächst abgelehnt

So haben wir das Verhalten je nach Region festgelegt.

Besucher

Ausgangszustand

Anzeige

Google-Tag

Aus Japan

Erlauben

Kein Banner

Wie gewohnt starten

Außerhalb Japans

Ablehnen

Banner am unteren Bildschirmrand (Alle erlauben / Alle ablehnen / Details). Nach der Auswahl erscheint eine schwebende Schaltfläche für die Einstellungen

Nur nach Zustimmung starten

Nicht bestimmbar

Ablehnen

Wie international

Nur nach Zustimmung starten

GPC-Signal vorhanden

Nur Werbung ablehnen

Grund für die Ablehnung von Werbung anzeigen

Werbenutzung eingestellt

In Japan setzen wir gemäß den Vorgaben zur "externen Übermittlung" grundsätzlich auf Benachrichtigung und Veröffentlichung; ein Banner wird nicht angezeigt. Im Ausland lehnen wir die Voreinstellung einheitlich ab, sowohl für die EU als auch für die USA. Viele US-Bundesstaatengesetze basieren auf einem Opt-out-Modell, weshalb dieser Ansatz teilweise strenger ausfällt. Wir haben uns jedoch für die sicherere Lösung entschieden, um den Betrieb zu vereinfachen.

Auch nicht eindeutig bestimmbare Fälle lehnen wir ab, nach dem gleichen Prinzip. Im Zweifel gilt: Tags werden nicht ausgelöst. Dieses Grundprinzip zieht sich durch das gesamte Design; auch das weiter unten beschriebene Verhalten bei fehlgeschlagenem Laden folgt genau dieser Linie.

Widerruf so einfach wie die Zustimmung gestalten

Die DSGVO verlangt, dass ein Widerruf der Einwilligung genauso einfach möglich ist wie die Erteilung. Wenn Nutzer im Banner mit zwei Klicks zustimmen können, der Widerruf aber nur über tief versteckte Richtlinienseiten möglich ist, entspricht das nicht diesem Grundsatz.

Die Schaltfläche "Cookie-Einstellungen", die den Einstellungsdialog öffnet, platzieren wir unabhängig von der Region im Abschnitt "Änderung und Widerruf der Einwilligung" auf der Richtlinienseite. Im Ausland wird zusätzlich nach der Auswahl im Banner dauerhaft unten links eine schwebende Einstellungsschaltfläche eingeblendet, sodass Nutzer von jeder Seite aus ändern oder widerrufen können. In Japan wird grundsätzlich kein Banner angezeigt; daher gibt es dort auch keine schwebende Schaltfläche, sondern nur die Schaltfläche auf der Richtlinienseite. Je nach Projekt lässt sich dies auf "auch in Japan anzeigen" oder "nicht anzeigen" umstellen.

Wenn Sie widerrufen, werden die im Verzeichnis aufgeführten Google-Cookies gelöscht und künftige Übermittlungen beendet.

Aufbau: 3 Teile

[Edge]  Cloudflare Worker が request.cf.country を見て
        <html data-lcmp-region="jp|overseas"> を HTML に注入
[HTML]  <head> 先頭の同期スクリプト(loader.js)が
        地域・保存済みの選択・GPC から gtag('consent','default') を確定
        → 日本 or 有効な同意あり → GTM を読む
        → それ以外 → GTM を読まず、バナー UI を遅延読み込み
[UI]    選択 → 検証・保存 → gtag('consent','update') → GTM を読み込む(何度呼ばれても挿入は1回だけ)
[GTM]   各タグ側の「追加の同意チェック」で最終ガード
  1. Regionserkennung ― Das Land wird am Edge ermittelt und im HTML markiert
  2. Einwilligungsskript ― Anhand der Markierung und der gespeicherten Auswahl wird entschieden, ob das Banner angezeigt und GTM gestartet wird
  3. Verzeichnis ― Liste der eingesetzten externen Dienste und Cookies. Grundlage der Richtlinientabelle und der Daten, die beim Widerruf gelöscht werden

① Die Regionserkennung markiert das HTML am Edge

Die Landeserkennung ließe sich mit request.cf.country von Cloudflare erledigen. Entscheidend war jedoch, wo sie eingesetzt wird.

Wenn die Prüfung auf der Browserseite über eine Entscheidungs-API erfolgt (dieser Ansatz wird bei großen internationalen Tools häufig verwendet), ist die Region erst bekannt, sobald die Antwort eintrifft. Dadurch wird auch japanischen Besuchern kurzzeitig eine Ablehnung angezeigt. Deshalb haben wir uns für einen anderen Ansatz entschieden: Am Edge wird das HTML umgeschrieben und in das <html>-Element die Regionsangabe als Attribut eingefügt. Mit HTMLRewriter wird lediglich data-lcmp-region="jp" ergänzt, sodass das Skript die Region synchron auslesen kann.

// dist/_worker.js/index.js(サイト側の post-build で生成)
import inner from './astro-entry.js';
import { wrapWorker } from './lg-region-wrap.js';
export default wrapWorker(inner);

Unsere Website basiert auf Astro mit @astrojs/cloudflare, dabei gab es einige Stolpersteine. In dieser Konfiguration erzeugt der Adapter _worker.js, wodurch das Verzeichnis functions/ ignoriert wird. Zudem durchlaufen vorab gerenderte Seiten die Middleware von Astro nicht. Letztlich haben wir den Einstiegspunkt des nach dem Build erzeugten Workers mit einem Wrapper umschlossen und die Logik so eingefügt.

Keine Unterscheidung nach Sprache

Wir haben auch überlegt, dies über <html lang>Accept-Language oder navigator.language zu erkennen. Wenn sich ein Nutzer mit Wohnsitz in der EU jedoch die japanische Seite ansieht und fälschlicherweise als jp eingestuft wird, würde das Tag ohne Einwilligung ausgeführt, was einen gefährlichen Fehler darstellt.

Für Projekte, in denen sich serverseitig keine Prüfung einschalten lässt (etwa bei AWS oder Mietservern, bei denen das DNS nicht auf Cloudflare zeigt), stellen wir eine Methode bereit, bei der eine IP-Adresse an unseren eigenen Prüfendpunkt gesendet wird. Dies entspricht dem Ansatz gängiger Consent-Management-Tools, bei dem die Prüfung über eine API des Anbieters erfolgt. Die IP-Adresse wird nur zur Prüfung verwendet; weder IP-Adresse noch Ländercode werden gespeichert. Die Antwort besteht lediglich aus zwei Werten: jp oder overseas. Als letzte Option gibt es außerdem einen Modus, der anhand der Zeitzone des Geräts schätzt (Asia/Tokyo gilt als Japan).

Welche Methode zur Prüfung verwendet wird, legen Sie pro Website in den Einstellungen fest. Unabhängig von dieser Einstellung prüft das Skript jedoch zuerst die Informationen, die sich synchron ermitteln lassen.

  1. Region-Attribut im HTML (immer vorrangig, sofern eine Edge-Prüfung vorhanden ist)
  2. Region im Cookie (für Setups, in denen das HTML nicht umgeschrieben werden kann und der Server das Prüfergebnis per Cookie übergibt)
  3. Nur wenn weder 1 noch 2 vorhanden sind, erfolgt die Prüfung über die in den Einstellungen gewählte Methode (IP-Prüf-API oder Zeitzone).
  4. Lässt sich auch dann nichts ermitteln, wird als Ausland behandelt** (**sicherheitsorientierter Standard).

Dass Attribut und Cookie stets Vorrang haben, dient dazu, später nur durch eine Einstellungsänderung auf eine Edge-Prüfung umstellen zu können. Läuft die IP-Prüf-API in ein Timeout, wird lediglich als Ausland behandelt; Tags werden dadurch niemals ohne Einwilligung ausgeführt.

② Vor der Einwilligung wird nicht "blockiert", sondern gar nicht erst geladen

Googles Consent Mode kennt zwei Varianten: Advanced, bei dem der GTM zuerst geladen wird und nur ein "Ablehnen"-Signal sendet, und Basic, bei dem der GTM selbst erst nach der Einwilligung geladen wird. Hier wird Basic verwendet. Wenn vor der Einwilligung nur das Consent-Skript den GTM lädt, vereinfacht sich der gesamte Aufbau erheblich.

  • Selbst wenn ein Skript nicht geladen werden kann, startet der GTM-Container keine nicht notwendigen Tags, da niemand mehr die Anweisungen des GTM liest.
  • Das GTM-Snippet wird nicht direkt in das HTML geschrieben. Ebenso wird keine Variante gewählt, bei der es als benutzerdefiniertes HTML-Tag im GTM ausgeliefert wird, da der GTM sonst vor der Einwilligung gelesen würde.
  • Zusätzlich wird auch im GTM bei jedem Tag die Option „Nur auslösen, wenn Einwilligung für Analyse/Werbung vorliegt“ aktiviert, sodass der Schutz doppelt greift.

„Vor der Einwilligung: 0 Verbindungen, 0 Cookies“ wird in E2E-Tests auf Netzwerkebene überprüft.

const FORBIDDEN_BEFORE_CONSENT = [
  '**googletagmanager.com/**', '**google-analytics.com/**',
  '**googleadservices.com/**', '**doubleclick.net/**', // …
];

test('T02: overseas first visit sends nothing', async ({ page }) => {
  const hits: string[] = [];
  await page.route('**/*', route => {
    if (FORBIDDEN_BEFORE_CONSENT.some(p => matchGlob(p, route.request().url()))) hits.push(route.request().url());
    return route.continue();
  });
  await page.goto('/');
  await expect(page.getByRole('region', { name: /cookie/i })).toBeVisible();
  expect(hits).toEqual([]);                          // 通信 0 件
  expect(await page.context().cookies()).toEqual([]); // Cookie 0 件
});

Beim Widerruf werden ausschließlich die im Verzeichnis erfassten bekannten Cookies gelöscht. Es werden keine Wildcard-Löschungen durchgeführt. Da nur bekannte Cookies entfernt werden, schlägt das Löschen fehl, wenn Domain oder Pfad im Verzeichnis nicht mit der Realität übereinstimmen. Dass Tests fehlschlagen, sobald das Verzeichnis nicht korrekt ist, trägt dazu bei, dass die Cookie-Richtlinie und die tatsächliche Kommunikation dauerhaft übereinstimmen.

③ Einbettungen außerhalb des GTM (YouTube, Karten, Webfonts)

Mit dem Stoppen des GTM war es nicht getan. YouTube- und Google-Maps-iframes sowie Webfonts, die nicht selbst gehostet werden können, werden am GTM vorbei direkt von der Seite geladen und setzen vor der Einwilligung Cookies.

Dafür wurde ein Ansatz gewählt, bei dem im HTML an einer Stelle ein Attribut angepasst wird.

<iframe data-lcmp-src="<https://www.youtube-nocookie.com/embed/ID>" data-lcmp-service="youtube" width="560" height="315"></iframe>

Vor der Einwilligung wird ein Platzhalter angezeigt, der aus den Werten des Verzeichnisses erzeugt wird („Dieser Inhalt wird von YouTube geladen; IP-Adresse und Informationen zur Nutzung werden an den Anbieter übermittelt.“ + Schaltflächen „Nur dieses Mal anzeigen“ / „Immer anzeigen“). Nach der Freigabe wird der eigentliche Inhalt geladen.

Eine „automatische Blockierung“, die das DOM überwacht und Ladevorgänge vor dem Laden umschreibt, wurde nicht eingesetzt. Sie führt zwangsläufig zu verpassten Ladevorgängen und Darstellungsfehlern, und auch bei Produkten von Drittanbietern gibt es dafür keine Funktionsgarantie. Das Anpassen eines Attributs am iframe an einer Stelle ist etwas mehr Aufwand, funktioniert aber zuverlässig.

Auch Webfonts lassen sich nach demselben Prinzip blockieren. <link rel="stylesheet">Ändern Sie lediglich das href in data-lcmp-href. Vor der Einwilligung wird die CSS-Datei der Schriftarten nicht geladen; nach der Zustimmung erfolgt das Laden. Der Loader wird synchron über <head>MutationObserver ausgeführt und verarbeitet neu hinzugefügte Elemente sofort. Ist die Einwilligung bereits erteilt, wird <link> direkt nach dem Einfügen durch den Parser wieder zu href umgewandelt. Der Zeitpunkt des Schriftladens ändert sich dadurch kaum gegenüber dem bisherigen Verhalten.

<link rel="stylesheet" data-lcmp-href="<https://fonts.googleapis.com/css2?family=…>" data-lcmp-service="google-fonts">

Mit einer Einwilligungspflicht werden Schriftarten bei Erstbesuchen aus dem Ausland nicht geladen, und die Seite wird mit Systemschriften angezeigt. Wenn Sie das vermeiden möchten, ist das Self-Hosting der Schriftdateien auf Ihrem eigenen Server die richtige Lösung. Dabei entfällt die externe Übertragung vollständig, und die Frage stellt sich nicht mehr.

Einzufügen ist eine Zeile, 8 KB

Voraussetzung ist, dass Messung und Werbetags über den GTM laufen. Websites, die den GTM nicht verwenden, lassen sich so nicht ohne Weiteres einbinden. Die Tags müssen zuerst in den GTM überführt werden.

Auf Seiten der Implementierung genügt es, <head>ein synchrones Skript am Anfang des einzufügen.

<script src="<https://cdn.liberogic.jp/lcmp/><siteId>/loader.js"></script>

Die Größe von loader.js beträgt gzip-komprimiert etwa 8 KB. Die UI für Banner und Dialoge liegt in einem separaten Chunk und wird erst bei Bedarf nachgeladen.

Außerdem gibt es für das Einfügen von gtm.js eine Option „nach LCP + einige Sekunden“. Wird sie aktiviert, werden Besucher, die die Seite vor dem Einfügen verlassen, nicht gemessen. Dafür fällt der Einfluss auf den Lighthouse-Score geringer aus.

Veröffentlichung pro Website und Verwaltungsoberfläche

Die Einstellungen (Register, GTM-ID, Texte, Theme) werden bei der Veröffentlichung in das Bundle eingebettet und über das CDN ausgeliefert. Zur Laufzeit wird keine Konfigurations-JSON abgerufen. Damit werden die Anforderungen „Initialisierung synchron, ohne Kommunikation“ und „keine externe Injektion beliebiger Konfigurationen“ gleichzeitig erfüllt. Eine Änderung der Einstellungen bedeutet daher eine neue Veröffentlichung und Auslieferung. Jede Veröffentlichung wird versioniert, sodass bei Problemen auf die vorherige Version zurückgewechselt werden kann.

Das Veröffentlichungspaket enthält loader.js und ui.js sowie ein Snippet zum direkten Einfügen, eine Installationsanleitung und eine GTM-Container-Vorlage (JSON zum Import) mit bereits konfigurierter Einwilligungsprüfung. Damit wird das Risiko verringert, dass im Ziel-GTM Tags ohne Einwilligungsprüfung verbleiben.

Mit dem Admin-Bereich können auch Nicht-Entwickler diese Veröffentlichung durchführen. Die wichtigsten Funktionen im Überblick:

  • Trennung von Entwurf und Veröffentlichung.
    Das Register ist eine rechtliche Erklärung zur Datenübermittlung an externe Dienste jeder Website. Daher wird eine Bearbeitung nicht sofort übernommen. Vor der Veröffentlichung zeigt das System eine Änderungsliste auf Japanisch mit den Unterschieden zur aktuell veröffentlichten Konfiguration. Wurde das Register geändert, das Datum der Richtlinienaktualisierung aber nicht, erscheint eine Warnung. Über den Veröffentlichungsverlauf lässt sich die vorherige Version mit einem Klick wiederherstellen.
  • Katalog häufig verwendeter Dienste.
    Dienste wie GA4, Google Ads, Clarity, YouTube und reCAPTCHA, die auf inländischen Websites häufig vorkommen, lassen sich mit Name, Anbieter, Zweck und standardisierten Cookie-Informationen in das Register aufnehmen. Die Kategorien sind Vorschlagswerte; die endgültige Entscheidung trifft ein Mensch.
  • Automatischer Cookie-Scan.
    Zielseiten werden in einem echten Browser in zwei Zuständen geöffnet, vor der Einwilligung und nach Zustimmung zu allen Optionen. Die gesetzten Cookies und Kommunikationsziele werden mit dem Register abgeglichen. Was bereits vor der Einwilligung ausgelöst wird, ist als „kritisch“ markiert, was nicht im Register steht, als „Hinweis“. Jeder Befund lässt sich mit einem Klick in das Register übernehmen.
  • Automatische Darstellung der Richtlinientabelle.
    Auf der Richtlinienseite genügt ein . Die Tabelle wird von loader.js aus dem eingebetteten Register erzeugt, sodass Richtlinie und tatsächlich gesteuerte Dienste nicht auseinanderlaufen.
  • Themenbearbeitung.
    Farben von Banner, Dialog und schwebendem Button lassen sich mit Live-Vorschau anpassen. Textfarben werden auf ein Kontrastverhältnis von mindestens 4,5:1 geprüft, Nicht-Textelemente wie Button-Rahmen auf 3:1. Liegt ein Wert darunter, erscheint sofort eine Warnung.

Fazit

Consent-Management funktioniert nicht allein mit einem Banner. Erst das Zusammenspiel aus regionaler Erkennung, Tag-Steuerung, Veröffentlichung der Richtlinie und einfachem Widerruf ergibt ein funktionierendes Ganzes. Wir haben dies in einem externen Skript und einem Register gebündelt. Wird das Register angepasst, ändern sich Banner-Text, Richtlinientabelle und die beim Widerruf zu löschenden Cookies gleichzeitig, sodass keine Abweichungen entstehen können.

Websites, die über Werbung Einnahmen erzielen, etwa mit AdSense, benötigen für Werbung im EU-Raum ein von Google zertifiziertes CMP und fallen daher nicht in den Anwendungsbereich dieser Lösung. Für gewöhnliche Websites ist sie jedoch ausreichend. Für Seiten, bei denen die verwendeten Tags feststehen und die Einwilligungsmechanismen selbst geprüft werden sollen, ist dies meiner Einschätzung nach eine übersichtlichere Alternative zu einem fertigen Tool.

Über den Autor

Vom DTP in die Webwelt: Heute beherrscht er Markup, Frontend, Projektleitung und Barrierefreiheit gleichermaßen – ein wahrer "Techniker-Guru". Seit den Anfängen von Liberogic vielseitig im Einsatz und heute eine lebende Enzyklopädie im Team. Derzeit tüftelt er mit großer Begeisterung an effizienteren Abläufen durch gezielte Prompts – etwa mit der Frage: "Können wir bei der Barrierefreiheit nicht mehr auf KI setzen?" Technik und Denkweise entwickeln sich weiter.

Ayumu Futamata

IAAP-zertifizierter Web Accessibility Specialist (WAS) / Markup-Entwickler / Frontend-Entwickler / Webdirektor

Artikel dieses Teammitglieds ansehen

Verlässliches Team und schnelle Reaktionsfähigkeit sind unsere Stärken

Bei Liberogic werden wir von unseren Kunden hoch geschätzt, da unsere erfahrenen Mitarbeiter Projekte proaktiv vorantreiben.
Wir achten darauf, Projektmanager und Direktoren gezielt einzusetzen, damit das gesamte Projekt reibungslos verläuft. Um unnötige Kostensteigerungen durch Vollzeitbindung zu vermeiden, verteilen wir Ressourcen passgenau. Zudem sind wir für unsere Geschwindigkeit bekannt, vom Verständnis der Anforderungen bis zur Erstellung und Einreichung von Angeboten.

Hinweis: Wir bieten keine SES-typischen Vor-Ort-Einsätze an. Wir bitten um Ihr Verständnis.

Sie können nahezu alle gängigen Tools für Projektmanagement und Chat nutzen, darunter Slack, Teams, Redmine, Backlog, Asana, Jira, Notion, Google Workspace, Zoom, Webex und viele weitere.

Stehen Sie bei großen Projekten mit SES oder Offshore-Teams vor technischen Herausforderungen oder Fragen zum Vorgehen?

Fallstudien