NextJS Core Web Vitals - measure the Core Web Vitals

The ultimate Next.js Core Web Vitals guide - how to measure the Core Web Vitals in Next.js

Arjen Karel Core Web Vitals Consultant
Arjen Karel
linkedin

Measure the Core Web Vitals in NextJS

Next.js is a JavaScript framework on top of REACT that enables you to build superfast and extremely user-friendly websites. That is true, Next.js is pretty fast and has a lot of features built in to ensure it stays fast. At least ....., in theory. Over time, as your website grows and more features get added and maybe when not all best-practices are followed Next.js pages will become slower and slower. That is probably why you are visiting this page :-)

To measure and prevent slow pages it is important to measure the Core Web Vitals and take action when a Core Vitals metric is below a threshold.

What are the Core Web Vitals?

The Core Web Vitals are the subset of Web Vitals that apply to all web pages, should be measured by all site owners, and will be surfaced across all Google tools. Each of the Core Web Vitals represents a distinct facet of the user experience, is measurable in the field, and reflects the real-world experience of a critical user-centric outcome.

The metrics that make up Core Web Vitals will evolve over time. The current set for 2020 focuses on three aspects of the user experience—loading, interactivity, and visual stability—and includes the following metrics (and their respective thresholds):

Largest Contentful Paint (LCP): measures loading performance. To provide a good user experience, LCP should occur within 2.5 seconds of when the page first starts loading.

First Input Delay (FID): measures interactivity. To provide a good user experience, pages should have a FID of 100 milliseconds or less.

Cumulative Layout Shift (CLS): measures visual stability. To provide a good user experience, pages should maintain a CLS of 0.1. or less.

Forget about lighthouse (sort of)

Lighthouse is a testing tool for the Core Web Vitals. Almost every client that I work for will, at some point, start talking about their lighthouse scores and how they do not match up with their Search Console Scores. The first thing I tell them is this: forget about lighthouse. I will explain:

lighthouse 100 score

Lighthouse is a very useful tool that gathers 'lab-data' for a non-cached first time visit under regulated conditions. Unfortunately the data gathered does not necessarily reflect the field data. Field data is collected by the browser every time a user loads one of your pages. That data is then send to Google and used for determining your actual Core Web Vitals scores. This process is also called real-user monitoring (RUM).

Now do not get me wrong: I love lighthouse. It is a masterful piece of software and it will give you great suggestions that you should probably implement. What I am saying is that the RUM metrics on a Next.js site are not merely made up out of first time, uncached views and of visitors that do not interact with your website (lighthouse does not interact with your website!)

No, the Core Web Vitals on a Next.js website are more complicated. That is why one of the first things I implement for my clients is real-time real user monitoring.

Set up Core Web Vitals Real-time real user monitoring

Collecting the Core Web Vitals data in Next.js is simple as Next.js provides a built-in method for capturing the Core Web Vitals. All you need to do is export the function reportWebVitals in _app.tsx and you are done.

export function reportWebVitals(metric: NextWebVitalsMetric) {
  if (metric.label === 'web-vital') {
    console.log(metric); 
     // The metric object ({ id, name, startTime, value, label }) is logged to the console
  }
}

Now on high traffic websites it will make little sense to collect all the data from all users. We can easily sample 50% or less like this:

const bInSample: boolean =  (Math.random() >= 0.5);

export function reportWebVitals(metric: NextWebVitalsMetric) {
  if (metric.label === 'web-vital' && bInSample) {
  	console.log(metric)
  }
}

Now if we for example want to send the Core Web Vitals metrics to analytics all we need to do is:

export function reportWebVitals(metric: NextWebVitalsMetric) {
  if (metric.label === 'web-vital') {
    window.gtag('event', name, {
      event_category: 'web-vital',
      value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value), // values must be integers
      event_label: metric.id, // id unique to current page load
      non_interaction: true, // avoids affecting bounce rate.
    })  
  }
}

And just as easily we can send the Core Web Vitals to any custom analytics backend:

export function reportWebVitals(metric: NextWebVitalsMetric) {
  const url = 'https://example.com/custom-analytics'

  // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
  if (navigator.sendBeacon) {
    navigator.sendBeacon(url, JSON.stringify(metric))
  } else {
    fetch(url, { JSON.stringify(metric), method: 'POST', keepalive: true })
  }
}

Now remember that when reading the RUM data for the Core Web Vitals you need to use the 75th percentile.

Third party tools that collect Core Web Vitals in Next.js

There are a few third party tools that collect Core Web Vitals in Next.js. For example NewRelic and sentry. Now as a Core Web Vitals guys I am not a fan. Sentry fires some high priority request early in the rendering process and NewRelic also slows down your site considerably. That being said I understand the importance of such tools and if you already use one of these tools they will do a great job of collecting and reporting the Core Web Vitals.s

I help teams pass the Core Web Vitals:

lighthouse 100 score

A slow website is likely to miss out on conversions and revenue. Nearly half of internet searchers don't wait three seconds for a page to load before going to another site. Ask yourself: "Is my site fast enough to convert visitors into customers?"

NextJS Core Web Vitals - measure the Core Web VitalsCore Web Vitals NextJS Core Web Vitals - measure the Core Web Vitals