TraceKitTraceKit Docs
Backend SDKs

Node.js / TypeScript Integration Guide

Learn how to integrate TraceKit with Node.js, Express, and NestJS. Automatic distributed tracing with live breakpoints for debugging production Node.js applications.

Learn how to instrument your Node.js and TypeScript applications with TraceKit APM for zero-config distributed tracing.

Let AI set up TraceKit for you -- AI assistants can guide you through the entire setup process. Try AI Setup

Zero-Config Automatic Tracing

TraceKit Node APM package automatically traces HTTP requests, errors, and provides first-class TypeScript support. Just install, configure, and go!

Prerequisites

  • Node.js 16.x or higher
  • Express 4.x/5.x or NestJS 10.x
  • A TraceKit account (create one free)
  • A generated API key from the API Keys page

What Gets Traced Automatically

With TraceKit Node APM installed, these operations are traced automatically:

ComponentSpan TypeCaptured AttributesAuto-Traced?
Incoming HTTPSERVERroute, method, status, duration, client_ip, user_agentYes
Outgoing HTTPCLIENTmethod, url, status_code, duration, peer.serviceYes
PostgreSQLDBdb.system, db.statement, db.name, durationYes
MySQLDBdb.system, db.statement, db.name, durationYes
MongoDBDBdb.system (mongodb), db.operation, db.name, durationYes
RedisDBdb.system (redis), db.statement, durationYes
LLM (OpenAI/Anthropic)CLIENTgen_ai.system, model, tokens, cost, finish_reason, latencyYes
ExceptionsN/Atype, message, stack_trace, request_contextYes
Custom SpansCustomuser-defined attributesManual

Auto-Instrumented Libraries

The following libraries are automatically instrumented when detected. Import them after calling tracekit.init() for automatic span creation:

LibrarySpan TypeCaptured AttributesAuto-Instrumented?
pg (PostgreSQL)DBdb.system, db.statement, db.name, durationYes
mysql / mysql2DBdb.system, db.statement, db.name, durationYes
mongodbDBdb.system (mongodb), db.operation, db.name, durationYes
ioredis / redisDBdb.system (redis), db.statement, durationYes
node:http / node:httpsCLIENThttp.method, http.url, http.status_code, peer.serviceYes
undici (Fetch API)CLIENThttp.method, http.url, http.status_code, peer.serviceYes

Import database and HTTP client libraries after calling tracekit.init() to ensure automatic instrumentation is applied.

Installation

Install the TraceKit Node APM package via npm or yarn:

npm install @tracekit/node-apm
# or
yarn add @tracekit/node-apm

Express Setup

JavaScript

const express = require('express');
const tracekit = require('@tracekit/node-apm');

const app = express();

// Initialize TraceKit (before routes!)
tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY,
  serviceName: 'my-express-app',
  endpoint: 'https://app.tracekit.dev/v1/traces',
  enableCodeMonitoring: true, // Optional: Enable live debugging
});

// Add TraceKit middleware (before routes!)
app.use(tracekit.middleware());

// Your routes - automatically traced!
app.get('/api/users', (req, res) => {
  res.json({ users: ['alice', 'bob'] });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

TypeScript

import express from 'express';
import * as tracekit from '@tracekit/node-apm';

const app = express();

// Initialize TraceKit (before routes!)
tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY!,
  serviceName: 'my-express-app',
  endpoint: 'https://app.tracekit.dev/v1/traces',
  enableCodeMonitoring: true, // Optional: Enable live debugging
});

// Add TraceKit middleware (before routes!)
app.use(tracekit.middleware());

