Web design & development · Performance

Your single-page app's Core Web Vitals were never really measured. Chrome 151 changes that

For most of the last five years, the Core Web Vitals of a React, Vue or Next.js app described exactly one thing: the first page a visitor landed on. Every in-app route change after that was either never measured or quietly charged to the wrong URL. Chrome 151, released in August 2026, is the first stable browser build that can measure Core Web Vitals across those in-app navigations. It is a real change, but not the one most summaries claim it is.

The short answer

Chrome 151 shipped two performance entries, soft-navigation and interaction-contentful-paint, that let a single-page app measure LCP, CLS and INP per route change instead of only on first load. Google's public field dataset still records one entry per full page load, so this improves what you can diagnose today, not what Google ranks on.

What Chrome 151 actually shipped

Chrome 151 added two new entry types to the PerformanceObserver timeline. A soft-navigation entry marks the moment the browser decides an in-app route change qualifies as a navigation. An interaction-contentful-paint entry measures the largest contentful paint that follows a user interaction, which is the closest equivalent to LCP for a route change that never reloads the document. Both landed after roughly two years of origin trials, starting in Chrome 139 and running through a final trial in Chrome 147 in March 2026.

Two limits matter before you plan anything around it. Only Chromium implements this, so Safari and Firefox visitors produce no soft-navigation data at all. And the measurement libraries are only starting to catch up: the web-vitals library now attaches a navigation ID and navigation URL to each metric so it lands against the right route, and reports TTFB as 0 for soft navigations because there is no server response to time.

What each metric measured before, and what it measures now

The useful way to read this change is metric by metric, because the three Core Web Vitals were broken in three different ways on single-page apps, and only one of them was broken by being missing.

MetricOn an SPA before Chrome 151With soft-navigation measurementWho can see it in September 2026
LCPMeasured once, on the initial document load. A route change produced no LCP at all, so the slowest screen in your app could be invisibleinteraction-contentful-paint gives an LCP-style figure for the content rendered after the click that started the route changeYour own field script, Chrome 151+ visitors only
INPMeasured across the whole tab lifetime and attributed to the landing URL, so a sluggish filter on /search was charged to the homepage a visitor entered onThe timeline splits at each soft navigation, so the slow interaction is attributed to the route it actually happened onYour own field script. Google's dataset still attributes it to the entry URL
CLSAccumulates for the life of the tab and never resets on a route change, so long browsing sessions inflate the score recorded against the entry pageResets per soft navigation, which is why some teams will see entry-page CLS drop once they re-instrumentYour own field script only
TTFBNo meaningful value for a client-side route changeReported as 0 by design, since nothing was requested from a serverNot comparable to hard-navigation TTFB, do not average the two
Search Console and CrUXOne record per full page load, keyed to that URLUnchanged. Chrome has not published a date for soft-navigation data in CrUXEveryone, and it is still the only version Google acts on

That last row is the one that gets misreported. If your reason for caring about Core Web Vitals is search performance, nothing about your Search Console report changed in August 2026.

The five conditions a route change has to meet to count

Chrome does not let a framework declare that a navigation happened. It detects one with heuristics, which keeps the definition consistent across React Router, Vue Router, the Next.js app router and hand-rolled routing. A route change is treated as a soft navigation when all five of these are true:

  1. A user interaction starts it, typically a click or a keypress.
  2. That interaction triggers a same-document history change, a pushState or replaceState call, or the equivalent through the Navigation API.
  3. The URL changes and a new history entry is created.
  4. The DOM is modified as a result.
  5. Something paints from that modification.

Which means a set of very common patterns produce no measurement, because the browser does not consider them navigations at all:

PatternWhy it fails the testWhat to do
A redirect the app fires itself after load, for example sending a logged-in user from / to /dashboardNo user interaction started itAccept it as part of the initial load and optimise it there
A modal, drawer or full-screen overlay showing page-like contentThe URL never changesIf it is a page to the user, give it a URL. If it is not, stop treating it as one
Tab or filter UI that swaps the whole content areaUsually no history entryPush a URL for states worth sharing, linking or ranking
Infinite scroll appending the next block of resultsNo discrete interaction and no history entryMeasure it as interaction latency, not navigation
A query-string update with no meaningful repaintNothing contentful paintsExpected. Not every URL change is a navigation

There is a second, more valuable use for that list. If the screens your team calls pages do not generate soft-navigation entries, a browser does not think they are pages, and neither does a crawler that never sees the URL. That is an architecture finding, not a measurement one, and it is usually cheaper to fix during a build or rebuild than after launch.

