This function is fired when the final values for any of the metrics have finished calculating on
the page. You can use to log any of the results to the console or send to a particular endpoint.
The metric object returned to the function consists of a number of properties:
id: Unique identifier for the metric in the context of the current page load
name: Metric name
startTime: First recorded timestamp of the performance entry in milliseconds (if applicable)
value: Value, or duration in milliseconds, of the performance entry
You can handle all the results of these metrics using the web-vital label:
export function reportWebVitals(metric) { if (metric.label === 'web-vital') { console.log(metric) // The metric object ({ id, name, startTime, value, label }) is logged to the console }}
There's also the option of handling each of the metrics separately:
export function reportWebVitals(metric) { switch (metric.name) { case 'FCP': // handle FCP results break case 'LCP': // handle LCP results break case 'CLS': // handle CLS results break case 'FID': // handle FID results break case 'TTFB': // handle TTFB results break case 'INP': // handle INP results (note: INP is still an experimental metric) break default: break }}
A third-party library, web-vitals, is used to measure
these metrics. Browser compatibility depends on the particular metric, so refer to the Browser
Support section to find out which
browsers are supported.
In addition to the core metrics listed above, there are some additional custom metrics that
measure the time it takes for the page to hydrate and render:
Next.js-hydration: Length of time it takes for the page to start and finish hydrating (in ms)
Next.js-route-change-to-render: Length of time it takes for a page to start rendering after a
route change (in ms)
Next.js-render: Length of time it takes for a page to finish render after a route change (in ms)
You can handle all the results of these metrics using the custom label:
export function reportWebVitals(metric) { if (metric.label === 'custom') { console.log(metric) // The metric object ({ id, name, startTime, value, label }) is logged to the console }}
There's also the option of handling each of the metrics separately:
export function reportWebVitals(metric) { switch (metric.name) { case 'Next.js-hydration': // handle hydration results break case 'Next.js-route-change-to-render': // handle route-change to render results break case 'Next.js-render': // handle render results break default: break }}
These metrics work in all browsers that support the User Timing API.
With the relay function, you can send results to any endpoint to measure and track
real user performance on your site. For example:
export function reportWebVitals(metric) { const body = JSON.stringify(metric) const url = 'https://example.com/analytics' // Use `navigator.sendBeacon()` if available, falling back to `fetch()`. if (navigator.sendBeacon) { navigator.sendBeacon(url, body) } else { fetch(url, { body, method: 'POST', keepalive: true }) }}
Good to know: If you use Google Analytics, using the
id value can allow you to construct metric distributions manually (to calculate percentiles,
etc.)
export function reportWebVitals({ id, name, label, value }) { // Use `window.gtag` if you initialized Google Analytics as this example: // https://github.com/vercel/next.js/blob/canary/examples/with-google-analytics/pages/_app.js window.gtag('event', name, { event_category: label === 'web-vital' ? 'Web Vitals' : 'Next.js custom metric', value: Math.round(name === 'CLS' ? value * 1000 : value), // values must be integers event_label: id, // id unique to current page load non_interaction: true, // avoids affecting bounce rate. })}