Technology · Next.js

Next.js Analytics and Monitoring

Integrate analytics, error tracking, and performance monitoring into your Next.js app.

TL;DR
  1. 01Use web-vitals library to measure Core Web Vitals automatically.
  2. 02Integrate Sentry to capture and track errors in production.
  3. 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 id="google-analytics" strategy="afterInteractive">
              {`
                window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'GA_ID');
              `}
            </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.

Next.js TestingNext.js API Routes Patterns