Zurück zum Blog

Soft Navigations: SPA-Performance so messen, wie der Browser sie sieht

Chromes Soft-Navigation-Heuristiken lassen Core Web Vitals endlich an clientseitige Routenwechsel andocken. So funktioniert die API und so misst man sie ohne Überwachung.

Ein Jahrzehnt lang beschrieben Core Web Vitals nur die erste Seite, die ein Besucher lud. Jeder Routenwechsel danach in einer Single-Page-Application blieb für die Metriken unsichtbar. Chromes Experiment mit Soft Navigations schließt diese Lücke und verändert, wie eine datenschutzorientierte Analytics die reale Nutzer-Performance messen sollte.

Der blinde Fleck, den Soft Navigations beheben

Eine klassische Hard Navigation entlädt das Dokument und lädt ein neues. Der Browser setzt seine Performance-Timeline zurück, löst ein frisches LCP aus und beginnt, CLS und INP von null zu zählen. Felddaten-Werkzeuge wie CrUX schreiben alles dieser einen URL zu.

SPAs arbeiten nicht so. Nach dem ersten Laden tauschen React Router, der Next.js App Router oder SvelteKit den Inhalt an Ort und Stelle über die History API aus. Kein Dokument wird entladen, also beginnt keine neue Performance-Timeline. Ein Nutzer kann sich durch zehn "Seiten" klicken, während jeder Core Web Vital an der Einstiegs-URL festklebt.

Das Ergebnis kennt jeder, der schon einmal eine SPA auditiert hat: Die Landing-Route wirkt schnell, und die langsamen Interaktionen tiefer in der App tauchen in den Daten nie auf.

Wie Chrome eine Soft Navigation erkennt

Chromes Heuristik verlangt, dass drei Dinge in dieser Reihenfolge geschehen, bevor eine Soft Navigation erfasst wird:

  1. Die Navigation wird durch eine Nutzerinteraktion ausgelöst — einen Klick oder einen Tastendruck.
  2. Die URL wird durch die History API oder die Navigation API geändert.
  3. Eine DOM-Änderung folgt auf die Interaktion und verändert ein bereits vorhandenes DOM-Element.

Diese Abfolge ist bewusst streng. Ein pushState im Hintergrund für Analytics, ein automatisch weiterlaufendes Karussell oder ein URL-Wechsel ohne Interaktion qualifizieren sich nicht. Diese Präzision ist wichtig: Eine Soft Navigation entspricht damit etwas, das ein Mensch tatsächlich getan hat, und nicht beiläufiger Skriptaktivität.

Die API-Oberfläche

Soft Navigations werden über den Standard-PerformanceObserver mit einem eigenen Entry-Typ sichtbar. Du aktivierst sie pro Observer:

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(entry.name, entry.startTime);
  }
}).observe({ type: "soft-navigation", buffered: true });

Wichtiger noch: Andere Performance-Entries erhalten eine navigationId. LCP-, Layout-Shift- und Event-Timing-Entries, die nach einer Soft Navigation ausgegeben werden, tragen die neue ID, sodass du jeden Core Web Vital der Route zuordnen kannst, auf der sich der Nutzer wirklich befand:

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // entry.navigationId verknüpft dieses LCP mit einer bestimmten Soft Navigation
    send({ metric: "LCP", value: entry.startTime, navId: entry.navigationId });
  }
}).observe({ type: "largest-contentful-paint", buffered: true });

Heute steckt das hinter chrome://flags/#soft-navigation-heuristics und einem Origin Trial, mit begrenzter Sichtbarkeit in CrUX. Im stabilen Chrome ist es noch kein Standard, behandle Feldwerte also als richtungsweisend, nicht als verbindlich. Die web-vitals-Bibliothek liefert dieselben Daten über ihre Option reportSoftNavs — der praktische Weg, das anzubinden, ohne Observer von Hand zu schreiben.

Warum das in eine datenschutzorientierte Analytics gehört

Soft-Navigation-Daten sind reines Timing. Sie enthalten keinen Identifier, kein Cookie und nichts, was die Seitensitzung überdauert — eine Dauer, einen groben Elementtyp, einen Routenpfad. Genau die Art Signal, die ein cookiefreies Werkzeug erheben kann, ohne die Consent-Maschinerie zu berühren.

Der Tracker hängt sich bereits in history.pushState ein, um SPA-Routenwechsel zu zählen. Soft Navigations verfeinern genau diesen Hook: Statt nur zu fragen hat sich die Route geändert?, kannst du fragen war das eine interaktionsgetriebene Navigation, und wie war ihre Performance?. Die Performance-Entries reisen neben dem bestehenden Pageview-Beacon an /collect mit und ergänzen Feldmessung, ohne das Skript unter 2 KB zu beschweren oder das Modell der täglichen Hash-Identität zu brechen.

Die Falle, die man vermeiden muss: Soft Navigations als Grund zu sehen, mehr zu sammeln. Manche RUM-Anbieter werden die neue Zuordnung nutzen, um nutzerbezogene Navigationspfade über eine Sitzung hinweg zusammenzunähen — genau das Überwachungsmuster, das cookiefreie Analytics ablehnen soll. Die Metrik ist gerade deshalb wertvoll, weil sie aggregiert bleiben kann: medianes INP pro Route, LCP-Verteilung pro Route, kein Weg zurück zu einer Person.

Soft Navigations machen die tiefsten, langsamsten Teile deiner App zum ersten Mal messbar. Erfasse das Timing, verwirf alles andere, und du erhältst das Performance-Bild ohne das Profil.