Next.js Advanced Config
How Highlight captures Next.js errors
| Page Router | App Router | |
|---|---|---|
| API Errors | PageRouterHighlight | AppRouterHighlight |
| SSR Errors | pages/_error.tsx | app/error.tsx |
| Client | <HighlightInit /> | <HighlightInit /> |
| Edge runtime | EdgeHighlight | EdgeHighlight |
Our Next.js SDK gives you access to frontend session replays and server-side monitoring, all-in-one.
- On the frontend, the
<HighlightInit/>component sets up client-side session replays.
- On the backend, the
PageRouterHighlightwrapper exported from@highlight-run/next/servercaptures server-side errors and logs from Page Router API endpoints.
- On the backend, the
AppRouterHighlightwrapper exported from@highlight-run/next/app-routercaptures errors and logs from App Router API endpoints.
- The
EdgeHighlightwrapper exported from@highlight-run/next/servercaptures server-side errors and logs from both Page and App Router endpoints using Vercel's Edge runtime.
- Use
pages/_error.tsxandapp/error.tsxto forward Page Router and App Router SSR errors from the client to Highlight.
- The
withHighlightConfigconfiguration wrapper automatically proxies Highlight data to bypass ad-blockers and uploads source maps so your frontend errors include stack traces to your source code.
How Highlight captures Next.js logs
<HighlightInit /> captures front-end logs.
PageRouterHighlight and AppRouterHighlight capture server-side logs in traditional server runtimes. These wrappers typically fail in serverless runtimes (including Vercel), because we cannot guarantee that the serverless process will stay alive long enough to send all log data to Highlight.
Configure logging for your serverless cloud provider using one of our cloud provider logging guides, including Vercel Log Drain for Highlight.
Tracing Auto-instrumentation
Open Telemetry auto-instrumentation supports a wide array of packages.
Follow the Open Telemetry Instrumentation Initialization guide to initialize any of these supported library and framework..
Custom Tracing Spans
The Next.js Open Telemetry docs have some tips and patterns for using custom spans.
We went ahead and exposed H.startActiveSpan from @highlight-run/next/server to automatically integrate into our Next.js SDK. Wrap your API endpoints as always, then kick off spans as needed. Each span will be wrapped under a custom Highlight span that tracks session and request data, automatically tying your custom spans into the broader request context that Highlight is already tracking.
Here's a quick example:
// pages/api/page-router-trace.ts import { NextApiRequest, NextApiResponse } from 'next' import { withPageRouterHighlight } from '@/app/_utils/page-router-highlight.config' import { H } from '@highlight-run/next/server' export default withPageRouterHighlight(async function handler( req: NextApiRequest, res: NextApiResponse, ) { return new Promise<void>(async (resolve) => { const span = await H.startActiveSpan('page-router-span', {}) console.info('Here: /pages/api/page-router-trace.ts ⌚⌚⌚') res.send(`Trace sent! Check out this random number: ${Math.random()}`) span.end() resolve() }) })
// app/api/app-router-trace/route.ts import { NextRequest, NextResponse } from 'next/server' import { withAppRouterHighlight } from '@/app/_utils/app-router-highlight.config' import { H } from '@highlight-run/next/server' export const GET = withAppRouterHighlight(async function GET( request: NextRequest, ) { return new Promise(async (resolve) => { const span = await H.startActiveSpan('app-router-span', {}) console.info('Here: /pages/api/app-router-trace/route.ts ⏰⏰⏰') span.end() resolve(new Response('Success: /api/app-router-trace')) }) })
Environment variables
This section is extra opinionated about Next.js constants. It's not for everyone. We like how
zodand TypeScript work together to validateprocess.envinputs... but this is a suggestion. Do your own thing and replace our imports (import { CONSTANTS } from 'src/constants') with your own!
- Install Zod:
npm install zod
- Edit
.envto add your projectID toNEXT_PUBLIC_HIGHLIGHT_PROJECT_ID
# .env NEXT_PUBLIC_HIGHLIGHT_PROJECT_ID='<API KEY>'
- Feed your environment variables into the application with a constants file. We're using
zodfor this example, because it creates a validated, typedCONSTANTSobject that plays nicely with TypeScript.
// constants.ts import { z } from 'zod'; // Must assign NEXT_PUBLIC_* env vars to a variable to force Next to inline them const publicEnv = { NEXT_PUBLIC_HIGHLIGHT_PROJECT_ID: process.env.NEXT_PUBLIC_HIGHLIGHT_PROJECT_ID, }; export const CONSTANTS = z .object({ NEXT_PUBLIC_HIGHLIGHT_PROJECT_ID: z.string(), }) .parse(publicEnv);
Vercel Log Drain
Install our Vercel + Highlight Integration to enable Vercel Log Drain on your project.
Our API wrappers automatically send logs to Highlight in all runtime environments, but Vercel shuts down its Node.js and Edge processes so quickly that log messages are often lost.
Vercel Log Drain is a reliable way to capture those logs.
Next.js plugin
Proxy your front-end Highlight calls by adding withHighlightConfig to your next.config. Frontend session recording and error capture data will be piped through your domain on /highlight-events to sneak Highlight network traffic past ad-blockers.
The following example demonstrates both private source maps and the request proxy. withHighlightConfig does not require a second argument if you are only using the request proxy.
Request proxy only
// next.config.js const { withHighlightConfig } = require('@highlight-run/next/config') /** @type {import('next').NextConfig} */ const nextConfig = { experimental: { serverComponentsExternalPackages: ['@highlight-run/node'], }, productionBrowserSourceMaps: true, // optionally ship source maps to production } module.exports = withHighlightConfig(nextConfig)
Private source maps + request proxy
-
Get your Highlight API key from your project settings. You can also enable the Highlight + Vercel integration to inject
HIGHLIGHT_SOURCEMAP_UPLOAD_API_KEYdirectly into your Vercel environment.
-
Verify that
HIGHLIGHT_SOURCEMAP_UPLOAD_API_KEY=<apiKey>is set in your environment variables--try.env.localfor testing purposes--or passapiKeyin as an optional argument towithHighlightConfig.
-
Ensure that
productionBrowserSourceMapsis eitherfalseor omitted.
-
Wrap your
nextConfigwithwithHighlightConfig.apiKeyis unnecessary if you haveHIGHLIGHT_SOURCEMAP_UPLOAD_API_KEYin your environment variables.
-
Run
npm run build && npm run startto test. Your logs should show files uploading like so:
Uploaded /root/dev/highlight/next-test/.next/server/pages/index.js
// next.config.js const { withHighlightConfig } = require('@highlight-run/next/config') /** @type {import('next').NextConfig} */ const nextConfig = { experimental: { serverComponentsExternalPackages: ['@highlight-run/node'], }, productionBrowserSourceMaps: false, } module.exports = withHighlightConfig(nextConfig, { apiKey: '<API KEY>', uploadSourceMaps: true, })
Configure inlineImages
We use a package called rrweb to record web sessions. rrweb supports inlining images into sessions to improve replay accuracy, so that images that are only available from your local network can be saved; however, the inlined images can cause CORS issues in some situations.
We currently default inlineImages to true on localhost. Explicitly set inlineImages={false} if you run into trouble loading images on your page while Highlight is running. This will degrade tracking on localhost and other domains that are inaccessible to app.highlight.io.
Configure tracingOrigins and networkRecording
See Fullstack Mapping for details on how to associate your back-end errors to client sessions.