Retour au blog

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.