// Your routes - automatically traced!
app.get('/api/users', (req, res) => {
  res.json({ users: ['alice', 'bob'] });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Verify It Works -- Start your application and make a few requests. Then open the Traces page in your TraceKit dashboard. You should see:

  • SERVER spans for each incoming HTTP request with route and status
  • CLIENT spans for outgoing HTTP calls (auto-traced for http/https, fetch, axios)
  • DB spans for database queries (auto-traced for PostgreSQL, MySQL, MongoDB, Redis)

Traces typically appear within 30 seconds. If you don't see them, check the Troubleshooting section.

NestJS Setup

1. Import TracekitModule

Add the TracekitModule to your app.module.ts:

// app.module.ts
import { Module } from '@nestjs/common';
import { TracekitModule } from '@tracekit/node-apm/nestjs';
import { UsersModule } from './users/users.module';

@Module({
  imports: [
    TracekitModule.forRoot({
      apiKey: process.env.TRACEKIT_API_KEY!,
      serviceName: 'my-nestjs-app',
      endpoint: 'https://app.tracekit.dev/v1/traces',
      enableCodeMonitoring: true, // Optional: Enable live debugging
    }),
    UsersModule,
  ],
})
export class AppModule {}

2. Async Configuration

For environment-based configuration using ConfigModule:

// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TracekitModule } from '@tracekit/node-apm/nestjs';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TracekitModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        apiKey: config.get('TRACEKIT_API_KEY')!,
        serviceName: config.get('APP_NAME', 'my-app'),
        endpoint: config.get('TRACEKIT_ENDPOINT'),
        enabled: config.get('NODE_ENV') === 'production',
        enableCodeMonitoring: true, // Optional: Enable live debugging
      }),
    }),
  ],
})
export class AppModule {}

Automatic Interceptor -- The TracekitModule automatically registers a global interceptor that traces all HTTP requests. No additional middleware needed!

Middleware and Interceptor API

Function / ClassParametersReturnsDescription
createExpressMiddleware()client: TracekitClient, snapshot?: booleanRequestHandlerCreates Express middleware that automatically traces all incoming HTTP requests.
getCurrentSpan()req: RequestSpan or undefinedRetrieves the current active span from an Express request.
getClientIp()req: Requeststring or undefinedExtracts client IP from request headers (X-Forwarded-For, X-Real-IP) with proxy support.
TracekitInterceptorNestJS classNestInterceptorNestJS interceptor for automatic span creation on all controller methods.

Code Monitoring (Live Debugging)

Production-Safe Live Debugging -- Capture variable state, stack traces, and request context at any point in your code without redeployment. Perfect for debugging production issues! Full Code Monitoring Documentation

Setup

Enable code monitoring when initializing TraceKit:

import * as tracekit from '@tracekit/node-apm';

const client = tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY!,
  serviceName: 'my-app',
  enableCodeMonitoring: true,  // Enable live debugging
});

Usage: Add Debug Points

Use client.captureSnapshot() to capture variable state:

app.post('/checkout', async (req, res) => {
  const { userId, amount } = req.body;

  // Capture snapshot at this point
  await client.captureSnapshot('checkout-validation', {
    userId,
    amount,
    timestamp: new Date().toISOString(),
  });

  // Your business logic...
  const result = await processPayment(amount, userId);

  // Another checkpoint
  await client.captureSnapshot('payment-complete', {
    userId,
    paymentId: result.paymentId,
    success: result.success,
  });

  res.json(result);
});

Features

  • Auto-Registration -- Breakpoints automatically created on first call
  • Variable Capture -- Deep inspection of objects, arrays, and primitives
  • Stack Traces -- Full call stack with file and line numbers
  • Request Context -- HTTP method, route, headers, and query params

Production Safety

v6.0 adds multiple layers of protection so code monitoring is safe for production workloads:

  • PII Scrubbing -- 13 built-in sensitive-data patterns enabled by default. Matched values are replaced with typed [REDACTED:type] markers before data leaves the process.
  • Crash Isolation -- Every capture entry point is wrapped in try/catch so a failure in the SDK never propagates to your application code.
  • Circuit Breaker -- After 3 consecutive failures within 60 seconds the SDK enters a 5-minute cooldown, then auto-recovers. Fully configurable thresholds.
  • Remote Kill Switch -- Toggle code monitoring on or off from the TraceKit dashboard. The change propagates to all connected SDK instances via SSE in real time.

