Si vous suivez une application React, Vue, Angular ou Next.js avec un outil analytics et que vos rapports affichent une seule page vue par session, vous avez un problème de tracking SPA. C'est probablement le bug le plus courant — et le plus invisible — des implémentations analytics modernes.

Le diagnostic est simple : votre site change de route sans recharger la page, et votre outil analytics ne sait pas que l'utilisateur a navigué. Résultat : un funnel cassé, des taux de rebond artificiellement élevés et des décisions marketing prises sur des données fausses.

Trois méthodes permettent de corriger ça. Le principe est le même quel que soit votre outil — GA4, Piano Analytics, Matomo, Piwik PRO, Adobe Analytics, Plausible — mais chacune a un cas d'usage, des limites et un niveau de contrôle différent. Cet article les compare, avec les pièges que je rencontre régulièrement en mission de consulting tracking.

Pourquoi les outils analytics perdent la trace dans une SPA

Une Single Page Application charge une fois la page initiale, puis met à jour le contenu via JavaScript sans appel serveur. Les frameworks modernes utilisent l'History API du navigateur (pushState, replaceState) pour changer l'URL sans déclencher de rechargement.

Le tracking analytics traditionnel, lui, repose sur l'événement page_load du navigateur pour envoyer une vue de page. Sur une SPA, cet événement ne se produit qu'une seule fois : à l'arrivée de l'utilisateur. Toutes les navigations internes deviennent invisibles, quel que soit l'outil de mesure utilisé.

Le principe à retenir Toute implémentation analytics sur SPA doit explicitement choisir une stratégie de détection des changements de route. Sans décision, vous trackez une seule vue par visiteur — peu importe combien de pages il consulte réellement.

Méthode 1 : la détection automatique fournie par l'outil

Activer la détection SPA native de votre outil analytics

Méthode 1

La plupart des outils analytics modernes embarquent une fonctionnalité de détection automatique des changements d'URL :

  • GA4 — la mesure améliorée ("Changements de page basés sur les événements d'historique")
  • Piano Analytics — la propriété spa: true dans la configuration du SDK pa.js, qui active la détection des pushState
  • Matomo — le plugin "SPA tracker" ou trackPageView couplé au heartbeat
  • Piwik PRO — l'option Track virtual page views activée dans le conteneur, ou _paq.push(['trackPageView']) au changement de route
  • Adobe Analytics — la fonction track() avec l'option Single Page App
  • Plausible — l'option manual désactivée par défaut, avec auto-tracking via script.tagged-events.js
Avantages Zéro configuration. Mises à jour gérées par l'éditeur. Pas de code à maintenir.
Limites Aucun contrôle sur le timing : la vue de page part dès le changement d'URL, souvent avant que le titre ou le contenu ne soient à jour. Sur des stacks React, Vue ou Next.js modernes, j'observe régulièrement des page_title qui renvoient la valeur de la page précédente, des doublons sur les navigations avec redirection (replaceState après login), et des vues parasites sur les changements d'URL purement techniques (modaux, filtres).
Cas d'usage recommandé Site vitrine SPA simple, blog headless, application sans routage complexe. Si la majorité de vos rapports porte sur des événements (clics, formulaires) plutôt que sur les vues, c'est suffisant.

Méthode 2 : le déclencheur "History Change" du TMS

Déléguer la détection au Tag Management System

Méthode 2

Cette méthode reprend la main sur l'outil analytics en déplaçant la logique dans un Tag Management System (Google Tag Manager, Tealium, Commanders Act, Piano TMS…). C'est l'approche la plus répandue en implémentation professionnelle parce qu'elle équilibre simplicité et contrôle.

Étape préalable indispensable Désactivez la détection automatique côté outil analytics (méthode 1). Sans ça, vous générerez systématiquement des doublons.

Principe de configuration, illustré ici avec GTM mais identique dans les autres TMS :

  1. Créer un déclencheur de type History Change. Il se déclenche sur les événements pushState, replaceState et popstate.
  2. Créer une balise "vue de page" pour votre outil analytics en y mappant Page URL, Page Title et les paramètres souhaités.
  3. Associer la balise au déclencheur.
