Skip to main content

A Guide To Soft Navigations And Core Web Vitals Reporting

· 12 min read

Currently, there is no standardized way to measure Core Web Vitals and other web performance metrics inside single page applications (SPA) because they rely on soft navigations to respond to user actions, which are not as obvious to detect as hard navigations.

As of now, web performance monitoring tools can’t easily report web performance metrics for soft navigations. Instead, most metrics focus on the initial page load.

The main reason for this measurement gap is that we don’t yet have an agreed definition of what user actions qualify as soft navigations, which would allow developers of web performance tools and browser vendors to coherently detect and measure Web Vitals in single page applications.

However, there’s already some progress in the development of soft navigation reporting.

The Chrome developer team have started work on defining the heuristics and creating the APIs for reporting web performance metrics for soft navigations. The development is currently at an experimental stage, and the proposals are still not set in stone.

We still decided to cover this topic because it will be an important change. Including soft navigations in Core Web Vitals will change the way we build, monitor, and optimize single page applications.

In this article, we’ll look into how navigation works in single page applications, the possibilities of soft navigation reporting, and the evolution of Google’s web-vitals.js library.

Soft navigations diagram

A Brief Recap of How SPAs Work

Single page applications provide an alternative web application architecture to websites and multi page applications (MPAs). They are typically created with component-based JavaScript frameworks such as React, Vue, Angular, and others.

As opposed to traditional websites and MPAs which download a new HTML page whenever the user performs an action (e.g. clicks a button or menu item), SPAs only download a single HTML page (this is where the name ‘Single Page Application’ comes from), then update the page content using JavaScript every time the user interacts with the app.

While the SPA architecture provides users with a more dynamic interface and can react to user actions faster than a traditional website, it’s hard to track in-app navigation in a single page application because, by default, the browser renders every piece of content (including partial and full page rewrites) under the same top-level URL.

As a result, early SPAs had various usability and SEO issues. For example, content changes were not followed by corresponding URL changes in the browser’s address bar, and search engine, social media, and other bots couldn’t index dynamic page content properly.

SPA developers solved these issues by introducing the concept of ‘soft navigations’, which maps ‘soft URLs’ to dynamically rendered pages. They are called ‘soft’ because the browser doesn’t download a new HTML file in the background when the app generates a dynamic URL for the updated page content.

Despite the addition of soft navigations to single page applications, website analysis and monitoring tools still don't have an established way to measure in-app performance and other metrics. Let’s see why.

What Is a Soft Navigation?

A soft navigation is essentially the dynamic emulation of the corresponding hard navigation that would be used in a website or multi page application.

To expose dynamic content changes to the web browser and other user agents, SPAs update the URLs dynamically and push the previous URLs into the browser’s history using the History API.

As a result, on the surface, the updated page content will behave like a new HTML page — e.g. users will be able to see a new URL in the browser’s address bar, bookmark the page, share it on social media, use the browser’s Back and Forward buttons, etc.

Hard Navigation vs Soft Navigation: A Code Example

Now let’s see a code example of the technical differences between soft and hard navigations.

An Example of Hard Navigations

In the code snippet below, the three links in the <header> section are hard navigations and could be used on a static HTML page:

<!-- Hard navigation with HTML -->
<!-- index.html -->

<header>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</header>

To allow the user to navigate this website, we would also need to create an about.html and a contact.html file and upload them to the server.

The Corresponding Soft Navigations (in React)

Now, let’s see how the corresponding soft navigations look like in a single page application created with the React framework:

/**
* Soft navigations with React
* components/Header.js
*/
import { Link } from "react-router-dom"

const Header = () => {
return (
<header>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>
</header>
)
}

export default Header

And, here's the respective App.js file:

/**
* Soft navigations with React
* App.js
*/

import { BrowserRouter as BrowserRouter, Route, Routes } from "react-router-dom"
import Header from "./components/Header";
import Home from "./components/Home"
import About from "./components/About";
import Contact from "./components/Contact";

function App() {
return (
<BrowserRouter>
<div className="container">
<Header />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</div>
</BrowserRouter>
);
}

export default App;

To allow the user to navigate the React app above, we would also need to create the Home.js, About.js, and Contact.js components and add them to the application.

All in all, the browser will compile the React code above to the same HTML as in the first code snippet above.

Under the hood, the Link element uses history.pushState to update the page URL without fully reloading the page.

However, there’s an important difference:

Now, the three links in the <header> section are soft navigations.

When the user clicks one of them, the browser will update the page content and URL on the fly using JavaScript instead of sending an HTTP request to the server and downloading a new HTML page.

The React app will respond faster than the traditional HTML website because the entire code is already downloaded, the JavaScript is compiled, and no more client-server communication is needed.

However, capturing web performance metrics for a dynamic update of a single HTML page (i.e. soft navigation) is not as straightforward as measuring the performance impact of a static URL change where a real HTML page load takes place (i.e. hard navigation).

The Challenges of Reporting Soft Navigations

The issue with soft navigation reporting is that each SPA framework (or application in the case of native ECMAScript components) defines soft navigations in a different way.

If there’s just a single HTML page, which page updates qualify as ‘navigation’? There’s no standardized answer to this question.

For example, different SPAs can:

  • update the URL on different types of content changes
  • load content synchronously or asynchronously
  • update the URL before or after the new content loads
  • preload the content or not
  • and more