Real-Time Updates via SSE -- The Node SDK opens a lightweight Server-Sent Events connection to the TraceKit server on startup. Breakpoint enables/disables, kill-switch toggles, and configuration changes are pushed instantly -- no polling delay.

Exception Handling

Exceptions are automatically captured with full stack traces for code discovery:

// Exceptions in spans are automatically captured
app.get('/api/users/:id', async (req, res, next) => {
  try {
    const user = await getUserById(req.params.id);
    res.json(user);
  } catch (error) {
    // TraceKit automatically captures exception with stack trace
    next(error);
  }
});

// Express error handler
app.use((err, req, res, next) => {
  client.recordException(null, err);
  res.status(500).json({ error: 'Internal Server Error' });
});

Code Monitoring API

Method / ClassParametersReturnsDescription
captureSnapshot()label: string, vars: objectPromise<void>Captures a snapshot of variable state at the call site. Auto-registers a breakpoint on first call. Rate-limited to 1 capture/sec per label.
getSnapshotClient()noneSnapshotClient or undefinedReturns the snapshot client if code monitoring is enabled, or undefined if disabled.
SnapshotClientclass--Manages breakpoint polling and snapshot uploads. Created automatically when enableCodeMonitoring: true.
CaptureConfiginterface--Configuration for capture behaviour. Fields: enablePiiScrubbing (boolean), piiPatterns (PIIPatternEntry[]), circuitBreaker (CircuitBreakerConfig).
CircuitBreakerConfiginterface--Configures circuit breaker thresholds. Fields: maxFailures (default 3), windowMs (default 60000), cooldownMs (default 300000).
PIIPatternEntryinterface--Defines a sensitive-data pattern. Fields: name (string), pattern (RegExp), redactedType (string).

End-to-End Workflow

  1. Enable Code Monitoring -- Set enableCodeMonitoring: true in your init config.
  2. Add Capture Points -- Place captureSnapshot calls at code paths you want to debug. Note: captureSnapshot returns a Promise -- use await.
  3. Deploy and Verify Traces -- Deploy your application and confirm traces are flowing at /traces.
  4. Navigate to Code Monitoring -- Go to /snapshots and click the "Browse Code" tab.
  5. Set Breakpoints -- Breakpoints are auto-registered on the first captureSnapshot call. You can also manually add breakpoints via the UI.
  6. Trigger a Capture -- Make a request that hits a code path with captureSnapshot.
  7. View Snapshot -- Go to /snapshots and click the captured snapshot to view variables, call stack, request context, and trace link.

LLM Instrumentation

TraceKit automatically instruments OpenAI and Anthropic SDK calls when detected. LLM calls appear as spans with OTel GenAI semantic convention attributes.

Zero-config auto-instrumentation -- If openai or @anthropic-ai/sdk is installed, TraceKit patches them automatically at init. No code changes required.

Captured Attributes

AttributeDescription
gen_ai.systemProvider name (openai, anthropic)
gen_ai.request.modelModel name (gpt-4o, claude-sonnet-4-20250514, etc.)
gen_ai.usage.input_tokensPrompt token count
gen_ai.usage.output_tokensCompletion token count
gen_ai.response.finish_reasonsFinish reason (stop, end_turn, tool_calls)

Configuration

const client = init({
  apiKey: process.env.TRACEKIT_API_KEY,
  serviceName: 'my-service',
  endpoint: 'https://app.tracekit.dev/v1/traces',

  // LLM instrumentation (all enabled by default)
  instrumentLLM: {
    enabled: true,        // Master toggle
    openai: true,         // OpenAI instrumentation
    anthropic: true,      // Anthropic instrumentation
    captureContent: false, // Capture prompts/completions (off by default)
  },
});

Environment Variable Override

Use TRACEKIT_LLM_CAPTURE_CONTENT=true to enable prompt/completion capture without code changes. Useful for enabling in staging but not production.

Streaming Support

