Soft Navigations : mesurer la performance des SPA comme le navigateur
Les heuristiques de soft navigation de Chrome permettent enfin aux Core Web Vitals de se rattacher aux changements de route côté client. Voici comment l'API fonctionne et comment la mesurer sans surveillance.
Pendant une décennie, les Core Web Vitals ne décrivaient que la première page chargée par un visiteur. Chaque changement de route ultérieur dans une single-page application restait invisible pour les métriques. L'expérimentation des soft navigations de Chrome comble ce vide, et change la manière dont une analytique axée sur la confidentialité devrait mesurer la performance réelle des utilisateurs.
L'angle mort que corrigent les soft navigations
Une hard navigation classique décharge le document et en charge un autre. Le navigateur réinitialise sa timeline de performance, déclenche un nouveau LCP et commence à compter CLS et INP à partir de zéro. Les outils de terrain comme CrUX attribuent tout à cette unique URL.
Les SPA ne fonctionnent pas ainsi. Après le chargement initial, React Router, l'App Router de Next.js ou SvelteKit remplacent le contenu sur place via la History API. Aucun document n'est déchargé, donc aucune nouvelle timeline de performance ne démarre. Un utilisateur peut parcourir dix « pages » alors que chaque Core Web Vital reste figé sur l'URL d'entrée.
Le résultat est connu de quiconque a déjà audité une SPA : la route d'atterrissage paraît rapide, et les interactions lentes plus profondes dans l'application n'apparaissent jamais dans les données.
Comment Chrome détecte une soft navigation
L'heuristique de Chrome exige que trois choses se produisent dans l'ordre avant d'enregistrer une soft navigation :
- La navigation est déclenchée par une interaction de l'utilisateur — un clic ou une frappe de touche.
- L'URL est modifiée par la History API ou la Navigation API.
- Une modification du DOM suit l'interaction, en changeant un élément du DOM déjà existant.
Cette séquence est volontairement stricte. Un pushState en arrière-plan pour l'analytique, un carrousel qui avance tout seul ou un changement d'URL sans interaction ne se qualifient pas. Cette précision compte : une soft navigation correspond ainsi à quelque chose qu'un humain a réellement fait, et non à une activité de script incidente.
La surface de l'API
Les soft navigations apparaissent via le PerformanceObserver standard à l'aide d'un type d'entrée dédié. On s'y abonne par observer :
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry.name, entry.startTime);
}
}).observe({ type: "soft-navigation", buffered: true });
Plus important encore : d'autres entrées de performance gagnent un navigationId. Les entrées LCP, layout-shift et event-timing émises après une soft navigation portent le nouvel identifiant, ce qui permet de réattribuer chaque Core Web Vital à la route sur laquelle l'utilisateur se trouvait réellement :
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// entry.navigationId rattache ce LCP à une soft navigation précise
send({ metric: "LCP", value: entry.startTime, navId: entry.navigationId });
}
}).observe({ type: "largest-contentful-paint", buffered: true });
Aujourd'hui, cela vit derrière chrome://flags/#soft-navigation-heuristics et un origin trial, avec une exposition limitée dans CrUX. Ce n'est pas encore le comportement par défaut dans Chrome stable, traitez donc les chiffres de terrain comme indicatifs, pas comme faisant autorité. La bibliothèque web-vitals expose les mêmes données via son option reportSoftNavs, qui est la façon pratique de tout brancher sans écrire d'observers à la main.
Pourquoi cela relève d'une analytique axée sur la confidentialité
Les données de soft navigation sont du pur timing. Elles ne contiennent aucun identifiant, aucun cookie, et rien qui survive à la session de la page — une durée, un type d'élément grossier, un chemin de route. C'est exactement le genre de signal qu'un outil sans cookies peut collecter sans toucher à la machinerie du consentement.
Le tracker s'accroche déjà à history.pushState pour compter les changements de route des SPA. Les soft navigations affinent ce même hook : au lieu de demander seulement la route a-t-elle changé ?, on peut demander était-ce une navigation pilotée par une interaction, et quelle a été sa performance ?. Les entrées de performance voyagent aux côtés du beacon de pageview existant vers /collect, ajoutant de la mesure de terrain sans alourdir le script de moins de 2 Ko ni casser le modèle d'identité par hash quotidien.
Le piège à éviter est de traiter les soft navigations comme une raison de collecter davantage. Certains fournisseurs de RUM utiliseront la nouvelle attribution pour recoudre des parcours de navigation par utilisateur sur une session — exactement le schéma de surveillance que l'analytique sans cookies existe pour rejeter. La métrique est précieuse précisément parce qu'elle peut rester agrégée : INP médian par route, distribution du LCP par route, sans chemin de retour vers une personne.
Les soft navigations rendent enfin mesurables les parties les plus profondes et les plus lentes de votre application. Collectez le timing, jetez tout le reste, et vous obtenez l'image de performance sans le profil.