Does any of this change how Google ranks your site?

No, and it is worth being precise about why. Core Web Vitals remain part of the page experience signals, and the 2026 changes tightened how INP is measured rather than adding new ranking weight. Google's field data comes from the Chrome User Experience Report, which still records one entry per full page load, keyed to that URL. Chrome has said how soft navigations will eventually be represented there is still being worked out, with no published date.

The practical consequence is a clean split that most performance advice blurs:

What we'd do about it

Before instrumenting anything new, split your existing field data by entry URL versus in-app route. Most teams discover their reported CLS problem is one long-session accumulation artefact, and their real problem is a first-load LCP on two or three template types.

What to do about it, by what you have built

Your setupWhat actually mattersFirst move
Marketing or content site built as an SPASearch only ever sees the entry loadServer-render or statically generate entry templates. Soft-navigation data is secondary here
Ecommerce storefront with client-side routingCategory to product to cart transition speed, which drives revenue and is invisible to searchInstrument those three transitions, set a route-change budget, then fix the slowest one
Logged-in product or dashboardNothing here has SEO exposure at allTrack INP per route as a support and retention metric, and ignore Core Web Vitals thresholds
Hybrid framework setup, for example a Next.js app router buildWhich navigations are hard and which are soft is often not what the team assumesLog both entry types for a week before drawing any conclusions

A five-step implementation checklist

  1. Upgrade to a web-vitals version that reports navigation ID and navigation URL, and enable soft-navigation reporting in whatever field monitoring you already run.
  2. Send the route pattern, not the raw URL, as a dimension. /product/:id aggregates. /product/48211 does not.
  3. Keep hard-navigation and soft-navigation data in separate buckets. Averaging them produces a number that describes neither.
  4. Hold entry loads to the published thresholds, LCP under 2.5 seconds, INP under 200 milliseconds, CLS under 0.1. Hold route changes to your own baseline, because no public threshold for soft navigations exists yet.
  5. Treat the totals as a Chromium sample. Your Safari traffic contributes nothing to this dataset, and on consumer ecommerce that can be a third of your audience.

Frequently asked questions

What is a soft navigation?

A soft navigation is an in-app route change where a single-page app updates the URL and re-renders the view without loading a new HTML document. Chrome counts one when a user interaction triggers a same-document history change, the URL changes, the DOM is modified and something paints as a result.

Does Google use soft navigation data for ranking?

No. As of September 2026, Google's field dataset, the Chrome User Experience Report, records one entry per full page load, keyed to that URL, and that is what feeds Search Console and the page experience signals. Chrome has not published a date for including soft navigations.

Why does my single-page app report bad CLS when every screen looks stable?

Because CLS accumulated across the whole tab lifetime and never reset on route changes, so a visitor who moved through eight screens contributed all eight screens' layout shift to the one URL they entered on. Chrome 151's soft-navigation measurement resets the score per route, which is why re-instrumented sites often see the entry page's CLS fall.

Which Chrome version added Core Web Vitals measurement for single-page apps?

Chrome 151, released in August 2026. It introduced the soft-navigation and interaction-contentful-paint performance entries, following origin trials that began in Chrome 139 and ended with a final trial in Chrome 147 in March 2026.

Does this work in Safari or Firefox?

No. Only Chromium has implemented it, so any soft-navigation data you collect covers Chrome and Chromium-based browsers only. Treat the results as a sample of your audience rather than the whole of it.

Should we stop building single-page apps because of Core Web Vitals?

No, but you should be deliberate about which pages need to exist as real documents. Anything that has to rank, be shared or be crawled should be served as its own URL with server-rendered or statically generated content. Everything behind a login or deep inside a flow can stay client-side, where route-change speed is a conversion concern rather than a search one.

The takeaway

Chrome 151 closed a measurement gap that has existed since single-page apps became the default way to build. It did not close a ranking gap, because Google's field data still starts and ends with the page a visitor landed on. Use the new entries to find the in-app routes that are quietly costing you conversions, keep optimising entry loads for search, and use the five-condition test as a design check: if the screens your team calls pages cannot be detected as navigations, they probably should not be pages.

Sources & further reading

Rahul Gupta

Founder of HyberX, a digital growth agency working with brands across the US, Europe, the Middle East and India. Writes on web design, paid media and conversion optimisation.

More about Rahul · LinkedIn

Related reading

Not sure what your app's real-user performance looks like?

We audit field data the way browsers actually collect it, separate entry loads from in-app routes, and fix the ones costing you rankings or revenue.

Book a Growth Call