Streaming responses produce a single span that covers the entire stream. Token counts are accumulated from the final chunk. No special configuration needed.

LLM Dashboard

View LLM cost, token usage, and latency metrics on the dedicated LLM Observability dashboard at /ai/llm in your TraceKit instance.

Local UI (Development Mode)

Debug Locally Without an Account -- The Local UI lets you see traces in real-time on your local machine at http://localhost:9999. Perfect for development -- no account signup or API key required!

Quick Start

1. Install the Local UI:

npm install -g @tracekit/local-ui

2. Start the Local UI:

tracekit-local

3. Run your app in development mode:

NODE_ENV=development node app.js

4. Open your browser:

http://localhost:9999

Automatic Detection -- The SDK automatically detects when Local UI is running and sends traces to both your local instance and the cloud (if you have an API key configured). No code changes needed!

How It Works

  • Auto-Detection -- SDK checks for Local UI at localhost:9999 on startup
  • Real-Time Updates -- See traces instantly with WebSocket live updates
  • Development Only -- Only activates when NODE_ENV=development
  • Works Offline -- No internet connection required -- everything runs locally

Benefits

  • Zero friction onboarding -- Try TraceKit without creating an account
  • Faster debugging -- No context switching to web dashboard
  • Privacy first -- Traces never leave your machine
  • Perfect for demos -- Show TraceKit without cloud dependency

Troubleshooting Local UI -- If traces aren't appearing, check:

  • Local UI is running (curl http://localhost:9999/api/health)
  • NODE_ENV=development is set
  • SDK version is v0.3.2 or higher
  • Check console for "Local UI detected" message

Service Discovery

TraceKit automatically instruments outgoing HTTP calls to create service dependency graphs. When your service makes an HTTP request to another service, TraceKit creates CLIENT spans and injects trace context headers.

Supported HTTP Clients

  • http/https -- Node.js built-in modules
  • fetch -- Node 18+ native fetch API
  • axios -- Works via http module
  • node-fetch, got, superagent -- Work via http module

Custom Service Name Mappings

For local development or when service names can't be inferred from hostnames, configure service name mappings:

import * as tracekit from '@tracekit/node-apm';

tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY,
  serviceName: 'my-service',
  // Map localhost URLs to actual service names
  serviceNameMappings: {
    'localhost:8082': 'payment-service',
    'localhost:8083': 'user-service',
    'localhost:8084': 'inventory-service',
  },
});

// Now requests to localhost:8082 will show as "payment-service"
const response = await fetch('http://localhost:8082/charge');
// -> Creates CLIENT span with peer.service = "payment-service"

Service Name Detection

TraceKit intelligently extracts service names from URLs:

URLExtracted Service Name
http://payment-service:3000payment-service
http://payment.internalpayment
http://payment.svc.cluster.localpayment
https://api.example.comapi.example.com

Viewing Service Dependencies -- Visit your TraceKit dashboard to see the Service Map -- a visual graph showing which services call which, with health metrics and latency data.

Manual Instrumentation (Optional)

Express - Manual Spans

import { getClient } from '@tracekit/node-apm';

app.post('/api/process', async (req, res) => {
  const client = getClient();

  const span = client.startSpan('process-data', null, {
    'user.id': req.user?.id,
    'data.size': req.body.items.length,
  });

  try {
    const result = await processData(req.body);

    client.endSpan(span, {
      'result.count': result.length,
    });

    res.json(result);
  } catch (error) {
    client.recordException(span, error as Error);
    client.endSpan(span, {}, 'ERROR');
    throw error;
  }
});

NestJS - Manual Spans

import { Injectable, Inject } from '@nestjs/common';
import { TracekitClient } from '@tracekit/node-apm/nestjs';

@Injectable()
export class DataService {
  constructor(
    @Inject('TRACEKIT_CLIENT') private tracekit: TracekitClient
  ) {}

