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:
| Component | Span Type | Captured Attributes | Auto-Traced? |
|---|---|---|---|
| Incoming HTTP | SERVER | route, method, status, duration, client_ip, user_agent | Yes |
| Outgoing HTTP | CLIENT | method, url, status_code, duration, peer.service | Yes |
| PostgreSQL | DB | db.system, db.statement, db.name, duration | Yes |
| MySQL | DB | db.system, db.statement, db.name, duration | Yes |
| MongoDB | DB | db.system (mongodb), db.operation, db.name, duration | Yes |
| Redis | DB | db.system (redis), db.statement, duration | Yes |
| LLM (OpenAI/Anthropic) | CLIENT | gen_ai.system, model, tokens, cost, finish_reason, latency | Yes |
| Exceptions | N/A | type, message, stack_trace, request_context | Yes |
| Custom Spans | Custom | user-defined attributes | Manual |
Auto-Instrumented Libraries
The following libraries are automatically instrumented when detected. Import them after calling tracekit.init() for automatic span creation:
| Library | Span Type | Captured Attributes | Auto-Instrumented? |
|---|---|---|---|
| pg (PostgreSQL) | DB | db.system, db.statement, db.name, duration | Yes |
| mysql / mysql2 | DB | db.system, db.statement, db.name, duration | Yes |
| mongodb | DB | db.system (mongodb), db.operation, db.name, duration | Yes |
| ioredis / redis | DB | db.system (redis), db.statement, duration | Yes |
| node:http / node:https | CLIENT | http.method, http.url, http.status_code, peer.service | Yes |
| undici (Fetch API) | CLIENT | http.method, http.url, http.status_code, peer.service | Yes |
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-apmExpress 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 / Class | Parameters | Returns | Description |
|---|---|---|---|
createExpressMiddleware() | client: TracekitClient, snapshot?: boolean | RequestHandler | Creates Express middleware that automatically traces all incoming HTTP requests. |
getCurrentSpan() | req: Request | Span or undefined | Retrieves the current active span from an Express request. |
getClientIp() | req: Request | string or undefined | Extracts client IP from request headers (X-Forwarded-For, X-Real-IP) with proxy support. |
TracekitInterceptor | NestJS class | NestInterceptor | NestJS 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 / Class | Parameters | Returns | Description |
|---|---|---|---|
captureSnapshot() | label: string, vars: object | Promise<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() | none | SnapshotClient or undefined | Returns the snapshot client if code monitoring is enabled, or undefined if disabled. |
SnapshotClient | class | -- | Manages breakpoint polling and snapshot uploads. Created automatically when enableCodeMonitoring: true. |
CaptureConfig | interface | -- | Configuration for capture behaviour. Fields: enablePiiScrubbing (boolean), piiPatterns (PIIPatternEntry[]), circuitBreaker (CircuitBreakerConfig). |
CircuitBreakerConfig | interface | -- | Configures circuit breaker thresholds. Fields: maxFailures (default 3), windowMs (default 60000), cooldownMs (default 300000). |
PIIPatternEntry | interface | -- | Defines a sensitive-data pattern. Fields: name (string), pattern (RegExp), redactedType (string). |
End-to-End Workflow
- Enable Code Monitoring -- Set
enableCodeMonitoring: truein your init config. - Add Capture Points -- Place
captureSnapshotcalls at code paths you want to debug. Note:captureSnapshotreturns a Promise -- useawait. - Deploy and Verify Traces -- Deploy your application and confirm traces are flowing at /traces.
- Navigate to Code Monitoring -- Go to /snapshots and click the "Browse Code" tab.
- Set Breakpoints -- Breakpoints are auto-registered on the first
captureSnapshotcall. You can also manually add breakpoints via the UI. - Trigger a Capture -- Make a request that hits a code path with
captureSnapshot. - 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
| Attribute | Description |
|---|---|
gen_ai.system | Provider name (openai, anthropic) |
gen_ai.request.model | Model name (gpt-4o, claude-sonnet-4-20250514, etc.) |
gen_ai.usage.input_tokens | Prompt token count |
gen_ai.usage.output_tokens | Completion token count |
gen_ai.response.finish_reasons | Finish 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-ui2. Start the Local UI:
tracekit-local3. Run your app in development mode:
NODE_ENV=development node app.js4. Open your browser:
http://localhost:9999Automatic 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:9999on 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=developmentis 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:
| URL | Extracted Service Name |
|---|---|
http://payment-service:3000 | payment-service |
http://payment.internal | payment |
http://payment.svc.cluster.local | payment |
https://api.example.com | api.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
| Method | Parameters | Returns | Description |
|---|---|---|---|
startTrace() | op: string, attrs?: object | Span | Creates a new root trace for top-level operations not tied to an incoming HTTP request. |
startServerSpan() | op: string, attrs?: object | Span | Creates a SERVER span for incoming requests. Extracts trace context from request headers. |
startSpan() | op: string, parent?: Span, attrs?: object | Span | Creates a child span. If parent is null, automatically links to the current active span. |
endSpan() | span: Span, attrs?: object, status?: string | void | Ends a span, recording its duration. Optionally sets final attributes and status code. |
addEvent() | span: Span, name: string, attrs?: object | void | Records a timestamped event on a span. |
recordException() | span: Span, error: Error | void | Records an exception on a span with message, type, and stack trace. Sets span status to ERROR. |
Lifecycle Methods
| Method | Parameters | Returns | Description |
|---|---|---|---|
flush() | none | Promise<void> | Forces an immediate flush of all pending spans to the backend. |
shutdown() | none | Promise<void> | Gracefully shuts down the SDK: flushes remaining data, releases resources, stops background tasks. |
isEnabled() | none | boolean | Returns whether the SDK is currently enabled and actively tracing. |
shouldSample() | none | boolean | Returns whether the current request should be sampled based on the configured sample rate. |
getTracer() | none | Tracer | Returns 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=productionImportant Security Note -- Never commit your API key to version control. Use environment variables and keep your .env file out of git.
TracekitConfig Interface
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
apiKey | string | Yes | -- | Your TraceKit API key for authenticating with the collector |
endpoint | string | No | "app.tracekit.dev" | TraceKit collector endpoint URL |
tracesPath | string | No | "/v1/traces" | HTTP path for trace data export |
metricsPath | string | No | "/v1/metrics" | HTTP path for metrics data export |
serviceName | string | No | "node-app" | Name of your service shown in the trace dashboard and service map |
enabled | boolean | No | true | Enable or disable tracing globally |
sampleRate | number | No | 1.0 | Trace sampling rate from 0.0 to 1.0 (1.0 = trace 100%) |
enableCodeMonitoring | boolean | No | false | Enable live code debugging and snapshot capture |
autoInstrumentHttpClient | boolean | No | true | Auto-instrument outgoing HTTP calls via http/https and fetch |
serviceNameMappings | Record<string, string> | No | Map host:port patterns to friendly service names for the service map |
Configuration Reference
| Option | Type | Default | Env Variable | Description |
|---|---|---|---|---|
apiKey | string | required | TRACEKIT_API_KEY | Your TraceKit API key for authentication |
endpoint | string | "app.tracekit.dev" | TRACEKIT_ENDPOINT | TraceKit collector endpoint URL |
tracesPath | string | "/v1/traces" | TRACEKIT_TRACES_PATH | HTTP path for trace data export |
metricsPath | string | "/v1/metrics" | TRACEKIT_METRICS_PATH | HTTP path for metrics data export |
serviceName | string | "node-app" | TRACEKIT_SERVICE_NAME | Name of your service in the trace dashboard |
enabled | boolean | true | TRACEKIT_ENABLED | Enable or disable tracing globally |
sampleRate | number | 1.0 | TRACEKIT_SAMPLE_RATE | Trace sampling rate (0.0 to 1.0) |
enableCodeMonitoring | boolean | false | TRACEKIT_CODE_MONITORING_ENABLED | Enable live code debugging / snapshot capture |
autoInstrumentHttpClient | boolean | true | -- | Auto-instrument outgoing HTTP calls |
serviceNameMappings | Record<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);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
enabledis not set tofalse - 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: truein 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.
| Metric | Impact | Details |
|---|---|---|
| Request Tracing | < 1ms per request | Spans are batched and exported asynchronously |
| Code Monitoring (Idle) | Zero overhead | No performance impact when no active breakpoints |
| Code Monitoring (Capture) | < 5ms per snapshot | Includes variable serialization and security scanning |
| Memory Footprint | ~10-20 MB | SDK runtime and span buffer |
| SDK Initialization | < 200ms one-time | One-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 patcheshttp,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, callclient.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!
Go Integration Guide
Add TraceKit to your Go applications for automatic distributed tracing. Debug production Golang services with live breakpoints and complete request visibility.
Python Integration Guide
Integrate TraceKit with Python applications for automatic request tracing and live debugging. Monitor Flask, Django, and FastAPI apps in production with live breakpoints.