Soft Navigations: Core Web Vitals Finally Work in Single Page Apps

For years a React or Next.js app got one LCP for the first page and nothing after. Chrome 151 changed that. Here is what soft navigations measure, how to collect them, and what Google Search still does not see.

Glowing single page app window with route change arrows and metric gauges lighting up on each transition

The Short Answer: What Changed

Since Chrome 151, soft navigation measurement is switched on by default. A soft navigation is a route change inside a single page app, where JavaScript swaps the content and updates the URL without a full page load. Chrome now reports First Contentful Paint, Largest Contentful Paint, Cumulative Layout Shift and Interaction to Next Paint for each of those route changes, instead of treating the whole session as one long page.

The catch is just as important. Google's documentation says how soft navigations will be reported in CrUX is still to be determined. So your field data in Search Console does not change yet. What changes is that you can finally see, in your own monitoring, which routes in your app are slow.

Chrome 151first version with soft navigation measurement on by default
4metrics per route change: FCP, LCP, CLS, INP
0browsers outside Chromium that report it

The Problem Soft Navigations Fix

Core Web Vitals were designed around page loads. In a classic site every click loads a new document, so every page gets its own LCP, CLS and INP. In a single page app built with React, Next.js, Vue, Angular or Svelte, the browser loads one document and then JavaScript handles every click after that.

That produced two distortions. First, only the landing view ever got an LCP. A product page reached by clicking from a category page had no loading metric at all, however slow it felt. Second, CLS and INP piled up across the entire session and were blamed on the URL the visitor first landed on. A slow checkout step could show up as a poor score on your homepage. Developers have been asking for a fix since at least 2021, and Chrome tested an early version through an origin trial from 2024 before shipping it.

Soft Navigations by the Numbers

MetricBefore Chrome 151 in an SPAWith soft navigations
FCPFirst load onlyReported again for each route change
LCPFirst load onlyReported per route, via interaction-contentful-paint entries
CLSOne running total for the whole sessionSplit so each route gets its own value
INPWorst interaction of the whole sessionAttributed to the route where it happened
Browser coverageAll major browsers report the first loadChromium only, no Safari or Firefox
CrUX and Search ConsoleLanding URL onlyUnchanged for now, reporting still to be decided

What Counts as a Soft Navigation

Chrome does not treat every URL change as a new page. Roughly, it needs three things to happen together: a user interaction such as a click or tap, a change to the URL through the History API, and a visible change to the page that paints. A URL that changes on its own, for example a tracking parameter being rewritten on scroll, does not count. That is sensible, because it matches how a person experiences the app: they clicked, the address changed and new content appeared, so to them it was a new page.

This has one practical effect. If your router updates the URL long after the new view has painted, or paints the view without changing the URL, Chrome may not recognise the transition. Frameworks that follow the normal click, push state, render pattern are fine.

How to Collect the Data

The easiest route is the web-vitals library from version 6 onwards, which handles the edge cases for you. Turn on soft navigation reporting per metric:

import { onLCP, onCLS, onINP } from 'web-vitals';

function send(metric) {
  // metric.navigationType is 'soft-navigation' for route changes
  navigator.sendBeacon('/vitals', JSON.stringify({
    name: metric.name,
    value: metric.value,
    route: location.pathname,
    type: metric.navigationType
  }));
}

onLCP(send, { reportSoftNavs: true });
onCLS(send, { reportSoftNavs: true });
onINP(send, { reportSoftNavs: true });

If you prefer the raw browser API, feature detect first, because Safari and Firefox do not support it:

if (PerformanceObserver.supportedEntryTypes.includes('soft-navigation')) {
  new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      console.log('Soft navigation to', entry.name, 'at', entry.startTime);
    }
  }).observe({ type: 'soft-navigation', buffered: true });
}

Record the route with every value. The whole point is to find out which routes are slow, so group your data by path pattern, for example /product/:id, rather than by full URL. Our Core Web Vitals monitoring guide covers where to send this data and what to alert on.

Check the page load your visitors land on

Soft navigations cover route changes. Your first load still decides your CrUX score. Test it free in about thirty seconds.

Analyze your site free

What CrUX and Search Console See