  async processLargeDataset(data: any[]) {
    const span = this.tracekit.startSpan('process-dataset', null, {
      'dataset.size': data.length,
    });

    try {
      const results = [];
      for (const item of data) {
        const result = await this.processItem(item);
        results.push(result);
      }

      this.tracekit.endSpan(span, {
        'results.count': results.length,
      });

      return results;
    } catch (error) {
      this.tracekit.recordException(span, error as Error);
      this.tracekit.endSpan(span, {}, 'ERROR');
      throw error;
    }
  }
}

TracekitClient Tracing API

MethodParametersReturnsDescription
startTrace()op: string, attrs?: objectSpanCreates a new root trace for top-level operations not tied to an incoming HTTP request.
startServerSpan()op: string, attrs?: objectSpanCreates a SERVER span for incoming requests. Extracts trace context from request headers.
startSpan()op: string, parent?: Span, attrs?: objectSpanCreates a child span. If parent is null, automatically links to the current active span.
endSpan()span: Span, attrs?: object, status?: stringvoidEnds a span, recording its duration. Optionally sets final attributes and status code.
addEvent()span: Span, name: string, attrs?: objectvoidRecords a timestamped event on a span.
recordException()span: Span, error: ErrorvoidRecords an exception on a span with message, type, and stack trace. Sets span status to ERROR.

Lifecycle Methods

MethodParametersReturnsDescription
flush()nonePromise<void>Forces an immediate flush of all pending spans to the backend.
shutdown()nonePromise<void>Gracefully shuts down the SDK: flushes remaining data, releases resources, stops background tasks.
isEnabled()nonebooleanReturns whether the SDK is currently enabled and actively tracing.
shouldSample()nonebooleanReturns whether the current request should be sampled based on the configured sample rate.
getTracer()noneTracerReturns the underlying OpenTelemetry Tracer instance for advanced use cases.

Complete Tracing Lifecycle Example

const client = getClient();

// Start a root trace for a background job or non-HTTP operation
const span = client.startTrace('process-order', { 'order.id': orderId });

try {
  // Create a child span for a sub-operation
  const childSpan = client.startSpan('validate-payment', span);
  client.addEvent(childSpan, 'payment-validated', { amount: total });
  client.endSpan(childSpan);

  // End the root span with final attributes
  client.endSpan(span, { 'order.status': 'completed' });
} catch (err) {
  // Record the exception and mark the span as errored
  client.recordException(span, err);
  client.endSpan(span, {}, 'ERROR');
} finally {
  // Ensure all spans are exported before continuing
  await client.flush();
}

Configuration Options

tracekit.init({
  // Required: Your TraceKit API key
  apiKey: process.env.TRACEKIT_API_KEY,

  // Optional: Service name (default: 'node-app')
  serviceName: 'my-service',

  // Optional: TraceKit endpoint
  endpoint: 'https://app.tracekit.dev/v1/traces',

  // Optional: Enable/disable tracing (default: true)
  enabled: process.env.NODE_ENV !== 'development',

  // Optional: Sample rate 0.0-1.0 (default: 1.0 = 100%)
  sampleRate: 0.5, // Trace 50% of requests

  // Optional: Enable code monitoring / live debugging (default: false)
  enableCodeMonitoring: true,
});

Environment Variables

Best practice: Store configuration in environment variables:

# .env
TRACEKIT_API_KEY=ctxio_your_generated_api_key_here
TRACEKIT_ENDPOINT=https://app.tracekit.dev/v1/traces
TRACEKIT_SERVICE_NAME=my-nodejs-app
TRACEKIT_CODE_MONITORING_ENABLED=true
NODE_ENV=production

Important Security Note -- Never commit your API key to version control. Use environment variables and keep your .env file out of git.

TracekitConfig Interface

