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 to automatically collect and visualize metrics for you.
For more advanced analytics and monitoring needs, Next.js provides a instrumentation-client.js|ts file that runs before your application's frontend code starts executing. This is ideal for setting up global analytics, error tracking, or performance monitoring tools.
To use it, create an instrumentation-client.js or instrumentation-client.ts file in your application's root directory:
instrumentation-client.js
// Initialize analytics before the app startsconsole.log('Analytics initialized')// Set up global error trackingwindow.addEventListener('error', (event) => { // Send to your error tracking service reportError(event.error)})
'use client'import { useReportWebVitals } from 'next/web-vitals'export function WebVitals() { useReportWebVitals((metric) => { console.log(metric) })}
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.
You can send results to any endpoint to measure and track
real user performance on your site. For example:
useReportWebVitals((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.)
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. })})