Retour au blog

Intégrer des Analytics Respectueux de la Vie Privée dans un Site Astro

Les View Transitions d'Astro cassent silencieusement les scripts d'analytics standard. Voici le bon pattern pour suivre chaque changement de route sans cookies ni bandeau de consentement.

Les View Transitions d'Astro échangent le contenu de la page sans rechargement complet du navigateur — ce qui signifie que tout script d'analytics s'appuyant sur DOMContentLoaded ou load ne se déclenchera qu'une seule fois, lors de la visite initiale. Chaque navigation côté client suivante est invisible. Ce n'est pas une erreur de configuration de votre part ; c'est une conséquence fondamentale du fonctionnement du ClientRouter.

Le même problème de suivi silencieux existe dans SvelteKit 2 et Remix, mais la correction diffère selon le framework. Dans Astro, la réponse est l'événement de cycle de vie astro:page-load.

Pourquoi la balise script habituelle échoue

Quand <ClientRouter /> est actif (opt-in via astro:transitions dans Astro 4, activé par défaut dans Astro 5), les navigations ne déchargent pas la page. Astro récupère la page suivante en arrière-plan, échange le DOM et met à jour l'URL — tout cela sans détruire le contexte JavaScript courant.

Un script de suivi chargé via une simple balise <script> est traité comme un script de module groupé par le pipeline de build d'Astro. Les scripts de module groupés s'exécutent exactement une fois par session de page. Le tracker s'initialise, enregistre un pageview pour la page d'atterrissage, puis ne s'exécute plus pendant que l'utilisateur navigue.

Pour se déclencher à chaque navigation, la logique d'initialisation doit être liée au cycle de vie de navigation d'Astro. Le bon hook est astro:page-load, qui se déclenche après que la nouvelle page est visible et que tous les scripts bloquants sont chargés — aussi bien lors du chargement initial que lors de chaque transition suivante.

L'intégration correcte

Ajoutez le script de suivi une seule fois dans votre layout racine (src/layouts/Layout.astro ou équivalent), puis attachez un listener pour astro:page-load :

---
// Layout.astro
---
<html lang="fr">
  <head>
    <!-- contenu du head -->
  </head>
  <body>
    <slot />

    <script
      is:inline
      src="https://api.monoid.website/tracker.min.js"
      data-site-id="VOTRE_SITE_ID"
      async
    ></script>
  </body>
</html>

La directive is:inline indique au bundler d'Astro de laisser ce script exactement tel quel. Sans elle, Astro traiterait le script comme un module, le dédupliquerait et supprimerait sa ré-exécution. Avec is:inline, la balise script est émise verbatim dans le HTML de chaque page.

Pour les sites sans View Transitions, c'est tout ce dont vous avez besoin. Le tracker se déclenche une fois au chargement et c'est terminé.

Gérer la navigation avec les View Transitions

Si votre site utilise <ClientRouter />, le hook history.pushState intégré du tracker se déclenche correctement après chaque transition — le tracker écoute en interne les événements de navigation d'Astro. Aucune configuration supplémentaire n'est requise.

Pour vérifier, ouvrez l'onglet Réseau des DevTools et filtrez par collect. Naviguez entre deux pages. Vous devriez voir une requête POST par navigation, y compris le chargement initial.

Si vous injectez le tracker de manière conditionnelle et avez besoin qu'il se réinitialise après chaque échange (par exemple, après le montage d'une île dynamique), vous pouvez déclencher manuellement une ré-exécution :

<script data-astro-rerun>
  // Ce bloc se ré-exécute après chaque View Transition.
  // À utiliser avec parcimonie — la plupart de la logique du tracker ne devrait pas être ici.
  if (window.__monoid) {
    window.__monoid.trackPageview();
  }
</script>

L'attribut data-astro-rerun force les scripts inline à se ré-exécuter après chaque transition. Notez qu'il implique is:inline, donc il ne s'applique qu'aux scripts non groupés.

Séparer les environnements

Les projets Astro ont généralement des environnements de développement local, de preview et de production. Utilisez une variable d'environnement pour stocker le site_id et supprimer le suivi en développement :

---
const siteId = import.meta.env.PUBLIC_MONOID_SITE_ID
---

{siteId && (
  <script
    is:inline
    src="https://api.monoid.website/tracker.min.js"
    data-site-id={siteId}
    async
  ></script>
)}

Définissez PUBLIC_MONOID_SITE_ID dans .env pour la production et laissez-la indéfinie en local. Astro expose les variables préfixées par PUBLIC_ au client ; les variables côté serveur uniquement (sans le préfixe) ne sont pas visibles dans le code exécuté dans le navigateur.

Ce dont vous n'avez pas besoin

Pas de bandeau de consentement pour les cookies. Pas d'intégration CMP. L'endpoint de collecte calcule un hash quotidien du visiteur à partir de l'adresse IP, du User-Agent, d'un secret côté serveur et de la date actuelle :

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

Le hash est réinitialisé toutes les 24 heures. Rien n'est stocké sur l'appareil du visiteur. La famille de navigateur et le type d'appareil sont dérivés côté serveur depuis le User-Agent de la requête pour les rapports agrégés — les chaînes User-Agent complètes, les versions de navigateur et les identifiants persistants ne sont jamais stockés.

Les sites Astro sont souvent entièrement statiques ou rendus à la périphérie avec un JavaScript minimal. Ajouter un script d'analytics de moins de 2 KB sans cookies et sans obligation de consentement s'inscrit naturellement dans cette philosophie. Il n'y a pas de paquet npm à maintenir, pas de SDK à mettre à jour, et pas de base juridique RGPD à documenter pour le traitement des analytics.