FieldTypeRequiredDefaultDescription
apiKeystringYes--Your TraceKit API key for authenticating with the collector
endpointstringNo"app.tracekit.dev"TraceKit collector endpoint URL
tracesPathstringNo"/v1/traces"HTTP path for trace data export
metricsPathstringNo"/v1/metrics"HTTP path for metrics data export
serviceNamestringNo"node-app"Name of your service shown in the trace dashboard and service map
enabledbooleanNotrueEnable or disable tracing globally
sampleRatenumberNo1.0Trace sampling rate from 0.0 to 1.0 (1.0 = trace 100%)
enableCodeMonitoringbooleanNofalseEnable live code debugging and snapshot capture
autoInstrumentHttpClientbooleanNotrueAuto-instrument outgoing HTTP calls via http/https and fetch
serviceNameMappingsRecord<string, string>NoMap host:port patterns to friendly service names for the service map

Configuration Reference

OptionTypeDefaultEnv VariableDescription
apiKeystringrequiredTRACEKIT_API_KEYYour TraceKit API key for authentication
endpointstring"app.tracekit.dev"TRACEKIT_ENDPOINTTraceKit collector endpoint URL
tracesPathstring"/v1/traces"TRACEKIT_TRACES_PATHHTTP path for trace data export
metricsPathstring"/v1/metrics"TRACEKIT_METRICS_PATHHTTP path for metrics data export
serviceNamestring"node-app"TRACEKIT_SERVICE_NAMEName of your service in the trace dashboard
enabledbooleantrueTRACEKIT_ENABLEDEnable or disable tracing globally
sampleRatenumber1.0TRACEKIT_SAMPLE_RATETrace sampling rate (0.0 to 1.0)
enableCodeMonitoringbooleanfalseTRACEKIT_CODE_MONITORING_ENABLEDEnable live code debugging / snapshot capture
autoInstrumentHttpClientbooleantrue--Auto-instrument outgoing HTTP calls
serviceNameMappingsRecord<string, string>--Map host:port to service names for service discovery

The Node.js SDK does not auto-read environment variables. Read them with process.env and pass to init().

Complete Example

Here's a complete Express + TypeScript example:

import express, { Request, Response } from 'express';
import * as tracekit from '@tracekit/node-apm';

const app = express();
app.use(express.json());

// Initialize TraceKit
tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY!,
  serviceName: 'express-api',
  endpoint: 'https://app.tracekit.dev/v1/traces',
  enabled: process.env.NODE_ENV === 'production',
  enableCodeMonitoring: true, // Optional: Enable live debugging
});

// Add middleware
app.use(tracekit.middleware());

interface User {
  id: string;
  name: string;
  email: string;
}

// Routes - automatically traced!
app.get('/api/users', (req: Request, res: Response) => {
  const users: User[] = [
    { id: '1', name: 'Alice', email: 'alice@example.com' },
    { id: '2', name: 'Bob', email: 'bob@example.com' },
  ];
  res.json(users);
});

// Manual span example
app.post('/api/users', async (req: Request, res: Response) => {
  const client = tracekit.getClient();

  const span = client.startSpan('create-user', null, {
    'user.email': req.body.email,
  });

  try {
    // Simulate user creation
    const user: User = {
      id: Date.now().toString(),
      name: req.body.name,
      email: req.body.email,
    };

    // Simulate async operation
    await new Promise(resolve => setTimeout(resolve, 100));

    client.endSpan(span, {
      'user.id': user.id,
    });

    res.status(201).json(user);
  } catch (error) {
    client.recordException(span, error as Error);
    client.endSpan(span, {}, 'ERROR');
    res.status(500).json({ error: 'Failed to create user' });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log('Server running on port ' + PORT);
});

Custom Metrics

Track custom metrics like request counts, queue sizes, and response times using the TraceKit metrics API.

Counter

Track monotonically increasing values (requests, events):

import * as tracekit from '@tracekit/node-apm';

const client = tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY,
  serviceName: 'my-service',
});

// Create a counter with optional tags
const counter = client.counter('http.requests.total', { service: 'api' });

// Increment by 1
counter.inc();

// Add a specific value
counter.add(5);

Gauge

Track values that can go up or down (queue size, connections):

// Create a gauge
const gauge = client.gauge('http.connections.active');

