🟢 Node.js / TypeScript Integration Guide
Learn how to instrument your Node.js and TypeScript applications with TraceKit APM for zero-config distributed tracing.
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
- • An active TraceKit account
- • A generated API key from the API Keys page
🔍 What Gets Traced Automatically?
With TraceKit Node APM installed, these operations are traced automatically:
| Component | What's Captured | Auto-Traced? |
|---|---|---|
| Incoming HTTP | Route, method, status, duration, client IP, user agent | ✓ Yes |
| Outgoing HTTP | http/https, fetch, axios - URL, method, status, peer.service | ✓ Yes |
| PostgreSQL | SQL queries, parameters, database name, duration | ✓ Yes |
| MySQL | SQL queries, parameters, database name, duration | ✓ Yes |
| MongoDB | Collection operations, query filters, database name | ✓ Yes |
| Redis | Commands (GET, SET, etc.), keys accessed, duration | ✓ Yes |
| Exceptions | Type, message, stack trace, request context | ✓ Yes |
| Custom Spans | Manual instrumentation for custom operations | Manual |
📦 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');
});That's It!
All HTTP requests are now automatically traced. Add the middleware before your routes and you're good to go!
🐈 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!
📸 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 DocumentationSetup
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
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' });
});Production Safe
Snapshots are sampled and have minimal performance impact. Capture rates and conditions can be controlled via the TraceKit dashboard.
🚀 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: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
If traces aren't appearing in Local UI, 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"This maps localhost:8082 to "payment-service" in your service graph.
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;
}
}
}⚙️ Configuration Options
Available 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.
✅ 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: '[email protected]' },
{ id: '2', name: 'Bob', email: '[email protected]' },
];
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);
});You're all set!
Your Node.js application is now sending traces to TraceKit. Visit the Dashboard to see your traces.
🔧 Troubleshooting
Traces Not Appearing?
- Verify your API key is correct in environment variables
- Check that
tracekit.init()is called before your routes - Ensure middleware is added before route handlers
- Check Node.js console for errors
- Verify TraceKit endpoint is accessible
TypeScript Types Not Working?
Make sure you have TypeScript definitions installed:
npm install --save-dev @types/node # Types are included in the package, no separate @types needed!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);🚀 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!