Skip to content

Node.js ​

Automatic traces, metrics and logs for Express, Fastify, NestJS, Koa, Next.js, http, fetch, Postgres, MySQL, Redis, MongoDB and more, without changing your code.

Before you start

You need a stream and ingest key for each signal. See OpenTelemetry → Before you start.

1. Install ​

bash
npm install @opentelemetry/api @opentelemetry/auto-instrumentations-node

2. Configure ​

Add these to your environment (or .env):

bash
OTEL_SERVICE_NAME=checkout-api
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://ws.latency.app/v1/telemetry/traces
OTEL_EXPORTER_OTLP_TRACES_HEADERS=authorization=Bearer%20lit_your_traces_key

OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://ws.latency.app/v1/telemetry/metrics
OTEL_EXPORTER_OTLP_METRICS_HEADERS=authorization=Bearer%20lit_your_metrics_key
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta

OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://ws.latency.app/v1/telemetry/logs
OTEL_EXPORTER_OTLP_LOGS_HEADERS=authorization=Bearer%20lit_your_logs_key

Only sending traces? Leave out the other blocks and add OTEL_METRICS_EXPORTER=none and OTEL_LOGS_EXPORTER=none.

3. Run ​

Load the instrumentation before your app starts:

bash
node --require @opentelemetry/auto-instrumentations-node/register app.js

Can't change the start command? Set it in the environment instead:

bash
NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"

Using .env files?

The SDK reads configuration as it loads, before your app parses .env. Load the file first with Node's built-in flag: node --env-file=.env --require @opentelemetry/auto-instrumentations-node/register app.js

4. Check it's working ​

Make a few requests to your app, then open Telemetry in the Console and pick your traces stream. Traces show up within seconds. Metrics follow within a minute.

Custom spans ​

Wrap any work you want to see in a trace:

js
import { trace } from '@opentelemetry/api';

const tracer = trace.getTracer('checkout');

await tracer.startActiveSpan('charge-card', async (span) => {
  try {
    span.setAttribute('order.id', order.id);
    await chargeCard(order);
  } finally {
    span.end();
  }
});

Custom metrics ​

js
import { metrics } from '@opentelemetry/api';

const meter = metrics.getMeter('checkout');
const orders = meter.createCounter('orders.placed');
const duration = meter.createHistogram('checkout.duration', { unit: 'ms' });

orders.add(1, { plan: 'pro' });
duration.record(182, { route: '/pay' });

Logs ​

Logs written with pino or bunyan are sent automatically, with the trace they belong to. For winston, also install the transport:

bash
npm install @opentelemetry/winston-transport

ES modules ​

Using "type": "module" or .mjs? Add OpenTelemetry's loader hook so imported libraries get instrumented too:

bash
node --experimental-loader=@opentelemetry/instrumentation/hook.mjs \
  --import @opentelemetry/auto-instrumentations-node/register app.js

More in OpenTelemetry's ESM support notes.

© 2026 Latency Labs LLC