Ajouter des Analytics Respectueux de la Vie Privée à une App SvelteKit
SvelteKit 2 intercepte la navigation côté client différemment des autres frameworks. Voici le bon pattern pour suivre les changements de route sans cookies ni bannière de consentement.
SvelteKit 2 a silencieusement cassé la plupart des intégrations d'analytics existantes. Une balise <script> simple qui fonctionnait parfaitement dans SvelteKit 1 ne se déclenche plus que lors des rechargements complets dans SvelteKit 2, manquant toute navigation côté client. Le correctif habituel — intercepter history.pushState — ne fonctionne pas non plus, car SvelteKit intercepte la navigation au niveau du routeur avant que pushState soit appelé. Le tracker Monoid gère cela correctement sans aucune configuration supplémentaire.
Pourquoi l'approche habituelle échoue
Les scripts d'analytics traditionnels détectent les changements de route en appliquant du monkey-patching sur history.pushState et history.replaceState. Le routeur de SvelteKit appelle ses propres primitives de navigation internes et n'invoque pushState qu'en tant qu'effet secondaire, après que la transition de route est déjà en cours. Au moment où le pushState patchlé se déclenche, la nouvelle route peut ne pas encore être entièrement rendue, et dans certains types de navigation (appels programmatiques à goto(), clics sur <a> avec préchargement) le timing produit des doublons ou des événements manqués.
C'est la cause profonde du problème largement signalé où Google Analytics GA4 n'enregistre que le premier pageview au chargement initial dans les applications SvelteKit 2.
L'approche correcte
Ajoutez le script du tracker Monoid une seule fois dans votre +layout.svelte racine via <svelte:head> :
<svelte:head>
<script
async
src="https://api.monoid.website/tracker.min.js"
data-site-id="VOTRE_SITE_ID"
></script>
</svelte:head>
Le listener DOMContentLoaded intégré du tracker se déclenche au chargement initial de la page. Pour les navigations côté client suivantes, le hook history.pushState du tracker se déclenche après que la navigation interne de SvelteKit est résolue — ce qui signifie que chaque route, y compris la première, est enregistrée exactement une fois, sans doublons ni événements manqués.
Pour vérifier, ouvrez l'onglet Réseau dans DevTools et surveillez les requêtes POST vers /collect. Vous devriez en voir une par changement de route.
Séparer le trafic de staging
Les projets SvelteKit tournent généralement sur localhost en développement. Enregistrez un site séparé et associez son site_id à une variable d'environnement pour que le trafic de développement ne pollue jamais les métriques de production :
<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>
Définissez VITE_MONOID_SITE_ID dans .env.local pour le développement (ou laissez-le non défini pour supprimer le tracking) et dans votre environnement de déploiement pour la production. Le bloc {#if siteId} garantit que le tracker n'est jamais injecté lorsque la variable n'est pas définie.
Ce dont vous n'avez pas besoin
Pas de bannière de consentement aux cookies. Pas de mise à jour de la politique de cookies. Pas de vérification navigator.cookieEnabled. Le point de collecte dérive un hash de visiteur quotidien à partir de l'adresse IP, du User-Agent, d'un secret côté serveur et de la date du jour :
visitor_hash = SHA-256(IP + UA + SALT_SECRET + YYYY-MM-DD)
Le hash se réinitialise toutes les 24 heures et ne peut pas être inversé pour récupérer l'IP ou le User-Agent. Rien n'est stocké sur l'appareil du visiteur. Cela signifie que l'intégration ne déclenche pas les exigences de consentement ePrivacy ou PECR — il n'y a rien à consentir.
Vérification dans le tableau de bord
Après le déploiement, ouvrez votre tableau de bord d'analytics et naviguez entre plusieurs routes sur votre site en production. Chaque navigation devrait produire une nouvelle entrée de pageview avec le chemin correct. Si vous ne voyez qu'une seule entrée quelle que soit la navigation, vérifiez que le script est chargé dans le layout racine et que VITE_MONOID_SITE_ID est défini dans l'environnement de production.
L'adaptateur SvelteKit que vous utilisez (Cloudflare, Vercel, Node, statique) n'affecte pas la collecte d'analytics, car le tracking se produit entièrement dans le navigateur après l'hydratation.