However, if each SPA follows different rules to update the URL, how should website analytics tools consistently detect soft navigations and report their performance impact?

To measure Core Web Vitals and other performance metrics for soft navigations, we need a standardized way that can be used for any single page application, irrespective of the technology it was built with.

The Standardization and Implementations of Soft Navigations

The defining rules to identify soft navigations (a.k.a. heuristics) and the corresponding technical implementations are still in the drafting stage.

According to the current version of the specifications (which can still change in the future), the following dynamic URL updates qualify as soft navigations:

  • “The navigation is initiated by a user action.”
  • “The navigation results in a visible URL change to the user, and a history change.”
  • “The navigation results in a DOM change.”

(Source: Chrome for Developers Blog)

The heuristics above are being/will be implemented at the following levels:

W3C Specifications and Web APIs

There’s already an unofficial Soft Navigations draft published by W3C’s Web Platform Incubator Community Group (WICG), however it’s still in an early stage.

Once soft navigation reporting is added to the native browser APIs, they will be part of the Performance interface.

The addition of soft navigation detection to actual web APIs depends on the three browser engine developers: Chromium (Blink engine), Firefox (Gecko engine), and Safari (WebKit engine) — as of the currently available information, only Chromium is working on the feature.

Browser Developer Tools

Soft navigation detection is already available as an experimental feature of Chrome DevTools.

You can report the occurrence of soft navigations to the console by enabling the ‘Enable Experimental Web Platform Features’ flag in your Chrome browser:

Enable Experimental Web Platform Features flag, Google Chrome

The Web Vitals Initiative and Its Experimental soft-navs Branch

Currently, the performance impact of soft navigations is not included in the official Web Vitals metrics, so they are not available in either Chrome DevTools or Google’s lab tools (e.g. Lighthouse).

However, Google Chrome’s web-vitals.js library has an experimental soft-nav branch that already includes working code that you can use to report Web Vitals for soft navigations.

For example, here’s the simplest way to add soft navigation reporting for Largest Contentful Paint, Interaction to Next Paint, and Cumulative Layout Shift to your application:

import {
onLCP,
onINP,
onCLS,
} from 'https://unpkg.com/web-vitals@soft-navs/dist/web-vitals.js?module';

onLCP(console.log, {reportSoftNavs: true});
onINP(console.log, {reportSoftNavs: true});
onCLS(console.log, {reportSoftNavs: true});

The CrUX Report

Similar to Lighthouse, soft navigation reporting is not included in the Chrome User Experience report either, which also only reports Core Web Vitals for hard navigations. Google still has no known plans to add the impact of soft navigations to the CrUX report.

The Current State of Soft Navigation Reporting

As of Chrome for Developers’ article on soft navigation reporting, the experimental branch of the web-vitals.js library currently reports soft navigations for the individual Web Vitals as follows (however, note that the data below is still subject to change):

  • Time To First Byte (TTFB) for soft navigations is always reported as 0 because TTFB is a server-side metric. When a soft navigation happens, there's no communication with the server, and the ‘first byte’ is already present in the browser (i.e. the page is already downloaded).
  • First Contentful Paint (FCP) is currently not supported by the experimental branch of the web-vitals.js library, but there are plans to register the timestamp when the dynamic URL changes and to use it as the FCP value for the soft navigation.
  • Largest Contentful Paint (LCP) doesn’t include the existing paints from the previous navigation, whether it was a hard or soft navigation. Its value is either 0 or a positive number. The latter happens when the largest content element on the updated page has appeared during that update.
  • Cumulative Layout Shift (CLS) reports the amount of unexpected layout shifts that have happened since the last navigation.
  • First Input Delay (FID) is currently not supported by the experimental branch of the web-vitals.js library, which as of now only registers the first first input delay (which follows the initial hard navigation), but there are plans to register the first input delays for the subsequent soft navigations too.
  • Interaction to Next Paint (INP) reports the 98th percentile value of all interaction delays that have happened since the previous (soft or hard) navigation.

In other words, Web Vitals (except FCP and FID, which are currently not supported by the library) are split into smaller parts so that you can see the performance impacts of the subsequent soft navigations and separate them from the initial hard navigation, which has resulted in the download of the entire code base of the single page application.

Wrapping Up

In this article, we looked into the current state, the existing implementations, and the future possibilities of reporting Web Vitals for soft navigations.

The comparison table below highlights the main differences between soft navigations vs. hard navigations:

Soft navigationHard navigation
Definitiona page update executed by JavaScripta new HTML page download from the server
URL changedynamic (the URL is updated by JavaScript, e.g. using the React Router package, the browser only ‘sees’ the top-level domain)static (the URL is changed by HTTP, which is the result of real browser-server communication)
Use casessingle page applications created with component-based UI frameworks (e.g. React, Angular, Vue, etc.) or ES6 moduleswebsites, multi page applications
Speedreacts faster to user actionsresponse to user actions takes at least one round-trip to the server
Monitoringhard to track and monitor (no standardized definition and technical implementation of how to detect and measure dynamic URL changes)easy to track and monitor

As I mentioned above, the standardization of soft navigation reporting is still in the early stages. Here are some resources where you can find more information about the current state of the process and contribute if you want to:

Get a monthly email with page speed tips