Skip to content

Commit 0cdddd4

Browse files
authored
docs: update analytics docs for useReportWebVitals (#58196)
[This page](https://nextjs.org/docs/app/building-your-application/optimizing/analytics) was not yet mentioning `useReportWebVitals`. Closes #57715.
1 parent 4024b25 commit 0cdddd4

File tree

1 file changed

+115
-117
lines changed

1 file changed

+115
-117
lines changed

docs/02-app/01-building-your-application/06-optimizing/07-analytics.mdx

Lines changed: 115 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,62 @@ description: Measure and track page performance using Next.js Speed Insights
55

66
{/* 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. */}
77

8-
[Next.js Speed Insights](https://nextjs.org/analytics) allows you to analyze and measure the performance of
9-
pages using different metrics.
10-
11-
You can start collecting your [Real Experience Score](https://vercel.com/docs/concepts/speed-insights#core-web-vitals-explained?utm_source=next-site&utm_medium=docs&utm_campaign=next-website) with zero-configuration on [Vercel deployments](https://vercel.com/docs/concepts/speed-insights?utm_source=next-site&utm_medium=docs&utm_campaign=next-website).
12-
13-
The rest of this documentation describes the built-in relayer Next.js Speed Insights uses.
14-
15-
<PagesOnly>
8+
Next.js has built-in support for measuring and reporting performance metrics. You can either use the `useReportWebVitals` hook to manage reporting yourself, or alternatively, Vercel provides a [managed service](https://vercel.com/analytics?utm_source=next-site&utm_medium=docs&utm_campaign=next-website) to automatically collect and visualize metrics for you.
169

1710
## Build Your Own
1811

19-
First, you will need to create a [custom App](/docs/pages/building-your-application/routing/custom-app) component and define a `reportWebVitals` function:
12+
<PagesOnly>
2013

2114
```jsx filename="pages/_app.js"
22-
export function reportWebVitals(metric) {
23-
console.log(metric)
24-
}
15+
import { useReportWebVitals } from 'next/web-vitals'
2516

2617
function MyApp({ Component, pageProps }) {
18+
useReportWebVitals((metric) => {
19+
console.log(metric)
20+
})
21+
2722
return <Component {...pageProps} />
2823
}
29-
30-
export default MyApp
3124
```
3225

33-
This function is fired when the final values for any of the metrics have finished calculating on
34-
the page. You can use to log any of the results to the console or send to a particular endpoint.
26+
View the [API Reference](/docs/pages/api-reference/functions/use-report-web-vitals) for more information.
27+
28+
</PagesOnly>
3529

36-
The `metric` object returned to the function consists of a number of properties:
30+
<AppOnly>
3731

38-
- `id`: Unique identifier for the metric in the context of the current page load
39-
- `name`: Metric name
40-
- `startTime`: First recorded timestamp of the performance entry in [milliseconds](https://developer.mozilla.org/docs/Web/API/DOMHighResTimeStamp) (if applicable)
41-
- `value`: Value, or duration in [milliseconds](https://developer.mozilla.org/docs/Web/API/DOMHighResTimeStamp), of the performance entry
42-
- `label`: Type of metric (`web-vital` or `custom`)
32+
```jsx filename="app/_components/web-vitals.js"
33+
'use client'
4334

44-
There are two types of metrics that are tracked:
35+
import { useReportWebVitals } from 'next/web-vitals'
4536

46-
- Web Vitals
47-
- Custom metrics
37+
export function WebVitals() {
38+
useReportWebVitals((metric) => {
39+
console.log(metric)
40+
})
41+
}
42+
```
4843

49-
</PagesOnly>
44+
```jsx filename="app/layout.js"
45+
import { WebVitals } from './_components/web-vitals'
46+
47+
export default function Layout({ children }) {
48+
return (
49+
<html>
50+
<body>
51+
<WebVitals />
52+
{children}
53+
</body>
54+
</html>
55+
)
56+
}
57+
```
58+
59+
> 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.
60+
61+
View the [API Reference](/docs/app/api-reference/functions/use-report-web-vitals) for more information.
62+
63+
</AppOnly>
5064

5165
## Web Vitals
5266

@@ -58,55 +72,81 @@ experience of a web page. The following web vitals are all included:
5872
- [Largest Contentful Paint](https://web.dev/lcp/) (LCP)
5973
- [First Input Delay](https://web.dev/fid/) (FID)
6074
- [Cumulative Layout Shift](https://web.dev/cls/) (CLS)
61-
- [Interaction to Next Paint](https://web.dev/inp/) (INP) _(experimental)_
75+
- [Interaction to Next Paint](https://web.dev/inp/) (INP)
76+
77+
You can handle all the results of these metrics using the `name` property.
6278

6379
<PagesOnly>
6480

65-
You can handle all the results of these metrics using the `web-vital` label:
81+
```jsx filename="pages/_app.js"
82+
import { useReportWebVitals } from 'next/web-vitals'
6683

67-
```js
68-
export function reportWebVitals(metric) {
69-
if (metric.label === 'web-vital') {
70-
console.log(metric) // The metric object ({ id, name, startTime, value, label }) is logged to the console
71-
}
84+
function MyApp({ Component, pageProps }) {
85+
useReportWebVitals((metric) => {
86+
switch (metric.name) {
87+
case 'FCP': {
88+
// handle FCP results
89+
}
90+
case 'LCP': {
91+
// handle LCP results
92+
}
93+
// ...
94+
}
95+
})
96+
97+
return <Component {...pageProps} />
7298
}
7399
```
74100

75-
There's also the option of handling each of the metrics separately:
101+
</PagesOnly>
76102

77-
```js
78-
export function reportWebVitals(metric) {
79-
switch (metric.name) {
80-
case 'FCP':
81-
// handle FCP results
82-
break
83-
case 'LCP':
84-
// handle LCP results
85-
break
86-
case 'CLS':
87-
// handle CLS results
88-
break
89-
case 'FID':
90-
// handle FID results
91-
break
92-
case 'TTFB':
93-
// handle TTFB results
94-
break
95-
case 'INP':
96-
// handle INP results (note: INP is still an experimental metric)
97-
break
98-
default:
99-
break
100-
}
103+
<AppOnly>
104+
105+
```tsx filename="app/components/web-vitals.tsx" switcher
106+
'use client'
107+
108+
import { useReportWebVitals } from 'next/web-vitals'
109+
110+
export function WebVitals() {
111+
useReportWebVitals((metric) => {
112+
switch (metric.name) {
113+
case 'FCP': {
114+
// handle FCP results
115+
}
116+
case 'LCP': {
117+
// handle LCP results
118+
}
119+
// ...
120+
}
121+
})
101122
}
102123
```
103124

104-
A third-party library, [web-vitals](https://github.com/GoogleChrome/web-vitals), is used to measure
105-
these metrics. Browser compatibility depends on the particular metric, so refer to the [Browser
106-
Support](https://github.com/GoogleChrome/web-vitals#browser-support) section to find out which
107-
browsers are supported.
125+
```jsx filename="app/components/web-vitals.js" switcher
126+
'use client'
127+
128+
import { useReportWebVitals } from 'next/web-vitals'
129+
130+
export function WebVitals() {
131+
useReportWebVitals((metric) => {
132+
switch (metric.name) {
133+
case 'FCP': {
134+
// handle FCP results
135+
}
136+
case 'LCP': {
137+
// handle LCP results
138+
}
139+
// ...
140+
}
141+
})
142+
}
143+
```
144+
145+
</AppOnly>
146+
147+
<PagesOnly>
108148

109-
## Custom metrics
149+
## Custom Metrics
110150

111151
In addition to the core metrics listed above, there are some additional custom metrics that
112152
measure the time it takes for the page to hydrate and render:
@@ -116,17 +156,7 @@ measure the time it takes for the page to hydrate and render:
116156
route change (in ms)
117157
- `Next.js-render`: Length of time it takes for a page to finish render after a route change (in ms)
118158

119-
You can handle all the results of these metrics using the `custom` label:
120-
121-
```js
122-
export function reportWebVitals(metric) {
123-
if (metric.label === 'custom') {
124-
console.log(metric) // The metric object ({ id, name, startTime, value, label }) is logged to the console
125-
}
126-
}
127-
```
128-
129-
There's also the option of handling each of the metrics separately:
159+
You can handle all the results of these metrics separately:
130160

131161
```js
132162
export function reportWebVitals(metric) {
@@ -148,13 +178,15 @@ export function reportWebVitals(metric) {
148178

149179
These metrics work in all browsers that support the [User Timing API](https://caniuse.com/#feat=user-timing).
150180

181+
</PagesOnly>
182+
151183
## Sending results to external systems
152184

153-
With the relay function, you can send results to any endpoint to measure and track
185+
You can send results to any endpoint to measure and track
154186
real user performance on your site. For example:
155187

156188
```js
157-
export function reportWebVitals(metric) {
189+
useReportWebVitals((metric) => {
158190
const body = JSON.stringify(metric)
159191
const url = 'https://example.com/analytics'
160192

@@ -164,57 +196,23 @@ export function reportWebVitals(metric) {
164196
} else {
165197
fetch(url, { body, method: 'POST', keepalive: true })
166198
}
167-
}
199+
})
168200
```
169201

170202
> **Good to know**: If you use [Google Analytics](https://analytics.google.com/analytics/web/), using the
171203
> `id` value can allow you to construct metric distributions manually (to calculate percentiles,
172204
> etc.)
173-
>
205+
174206
> ```js
175-
> export function reportWebVitals({ id, name, label, value }) {
207+
> useReportWebVitals(metric => {
176208
> // Use `window.gtag` if you initialized Google Analytics as this example:
177209
> // https://github.com/vercel/next.js/blob/canary/examples/with-google-analytics/pages/_app.js
178-
> window.gtag('event', name, {
179-
> event_category:
180-
> label === 'web-vital' ? 'Web Vitals' : 'Next.js custom metric',
181-
> value: Math.round(name === 'CLS' ? value * 1000 : value), // values must be integers
182-
> event_label: id, // id unique to current page load
210+
> window.gtag('event', metric.name, {
211+
> value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value), // values must be integers
212+
> event_label: metric.id, // id unique to current page load
183213
> non_interaction: true, // avoids affecting bounce rate.
184-
> })
214+
> });
185215
> }
186216
> ```
187217
>
188218
> Read more about [sending results to Google Analytics](https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics).
189-
190-
## TypeScript
191-
192-
If you are using TypeScript, you can use the built-in type `NextWebVitalsMetric`:
193-
194-
```tsx filename="pages/_app.tsx" switcher
195-
import type { AppProps, NextWebVitalsMetric } from 'next/app'
196-
197-
function MyApp({ Component, pageProps }: AppProps) {
198-
return <Component {...pageProps} />
199-
}
200-
201-
export function reportWebVitals(metric: NextWebVitalsMetric) {
202-
console.log(metric)
203-
}
204-
205-
export default MyApp
206-
```
207-
208-
```jsx filename="pages/_app.js" switcher
209-
function MyApp({ Component, pageProps }) {
210-
return <Component {...pageProps} />
211-
}
212-
213-
export function reportWebVitals(metric) {
214-
console.log(metric)
215-
}
216-
217-
export default MyApp
218-
```
219-
220-
</PagesOnly>

0 commit comments

Comments
 (0)