Zurück zum Blog

Privacy-First Analytics zu einer SvelteKit-App hinzufügen

SvelteKit 2 behandelt clientseitige Navigation anders als andere Frameworks. Hier ist das richtige Muster zum Tracken von Routenwechseln ohne Cookies oder Cookie-Banner.

SvelteKit 2 hat die meisten bestehenden Analytics-Integrationen still und leise gebrochen. Ein einfaches <script>-Tag, das in SvelteKit 1 einwandfrei funktionierte, feuert in SvelteKit 2 nur noch bei vollständigen Seitenladevorgängen — jede clientseitige Navigation wird verpasst. Der übliche Workaround — history.pushState zu patchen — funktioniert ebenfalls nicht, weil SvelteKit die Navigation auf Router-Ebene abfängt, bevor pushState aufgerufen wird. Der Monoid Tracker handhabt das von Haus aus korrekt.

Warum der übliche Ansatz scheitert

Traditionelle Analytics-Skripte erkennen Routenwechsel durch Monkey-Patching von history.pushState und history.replaceState. Der SvelteKit-Router ruft eigene interne Navigationsprimitive auf und ruft pushState nur als Nebeneffekt auf, nachdem der Routenübergang bereits läuft. Wenn der gepatchte pushState feuert, ist die neue Route möglicherweise noch nicht vollständig gerendert — bei bestimmten Navigationstypen (programmatische goto()-Aufrufe, <a>-Klicks mit Prefetching) entstehen dadurch Duplikate oder verpasste Ereignisse.

Das ist die eigentliche Ursache des weitverbreiteten Problems, bei dem Google Analytics GA4 in SvelteKit-2-Anwendungen beim ersten Laden nur den initialen Pageview aufzeichnet.

Der richtige Ansatz

Fügen Sie das Monoid-Tracker-Skript einmalig in Ihr Root-+layout.svelte über <svelte:head> ein:

<svelte:head>
  <script
    async
    src="https://api.monoid.website/tracker.min.js"
    data-site-id="IHRE_SITE_ID"
  ></script>
</svelte:head>

Der eingebaute DOMContentLoaded-Listener des Trackers feuert beim initialen Seitenladen. Für nachfolgende clientseitige Navigationen feuert der history.pushState-Hook des Trackers, nachdem die interne Navigation von SvelteKit abgeschlossen ist — jede Route, einschließlich der ersten, wird dadurch genau einmal getrackt, ohne Duplikate oder verpasste Ereignisse.

Zur Überprüfung öffnen Sie den Netzwerk-Tab in den DevTools und beobachten POST-Anfragen an /collect. Sie sollten eine pro Routenwechsel sehen.

Staging-Traffic trennen

SvelteKit-Projekte laufen während der Entwicklung typischerweise auf localhost. Registrieren Sie eine separate Site und binden Sie deren site_id an eine Umgebungsvariable, damit Entwicklungs-Traffic niemals die Produktionsmetriken verunreinigt:

<script>
  const siteId = import.meta.env.VITE_MONOID_SITE_ID
</script>

<svelte:head>
  {#if siteId}
    <script
      async
      src="https://api.monoid.website/tracker.min.js"
      data-site-id={siteId}
    ></script>
  {/if}
</svelte:head>

Setzen Sie VITE_MONOID_SITE_ID in .env.local für die Entwicklung (oder lassen Sie es leer, um Tracking zu unterdrücken) und in Ihrer Produktionsumgebung. Der {#if siteId}-Block stellt sicher, dass das Tracker-Skript nie eingefügt wird, wenn die Variable nicht gesetzt ist.

Was Sie nicht brauchen

Kein Cookie-Consent-Banner. Keine Aktualisierung der Cookie-Richtlinie. Keine navigator.cookieEnabled-Prüfung. Der Erfassungsendpunkt leitet einen täglichen Besucher-Hash aus IP-Adresse, User-Agent, einem serverseitigen Geheimnis und dem aktuellen Datum ab:

visitor_hash = SHA-256(IP + UA + SALT_SECRET + YYYY-MM-DD)

Der Hash wird alle 24 Stunden zurückgesetzt und kann nicht rückgängig gemacht werden, um IP oder User-Agent wiederherzustellen. Auf dem Gerät des Besuchers wird nichts gespeichert. Damit löst die Integration keine ePrivacy- oder TTDSG-Einwilligungspflichten aus — es gibt schlicht nichts, dem man zustimmen müsste.

Überprüfung im Dashboard

Nach dem Deployment öffnen Sie Ihr Analytics-Dashboard und navigieren zwischen mehreren Routen auf Ihrer Live-Site. Jede Navigation sollte einen neuen Pageview-Eintrag mit dem korrekten Pfad erzeugen. Wenn Sie unabhängig von der Navigation nur einen Eintrag sehen, prüfen Sie, ob das Skript im Root-Layout geladen wird und ob VITE_MONOID_SITE_ID in der Produktionsumgebung gesetzt ist.

Der SvelteKit-Adapter, den Sie verwenden (Cloudflare, Vercel, Node, statisch), hat keinen Einfluss auf die Analytics-Erfassung, da das Tracking vollständig im Browser nach der Hydration stattfindet.