instrumentation-client.js
Source URL: https://nextjs.org/docs/app/api-reference/file-conventions/instrumentation-client
instrumentation-client.js
Section titled “instrumentation-client.js”The instrumentation-client.js|ts file allows you to add monitoring, analytics code, and other side-effects that run before your application becomes interactive. This is useful for setting up performance tracking, error monitoring, polyfills, or any other client-side observability tools.
To use it, place the file in the root of your application or inside a src folder.
Unlike server-side instrumentation, you do not need to export any specific functions. You can write your monitoring code directly in the file:
// Set up performance monitoringperformance.mark('app-init')
// Initialize analyticsconsole.log('Analytics initialized')
// Set up error trackingwindow.addEventListener('error', (event) => { // Send to your error tracking service reportError(event.error)})// Set up performance monitoringperformance.mark('app-init')
// Initialize analyticsconsole.log('Analytics initialized')
// Set up error trackingwindow.addEventListener('error', (event) => { // Send to your error tracking service reportError(event.error)})Error handling: Implement try-catch blocks around your instrumentation code to ensure robust monitoring. This prevents individual tracking failures from affecting other instrumentation features.
Router navigation tracking
Section titled “Router navigation tracking”You can export an onRouterTransitionStart function to receive notifications when navigation begins:
performance.mark('app-init')
export function onRouterTransitionStart( url: string, navigationType: 'push' | 'replace' | 'traverse') { console.log(`Navigation started: ${navigationType} to ${url}`) performance.mark(`nav-start-${Date.now()}`)}performance.mark('app-init')
export function onRouterTransitionStart(url, navigationType) { console.log(`Navigation started: ${navigationType} to ${url}`) performance.mark(`nav-start-${Date.now()}`)}The onRouterTransitionStart function receives two parameters:
url: string- The URL being navigated tonavigationType: 'push' | 'replace' | 'traverse'- The type of navigation
Performance considerations
Section titled “Performance considerations”Keep instrumentation code lightweight.
Next.js monitors initialization time in development and will log warnings if it takes longer than 16ms, which could impact smooth page loading.
Execution timing
Section titled “Execution timing”The instrumentation-client.js file executes at a specific point in the application lifecycle:
- After the HTML document is loaded
- Before React hydration begins
- Before user interactions are possible
This timing makes it ideal for setting up error tracking, analytics, and performance monitoring that needs to capture early application lifecycle events.
Examples
Section titled “Examples”Error tracking
Section titled “Error tracking”Initialize error tracking before React starts and add navigation breadcrumbs for better debugging context.
import Monitor from './lib/monitoring'
Monitor.initialize()
export function onRouterTransitionStart(url: string) { Monitor.pushEvent({ message: `Navigation to ${url}`, category: 'navigation', })}import Monitor from './lib/monitoring'
Monitor.initialize()
export function onRouterTransitionStart(url) { Monitor.pushEvent({ message: `Navigation to ${url}`, category: 'navigation', })}Analytics tracking
Section titled “Analytics tracking”Initialize analytics and track navigation events with detailed metadata for user behavior analysis.
import { analytics } from './lib/analytics'
analytics.init()
export function onRouterTransitionStart(url: string, navigationType: string) { analytics.track('page_navigation', { url, type: navigationType, timestamp: Date.now(), })}import { analytics } from './lib/analytics'
analytics.init()
export function onRouterTransitionStart(url, navigationType) { analytics.track('page_navigation', { url, type: navigationType, timestamp: Date.now(), })}Performance monitoring
Section titled “Performance monitoring”Track Time to Interactive and navigation performance using the Performance Observer API and performance marks.
const startTime = performance.now()
const observer = new PerformanceObserver( (list: PerformanceObserverEntryList) => { for (const entry of list.getEntries()) { if (entry instanceof PerformanceNavigationTiming) { console.log('Time to Interactive:', entry.loadEventEnd - startTime) } } })
observer.observe({ entryTypes: ['navigation'] })
export function onRouterTransitionStart(url: string) { performance.mark(`nav-start-${url}`)}const startTime = performance.now()
const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (entry instanceof PerformanceNavigationTiming) { console.log('Time to Interactive:', entry.loadEventEnd - startTime) } }})
observer.observe({ entryTypes: ['navigation'] })
export function onRouterTransitionStart(url) { performance.mark(`nav-start-${url}`)}Polyfills
Section titled “Polyfills”Load polyfills before application code runs. Use static imports for immediate loading and dynamic imports for conditional loading based on feature detection.
import './lib/polyfills'
if (!window.ResizeObserver) { import('./lib/polyfills/resize-observer').then((mod) => { window.ResizeObserver = mod.default })}import './lib/polyfills'
if (!window.ResizeObserver) { import('./lib/polyfills/resize-observer').then((mod) => { window.ResizeObserver = mod.default })}Version history
Section titled “Version history”| Version | Changes |
|---|---|
v15.3 | instrumentation-client introduced |