Next.js OpenTelemetry instrumentation
Next.js loads OpenTelemetry through its built-in instrumentation.ts hook rather than the --require flag used by other Node.js frameworks. Because Next.js bundles server code and runs some routes on the Edge runtime, the supported path is the @vercel/otel package, which configures the SDK for both runtimes and sends traces, metrics, and logs to Osuite over OTLP.
Prerequisites
Section titled “Prerequisites”- Next.js 15 or newer (App Router or Pages Router). On Next.js 13.4–14 the instrumentation hook is behind a flag — see the note below.
- Node.js 18 or newer.
- An Osuite ingest token from Settings → API Keys.
Instrument the app
Section titled “Instrument the app”-
Install the package
Terminal window npm install @vercel/otel@vercel/otelbundles the OpenTelemetry SDK and OTLP exporters, so no separate exporter packages are required. -
Create the instrumentation hook
Create
instrumentation.tsin your project root (or insidesrc/if you use asrcdirectory). Next.js calls the exportedregisterfunction once when the server starts.instrumentation.ts import { registerOTel } from '@vercel/otel';export function register() {registerOTel({ serviceName: 'storefront' });}
Configure and run
Section titled “Configure and run”@vercel/otel reads the OTLP endpoint and headers from environment variables and defaults to the HTTP/protobuf transport:
OTEL_EXPORTER_OTLP_ENDPOINT— your Osuite ingest endpoint.OTEL_EXPORTER_OTLP_HEADERS— thex-osuite-ingest-tokenheader that authenticates ingestion.OTEL_SERVICE_NAME— the service name that identifies this service in Osuite. Set it to the same name passed asserviceNamein theregistercall above (storefront); if the two disagree, your telemetry is split across two services in Osuite.OTEL_RESOURCE_ATTRIBUTES— additional resource attributes such asservice.environment.
Build the app (npm run build) and start it. Choose your deployment target:
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.osuite.io:443"export OTEL_EXPORTER_OTLP_HEADERS="x-osuite-ingest-token=<your-ingest-token>"export OTEL_SERVICE_NAME="storefront"export OTEL_RESOURCE_ATTRIBUTES="service.environment=production"
npm run start# DockerfileFROM node:22-slimWORKDIR /appCOPY package*.json ./RUN npm ciCOPY . .RUN npm run buildCMD ["npm", "run", "start"]Pass the configuration at run time so the ingest token never lands in the image:
docker run \ -e OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.osuite.io:443" \ -e OTEL_EXPORTER_OTLP_HEADERS="x-osuite-ingest-token=<your-ingest-token>" \ -e OTEL_SERVICE_NAME="storefront" \ -e OTEL_RESOURCE_ATTRIBUTES="service.environment=production" \ storefrontStore the ingest token in a Secret:
kubectl create secret generic osuite-ingest \ --from-literal=otlp-headers="x-osuite-ingest-token=<your-ingest-token>"Reference it from the Deployment:
apiVersion: apps/v1kind: Deploymentmetadata: name: storefrontspec: replicas: 1 selector: matchLabels: app: storefront template: metadata: labels: app: storefront spec: containers: - name: storefront image: storefront:latest command: ["npm", "run", "start"] env: - name: OTEL_EXPORTER_OTLP_ENDPOINT value: "https://ingest.<region>.osuite.io:443" - name: OTEL_EXPORTER_OTLP_HEADERS valueFrom: secretKeyRef: name: osuite-ingest key: otlp-headers - name: OTEL_SERVICE_NAME value: "storefront" - name: OTEL_RESOURCE_ATTRIBUTES value: "service.environment=production"Framework notes
Section titled “Framework notes”Verify in Osuite
Section titled “Verify in Osuite”What you should see
Load a page or call a route handler, then open APM. The storefront service appears within a minute, emitting request-rate and latency metrics. Opening a trace shows the inbound request span with child spans for server-side data fetches and outbound calls.
Troubleshooting
Section titled “Troubleshooting”No data in Osuite after a few minutes? Work through these checks.
- Endpoint — confirm the exporter targets exactly
ingest.<region>.osuite.io:443for your region, over TLS. - Token — confirm the ingest header carries a valid
<your-ingest-token>and has not been rotated. - Pipeline — confirm the signal you expect (traces, logs, or metrics) is wired into an active pipeline with the
otlp/osuiteexporter attached. - Export errors — check the application or Collector logs for OTLP export failures (auth, DNS, TLS, connection refused).
- Network — confirm the host has outbound access to the ingest endpoint on port
443. - Timing — allow up to a minute for the first data to appear before assuming a failure.
Still stuck? Ask the Investigation Agent or contact support.
For Node-specific issues — including why the instrumentation hook may not fire — see Node.js troubleshooting.
Next steps
Section titled “Next steps”- Add custom spans and metrics inside your route handlers and server actions.
- Instrument the browser with Real User Monitoring.
- Correlate application logs with traces.