// Set to specific value
gauge.set(42);

// Increment/decrement
gauge.inc();
gauge.dec();

Histogram

Track value distributions (latencies, sizes):

// Create a histogram with tags
const histogram = client.histogram('http.request.duration', { unit: 'ms' });

// Record values
histogram.record(45.2);
histogram.record(123.5);

View Custom Metrics Guide

Troubleshooting

Traces not appearing?

Cause: The SDK is not initialized or is initialized after route handlers are registered.

Fix:

  • Call tracekit.init() BEFORE registering any Express/Fastify routes or middleware
  • Verify API key with console.log(process.env.TRACEKIT_API_KEY)
  • Check that enabled is not set to false
  • Look for errors in the console output

Connection refused errors?

Cause: The TraceKit endpoint is unreachable from your Node.js process.

Fix:

  • Test with curl -X POST https://app.tracekit.dev/v1/traces (expect 401)
  • Check proxy/firewall settings
  • Verify the endpoint URL does not have a trailing slash

Code monitoring not working?

Cause: Code monitoring is disabled by default and requires explicit enablement.

Fix:

  • Set enableCodeMonitoring: true in the init options
  • Add captureSnapshot() calls where you want to inspect variables
  • Check the dashboard for active breakpoints
  • Allow up to 30 seconds for the SDK to poll for new breakpoints

Authentication errors (401/403)?

Cause: API key is wrong, has extra whitespace, or was revoked.

Fix:

  • Log the key to verify: console.log(JSON.stringify(apiKey)) (catches invisible characters)
  • Regenerate in dashboard if needed
  • Ensure the correct key is used per environment

Partial or missing spans?

Cause: Auto-instrumentation is not capturing all libraries, or async context is lost.

Fix:

  • Verify autoInstrumentHttpClient: true (default) for outgoing HTTP
  • For database spans, ensure the database library is imported AFTER tracekit.init()
  • Check that async/await is used consistently (callbacks can lose trace context)

Migrating from OpenTelemetry

If you are currently using OpenTelemetry directly, TraceKit wraps it with a simpler API. Replace your OTel setup with tracekit.init() and remove manual exporter configuration. TraceKit handles the OTel pipeline internally.

Performance Overhead

TraceKit is built on OpenTelemetry's efficient batch processing pipeline. The SDK adds minimal overhead to your Node.js application.

MetricImpactDetails
Request Tracing< 1ms per requestSpans are batched and exported asynchronously
Code Monitoring (Idle)Zero overheadNo performance impact when no active breakpoints
Code Monitoring (Capture)< 5ms per snapshotIncludes variable serialization and security scanning
Memory Footprint~10-20 MBSDK runtime and span buffer
SDK Initialization< 200ms one-timeOne-time cost at application startup

Performance characteristics are typical for production workloads and may vary with application complexity, request volume, and number of instrumented libraries. Use sampling configuration to reduce overhead in high-traffic services.

Best Practices

  • DO: Initialize TraceKit BEFORE requiring routes/modules -- The tracekit.init() call must be the first line in your entry file so auto-instrumentation patches http, express, and database drivers before they are loaded.
  • DO: Use environment variables for configuration -- Keep API keys, endpoints, and service names in environment variables for easy per-environment configuration.
  • DO: Add custom spans for critical business logic -- While auto-instrumentation covers HTTP and database calls, add manual spans for important operations like payment processing or order fulfillment.
  • DON'T: Initialize TraceKit inside a route handler -- This will miss all requests that come in before that route is hit.
  • DON'T: Forget to call flush() before process exit -- In serverless or short-lived processes, call client.flush() to ensure all spans are exported.

Next Steps

  • Explore your traces on the Traces page to identify performance bottlenecks
  • Set up alert rules to get notified when issues occur
  • Add custom spans for specific operations you want to measure
  • Configure sampling rates for high-traffic applications

Pro Tip -- Use the getClient() function to access the TraceKit client anywhere in your application for creating custom spans!

On this page