Avantages Vous gardez la vue de page initiale au chargement. Vous pouvez enrichir l'événement avec n'importe quelle variable TMS (utilisateur, contenu, expérience A/B). Pas de modification du code applicatif.
Limites Le déclencheur se base sur les variables natives du navigateur. Si votre framework met à jour le titre après le changement d'URL (cas fréquent avec React Helmet ou Vue Meta), vous capturez le titre de la page précédente. Le déclencheur se tire aussi sur les changements d'URL techniques (paramètres query qui gèrent l'état UI).
Cas d'usage recommandé Sites SPA avec un routage standard, où le titre est mis à jour rapidement. C'est le bon compromis pour 70 % des projets que je rencontre.

Méthode 3 : pousser un événement custom dans le dataLayer

Émettre l'événement depuis le code applicatif

Méthode 3

C'est la méthode la plus robuste et celle que je recommande pour les sites e-commerce, les applications avec funnel complexe, ou tout projet où la qualité des données est critique. Elle fonctionne avec n'importe quel outil analytics consommant un dataLayer (ou son équivalent).

Le principe : c'est le code de l'application qui décide quand notifier le tracking d'un changement de page. Vous ajoutez une instruction dans le router de votre framework qui pousse un événement après que le contenu et le titre ont été mis à jour.

React Router
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

export const usePageViewTracking = () => {
  const location = useLocation();
  useEffect(() => {
    requestAnimationFrame(() => {
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({
        event: 'virtual_page_view',
        page_path: location.pathname + location.search,
        page_title: document.title,
        page_location: window.location.href,
      });
    });
  }, [location]);
};
Vue Router
router.afterEach((to) => {
  setTimeout(() => {
    window.dataLayer.push({
      event: 'virtual_page_view',
      page_path: to.fullPath,
      page_title: document.title,
      page_location: window.location.href,
    });
  }, 0);
});

Côté TMS, vous créez ensuite un déclencheur sur l'événement personnalisé virtual_page_view qui pilote la balise vue de page de votre outil (peu importe lequel).

Avantages Contrôle total sur le timing. Possibilité d'enrichir le payload avec n'importe quelle donnée applicative (ID utilisateur, catégorie produit, étape de checkout). Filtrage natif des navigations parasites. Compatible serveur-side tagging. Système documenté côté code.
Limites Intervention dans le code de l'application. Demande une coordination dev / data au moment des évolutions de routing.
Cas d'usage recommandé E-commerce SPA, applications SaaS, sites avec authentification, projets avec serveur-side tagging, toute mise en place où vous avez besoin de paramètres custom dans la vue de page.

Comparatif des 3 méthodes

Critère M1 — Détection auto M2 — History Change TMS M3 — DataLayer custom
Effort de mise en placeAucunFaibleMoyen
Contrôle du timingTrès faibleMoyenTotal
Risque de titre incorrectÉlevéMoyenFaible
Risque de doublonsFaible si seulFaible si M1 désactivéeFaible
Paramètres custom✓ illimités
Maintenance long termeAucuneFaibleÀ documenter côté code
Cas typeVitrine, blog70 % des SPA standardE-commerce, SaaS, data-critique

Les pièges récurrents

Au-delà du choix de la méthode, certains problèmes reviennent dans presque toutes les implémentations SPA.

Le doublon silencieux La détection automatique de l'outil reste activée alors que le TMS envoie déjà des vues. Résultat : deux événements par navigation, sessions sous-estimées, taux de rebond explosé. C'est le bug le plus fréquent dans les audits que je mène.
Le titre de la page précédente Sur React, Vue ou Angular, la mise à jour du titre via les helpers (React Helmet, Vue Meta, Title service) est asynchrone. Utilisez requestAnimationFrame ou poussez l'événement dans le hook afterEach du router.
Les paramètres techniques dans l'URL Filtres, modaux, onglets actifs : chacune de ces interactions déclenche un pushState et donc une vue parasite. Soit vous filtrez côté TMS, soit vous passez en méthode 3.
Les redirections après login L'utilisateur arrive sur /login, est redirigé en replaceState vers /dashboard. La méthode 1 envoie deux vues, dont une sur /login jamais vraiment vue. Préférez la méthode 3 sur ces parcours.

Comment valider votre tracking SPA

Aucune des méthodes ne se déploie sans validation. Le minimum avant production : mode prévisualisation du TMS, mode debug de l'outil analytics (DebugView GA4, Real-Time Matomo, console Adobe…), comparaison du nombre de vues envoyées vs attendues sur un échantillon de 10 navigations réelles. Si vous obtenez 9 ou 11 vues au lieu de 10, le tracking est cassé.

Testez aussi les cas limites : bouton retour navigateur, ouverture en nouvel onglet, refresh sur une page interne, deep link partagé. Tous ces parcours doivent émettre exactement une vue.

Quelle méthode pour quel projet

Trois questions suffisent à trancher.

Données critiques → Méthode 3

Si vos décisions business reposent sur les rapports analytics (allocation média, attribution, A/B testing), le coût de mise en place est négligeable face au coût d'une décision prise sur des données fausses.

Paramètres custom → Méthode 3

Si vous avez besoin de catégoriser, segmenter ou enrichir la vue de page avec des paramètres applicatifs (ID utilisateur, étape funnel…), la méthode 1 est éliminée.

Stack simple et stable → Méthode 2

Sur une stack mature avec routage standard, le déclencheur History Change du TMS fonctionne bien et reste maintenable sans intervention dev.

Architecture moderne → Méthode 3

Sur Next.js App Router, Remix, ou des architectures avec micro-frontends, le push dataLayer reste la seule méthode fiable.

Conclusion

Tracker une Single Page Application n'est pas un problème technique difficile. C'est un problème de choix d'architecture, et il se pose de la même façon quel que soit l'outil analytics utilisé. La détection automatique répond à 80 % des cas avec un effort nul, le déclencheur History Change du TMS à 95 % avec un peu de configuration, le push dataLayer custom à 100 % avec un peu de code.

Le piège classique : empiler les méthodes au lieu d'en choisir une. Si vous prenez une seule décision après cet article, vérifiez que vous n'avez pas la détection automatique de votre outil activée en même temps qu'une balise TMS de vue de page. C'est le bug le plus fréquent et le plus simple à corriger.

ReactVueAngularNext.js GA4Piano AnalyticsMatomoPiwik PRO Adobe AnalyticsPlausibleGTM

À lire aussi

Tag Management Systems en 2026 : quel outil choisir ? 7 plateformes TMS comparées — GTM, Adobe, Tealium, Piwik PRO, Commanders Act, Matomo, Ensighten.
Quel outil analytics choisir en 2026 ? 11 outils analytics passés en revue : conformité RGPD, hébergement, exemption CNIL et recommandations.

Votre tracking SPA envoie-t-il les bonnes données ?

Audit complet de votre implémentation analytics (GA4, Piano, Matomo, Piwik PRO…) sur SPA, identification des doublons, recommandations priorisées. Échangeons 30 minutes sur votre setup.

Prendre RDV →