This is where most confusion will come from over the next months. The Chrome UX Report, which feeds Search Console and the field data at the top of PageSpeed Insights, still attributes metrics to the URL the visitor landed on. Google's documentation says how soft navigations will be reported in CrUX, once the feature is launched there, is still to be determined.

So three things are true at the same time:

Lab tools are a separate story again. Lighthouse and PageSpeed Insights lab data measure a single page load and do not click through your app. We explain the lab and field split in Lighthouse vs PageSpeed Insights.

Fixing Slow Route Changes

Once you can see route level numbers, the fixes are usually the same handful:

  1. Slow LCP on a route. The new view waits on a data fetch before it renders anything useful. Start the fetch on hover or on pointer down instead of on click, and render a skeleton that has the same size as the final content.
  2. High CLS on a route. Content arrives in pieces and pushes earlier content down. Give image and list containers their final dimensions up front.
  3. Poor INP on a route. The click handler does all the work of the new view before the browser can paint. Show the loading state first, then do the heavy work, and break long tasks up.
  4. Everything slow on the first click only. The route's JavaScript chunk is downloaded on demand. Prefetch likely next routes when the browser is idle.

If you run Next.js, most of these map onto features the framework already has. See our Next.js performance guide for the specifics.

Frequently Asked Questions

What is a soft navigation?

A soft navigation is a page change inside a single page app where JavaScript replaces the content and updates the URL without loading a new document. Chrome treats it as a new page view when a user interaction leads to a URL change and a visible paint.

Which Chrome version measures soft navigations?

Soft navigation measurement is enabled by default from Chrome 151. Earlier versions only offered it behind a flag or through the origin trial Google ran from 2024.

Which metrics are reported for soft navigations?

First Contentful Paint, Largest Contentful Paint, Cumulative Layout Shift and Interaction to Next Paint are reported for each soft navigation. LCP for a route change arrives through interaction-contentful-paint entries.

Do soft navigations change my Search Console Core Web Vitals?

Not yet. Google says how soft navigations will be reported in CrUX is still to be determined, and CrUX is what Search Console uses. Your field data is still attributed to the landing URL.

How do I track soft navigations with the web-vitals library?

Use web-vitals version 6 or later and pass reportSoftNavs: true in the options for each metric callback, such as onLCP, onCLS and onINP. Each report then includes a navigationType you can use to tell route changes apart.

Do Safari and Firefox report soft navigations?

No. Support is Chromium only, so your soft navigation data covers Chrome and Edge users but not Safari or Firefox users. Always feature detect before using the API.

Why do my soft navigation numbers not match PageSpeed Insights?

PageSpeed Insights lab data measures one fresh page load and never clicks through your app, and its field data comes from CrUX, which still uses the landing URL. Route level numbers only exist in your own real user monitoring.

The Bottom Line

Chrome 151 finally gives single page apps honest per route Core Web Vitals. Search Console does not use them yet, so nothing about your ranking data changes today. What changes is that you can stop guessing which route is slow. Add reportSoftNavs: true to your web-vitals setup, record the route with every value, and fix the slowest routes first while Google decides how to bring this into CrUX.

VF
VitalsFixer Editorial
Written by Abd Shanti, founder of VitalsFixer

Every claim on this page is checked against Google's own Chrome and web.dev documentation or our own server data, and dated. If something changes, we update the page and the date.

Sources and References
  1. Google Chrome for Developers. Measuring soft navigations: enabled by default in Chrome 151, metrics reported, CrUX status. Updated 2 September 2026.
  2. web.dev. How SPA architectures affect Core Web Vitals.
  3. GoogleChrome. web-vitals library: reportSoftNavs option, version 6.
  4. DebugBear. A Guide To Soft Navigations And Core Web Vitals Reporting.
Cite this article: "Since Chrome 151, soft navigation measurement is enabled by default, so Chrome reports FCP, LCP, CLS and INP for each route change in a single page app. Google says how soft navigations will be reported in CrUX is still to be determined, so Search Console data is unchanged for now."
Source: VitalsFixer. Soft Navigations: Core Web Vitals Finally Work in Single Page Apps (2026). https://vitalsfixer.com/blog/soft-navigations-core-web-vitals