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 />, aucune configuration supplémentaire n'est requise — mais il vaut la peine d'être précis sur la raison, car l'explication habituelle est fausse.
Le tracker n'écoute pas astro:page-load ni aucun autre événement du cycle de vie d'Astro. Il patche history.pushState au chargement. Le routeur d'Astro met à jour l'URL via ce même appel à la History API, donc la fonction patchée s'exécute à chaque transition et envoie un pageview. Le hook se situe sous la couche d'événements d'Astro plutôt que de l'écouter.
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.
Une réserve à connaître : le hook couvre pushState, pas popstate. Un appui sur Précédent ou Suivant change la route sans appeler pushState, et ne produit donc pas de nouveau pageview actuellement.
Le tracker n'expose aucune méthode manuelle de pageview. Le global n'accepte que des événements personnalisés :
<script>
// Événements personnalisés uniquement — il n'existe pas d'appel trackPageview().
// Le nom doit correspondre à [a-z0-9_][a-z0-9_-]{0,63}.
window.monoid('event', 'signup_started');
</script>
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.
Comments
Loading comments…