Technology · Next.js
Next.js Analytics and Monitoring
Integrate analytics, error tracking, and performance monitoring into your Next.js app.
TL;DR
- 01Use web-vitals library to measure Core Web Vitals automatically.
- 02Integrate Sentry to capture and track errors in production.
- 03Add Google Analytics to monitor user behavior and page views.
Web Vitals
- Measure Core Web Vitals with web-vitals library.
// app/layout.tsx import { useEffect } from "react"; export default function RootLayout({ children }) { useEffect(() => { import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { getCLS(console.log); getFID(console.log); getFCP(console.log); getLCP(console.log); getTTFB(console.log); }); }, []); return <html><body>{children}</body></html>; } - Web Vitals measures: CLS, FID, FCP, LCP, TTFB.
- Essential metrics for user experience and SEO.
- Send vitals to a custom analytics endpoint.
import { getCLS, getLCP } from "web-vitals"; function sendToAnalytics({ name, value, id }) { fetch("/api/vitals", { method: "POST", body: JSON.stringify({ name, value, id }) }); } getCLS(sendToAnalytics); getLCP(sendToAnalytics); - Use the built-in reportWebVitals export in Next.js pages.
// app/layout.tsx export function reportWebVitals(metric) { console.log(metric); // { name, value, id, startTime, ... } }
Error Tracking with Sentry
- Integrate Sentry for error monitoring.
npm install @sentry/nextjs - Set up Sentry in your Next.js config.
// next.config.js const { withSentryConfig } = require("@sentry/nextjs"); module.exports = withSentryConfig({ // your Next.js config }, { org: "your-org", project: "your-project", authToken: process.env.SENTRY_AUTH_TOKEN }); - Capture errors automatically on client and server.
import * as Sentry from "@sentry/nextjs"; Sentry.captureException(error); - Capture exceptions inside error boundaries manually.
// app/error.tsx "use client"; import * as Sentry from "@sentry/nextjs"; import { useEffect } from "react"; export default function Error({ error, reset }) { useEffect(() => { Sentry.captureException(error); }, [error]); return <button onClick={reset}>Try again</button>; } - Add user context to Sentry for better debugging.
Sentry.setUser({ id: user.id, email: user.email });
Google Analytics
- Add Google Analytics for user tracking.
// app/layout.tsx import Script from "next/script"; export default function RootLayout({ children }) { return ( <html> <head> <Script src="https://www.googletagmanager.com/gtag/js?id=GA_ID" strategy="afterInteractive" /></Script> </head> <body>{children}</body> </html> ); } - Track page views and custom events.
function trackEvent(name: string) { window.gtag('event', name); } - Track page views on route changes in App Router.
"use client"; import { usePathname } from "next/navigation"; import { useEffect } from "react"; export function Analytics() { const pathname = usePathname(); useEffect(() => { window.gtag?.("event", "page_view", { page_path: pathname }); }, [pathname]); return null; } - Track ecommerce events for purchases and conversions.
function trackPurchase(order) { window.gtag("event", "purchase", { transaction_id: order.id, value: order.total, currency: "USD" }); } - Use Google Tag Manager for managing multiple scripts.
<Script src="https://www.googletagmanager.com/gtm.js?id=GTM-XXXX" strategy="afterInteractive" />
Custom Metrics
- Measure custom metrics with events.
// Track API response times export async function POST(request: Request) { const start = performance.now(); try { const result = await processRequest(request); const duration = performance.now() - start; // Log metric console.log(`Request took ${duration}ms`); return Response.json(result); } catch (error) { Sentry.captureException(error); return Response.json({ error: "Failed" }, { status: 500 }); } } - Send metrics to monitoring service.
async function recordMetric(name: string, value: number) { await fetch("/api/metrics", { method: "POST", body: JSON.stringify({ name, value }) }); } - Store custom metrics in a database via API route.
// app/api/metrics/route.ts export async function POST(request: Request) { const { name, value } = await request.json(); await db.metric.create({ data: { name, value, at: new Date() } }); return Response.json({ ok: true }); } - Track user interactions like button clicks or searches.
function trackSearch(query: string) { fetch("/api/metrics", { method: "POST", body: JSON.stringify({ name: "search", value: query.length }) }); } - Use the Performance API to measure render times.
performance.mark("component-start"); // ... render performance.mark("component-end"); performance.measure("component", "component-start", "component-end");
Performance Monitoring
- Use Lighthouse CI to monitor performance.
npm install -g @lhci/cli@* lhci autorun - Monitor bundle size with package.json scripts.
{ "scripts": { "analyze": "ANALYZE=true npm run build" } } - Set up performance budgets.
// next.config.js const withBundleAnalyzer = require("@next/bundle-analyzer")({ enabled: process.env.ANALYZE === "true" }); - Run Lighthouse CI in a GitHub Actions workflow.
- name: Run Lighthouse CI run: lhci autorun env: LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_TOKEN }} - Set performance score thresholds to fail CI on regressions.
{ "assert": { "assertions": { "categories:performance": ["error", { "minScore": 0.9 }] } } }
Tip: Use web-vitals and Sentry together for complete visibility into user experience and error rates.
Warning: Be mindful of privacy when tracking user data — follow GDPR and CCPA regulations when storing user information.