🟢 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:

ComponentWhat's CapturedAuto-Traced?
Incoming HTTPRoute, method, status, duration, client IP, user agent✓ Yes
Outgoing HTTPhttp/https, fetch, axios - URL, method, status, peer.service✓ Yes
PostgreSQLSQL queries, parameters, database name, duration✓ Yes
MySQLSQL queries, parameters, database name, duration✓ Yes
MongoDBCollection operations, query filters, database name✓ Yes
RedisCommands (GET, SET, etc.), keys accessed, duration✓ Yes
ExceptionsType, message, stack trace, request context✓ Yes
Custom SpansManual instrumentation for custom operationsManual

📦 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 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

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-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

If traces aren't appearing in Local UI, 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"

This maps localhost:8082 to "payment-service" in your service graph.

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;
    }
  }
}

⚙️ 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=production
⚠️

Important 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?

  1. Verify your API key is correct in environment variables
  2. Check that tracekit.init() is called before your routes
  3. Ensure middleware is added before route handlers
  4. Check Node.js console for errors
  5. 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!