Files
15fcfb9ce4 docs: fix navigationType value and variable name in useReportWebVitals (#90599)
## For Contributors

### Improving Documentation

- [x] Run `pnpm prettier-fix` to fix formatting issues before opening
the PR.
- [x] Read the Docs Contribution Guide to ensure your contribution
follows the docs guidelines:
https://nextjs.org/docs/community/contribution-guide

### What?

Fix two bugs in the `useReportWebVitals` API reference docs:

1. `navigationType` value `"back_forward"` → `"back-forward"`: the
`web-vitals`
library intentionally renames this value to use a hyphen for
consistency.
2. Variable name mismatch in `handleCustomMetrics` example: parameter
was named
`metrics` (plural) but the function body referenced `metric.name`
(singular),
   causing a `ReferenceError`.

### Why?

The `navigationType` description reflected the raw
`PerformanceNavigationTiming`
API value (`"back_forward"`), not the actual value emitted by the
`web-vitals`
library (`"back-forward"`), which `useReportWebVitals` is built on top
of
Ref: https://github.com/GoogleChrome/web-vitals?tab=readme-ov-file#types

The variable name mismatch in the code example would cause a
`ReferenceError`
if copied as-is.

### How?

- Updated `navigationType` description to use `"back-forward"`.
- Renamed parameter `metrics` → `metric` in the `handleCustomMetrics`
example

---------

Co-authored-by: Joseph <[email protected]>
Co-authored-by: Joseph <[email protected]>
2026-02-27 15:10:29 +01:00

251 lines
8.1 KiB
Plaintext

---
title: useReportWebVitals
description: API Reference for the useReportWebVitals function.
---
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
The `useReportWebVitals` hook allows you to report [Core Web Vitals](https://web.dev/vitals/), and can be used in combination with your analytics service.
New functions passed to `useReportWebVitals` are called with the available metrics up to that point. To prevent reporting duplicated data, ensure that the callback function reference does not change (as shown in the code examples below).
<PagesOnly>
```jsx filename="pages/_app.js"
import { useReportWebVitals } from 'next/web-vitals'
const logWebVitals = (metric) => {
console.log(metric)
}
function MyApp({ Component, pageProps }) {
useReportWebVitals(logWebVitals)
return <Component {...pageProps} />
}
```
</PagesOnly>
<AppOnly>
```jsx filename="app/_components/web-vitals.js"
'use client'
import { useReportWebVitals } from 'next/web-vitals'
const logWebVitals = (metric) => {
console.log(metric)
}
export function WebVitals() {
useReportWebVitals(logWebVitals)
return null
}
```
```jsx filename="app/layout.js"
import { WebVitals } from './_components/web-vitals'
export default function Layout({ children }) {
return (
<html>
<body>
<WebVitals />
{children}
</body>
</html>
)
}
```
> Since the `useReportWebVitals` hook requires the `'use client'` directive, the most performant approach is to create a separate component that the root layout imports. This confines the client boundary exclusively to the `WebVitals` component.
</AppOnly>
## useReportWebVitals
The `metric` object passed as the hook's argument consists of a number of properties:
- `id`: Unique identifier for the metric in the context of the current page load
- `name`: The name of the performance metric. Possible values include names of [Web Vitals](#web-vitals) metrics (TTFB, FCP, LCP, FID, CLS) specific to a web application.
- `delta`: The difference between the current value and the previous value of the metric. The value is typically in milliseconds and represents the change in the metric's value over time.
- `entries`: An array of [Performance Entries](https://developer.mozilla.org/docs/Web/API/PerformanceEntry) associated with the metric. These entries provide detailed information about the performance events related to the metric.
- `navigationType`: Indicates the navigation type that triggered metric collection. Values are derived from [PerformanceNavigationTiming.type](https://developer.mozilla.org/docs/Web/API/PerformanceNavigationTiming/type) and may include `"navigate"`, `"reload"`, `"prerender"`, `"back-forward"` (normalized from `"back_forward"`), `"back-forward-cache"` (BFCache restore), and `"restore"` (page restored after discard).
- `rating`: A qualitative rating of the metric value, providing an assessment of the performance. Possible values are `"good"`, `"needs-improvement"`, and `"poor"`. The rating is typically determined by comparing the metric value against predefined thresholds that indicate acceptable or suboptimal performance.
- `value`: The actual value or duration of the performance entry, typically in milliseconds. The value provides a quantitative measure of the performance aspect being tracked by the metric. The source of the value depends on the specific metric being measured and can come from various [Performance API](https://developer.mozilla.org/docs/Web/API/Performance_API)s.
## Web Vitals
[Web Vitals](https://web.dev/vitals/) are a set of useful metrics that aim to capture the user
experience of a web page. The following web vitals are all included:
- [Time to First Byte](https://developer.mozilla.org/docs/Glossary/Time_to_first_byte) (TTFB)
- [First Contentful Paint](https://developer.mozilla.org/docs/Glossary/First_contentful_paint) (FCP)
- [Largest Contentful Paint](https://web.dev/lcp/) (LCP)
- [First Input Delay](https://web.dev/fid/) (FID)
- [Cumulative Layout Shift](https://web.dev/cls/) (CLS)
- [Interaction to Next Paint](https://web.dev/inp/) (INP)
You can handle all the results of these metrics using the `name` property.
<PagesOnly>
```jsx filename="pages/_app.js"
import { useReportWebVitals } from 'next/web-vitals'
const handleWebVitals = (metric) => {
switch (metric.name) {
case 'FCP': {
// handle FCP results
}
case 'LCP': {
// handle LCP results
}
// ...
}
}
function MyApp({ Component, pageProps }) {
useReportWebVitals(handleWebVitals)
return <Component {...pageProps} />
}
```
</PagesOnly>
<AppOnly>
```tsx filename="app/components/web-vitals.tsx" switcher
'use client'
import { useReportWebVitals } from 'next/web-vitals'
type ReportWebVitalsCallback = Parameters<typeof useReportWebVitals>[0]
const handleWebVitals: ReportWebVitalsCallback = (metric) => {
switch (metric.name) {
case 'FCP': {
// handle FCP results
}
case 'LCP': {
// handle LCP results
}
// ...
}
}
export function WebVitals() {
useReportWebVitals(handleWebVitals)
}
```
```jsx filename="app/components/web-vitals.js" switcher
'use client'
import { useReportWebVitals } from 'next/web-vitals'
const handleWebVitals = (metric) => {
switch (metric.name) {
case 'FCP': {
// handle FCP results
}
case 'LCP': {
// handle LCP results
}
// ...
}
}
export function WebVitals() {
useReportWebVitals(handleWebVitals)
}
```
</AppOnly>
<PagesOnly>
## Custom Metrics
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 separately:
```jsx filename="pages/_app.js"
import { useReportWebVitals } from 'next/web-vitals'
function handleCustomMetrics(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
}
}
function MyApp({ Component, pageProps }) {
useReportWebVitals(handleCustomMetrics)
return <Component {...pageProps} />
}
```
These metrics work in all browsers that support the [User Timing API](https://caniuse.com/#feat=user-timing).
</PagesOnly>
## Sending results to external systems
You can send results to any endpoint to measure and track
real user performance on your site. For example:
```js
function postWebVitals(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 })
}
}
useReportWebVitals(postWebVitals)
```
> **Good to know**: If you use [Google Analytics](https://analytics.google.com/analytics/web/), using the
> `id` value can allow you to construct metric distributions manually (to calculate percentiles,
> etc.)
> ```js
> useReportWebVitals(metric => {
> // Use `window.gtag` if you initialized Google Analytics as this example:
> // https://github.com/vercel/next.js/blob/canary/examples/with-google-analytics
> window.gtag('event', metric.name, {
> 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.
> });
> }
> ```
>
> Read more about [sending results to Google Analytics](https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics).