npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tracekit/node-apm

v1.5.0

Published

TraceKit APM for Node.js - Zero-config distributed tracing and code monitoring for Express and NestJS

Readme

TraceKit APM for Node.js

Zero-config distributed tracing and performance monitoring for Express and NestJS applications.

npm version Downloads License

Features

  • Zero Configuration - Works out of the box with sensible defaults
  • Automatic Instrumentation - No code changes needed
  • Express Support - Simple middleware integration
  • NestJS Support - Module and interceptor-based tracing
  • TypeScript First - Full type definitions included
  • HTTP Request Tracing - Track every request, route, and handler
  • Database Tracing - Automatic query instrumentation for PostgreSQL, MySQL, MongoDB, Redis
  • Client IP Capture - Automatic IP detection for DDoS & traffic analysis
  • Error Tracking - Capture exceptions with full context
  • Code Monitoring - Live debugging with breakpoints and variable inspection
  • Metrics API - Counter, Gauge, and Histogram metrics with automatic OTLP export
  • Low Overhead - < 5% performance impact

Installation

npm install @tracekit/node-apm

Quick Start

Express

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

const app = express();

// Initialize TraceKit
tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY,
  serviceName: 'my-express-app',
});

// Add middleware (must be before routes)
app.use(tracekit.middleware());

// Your routes
app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000);

Express (TypeScript)

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

const app = express();

// Initialize TraceKit
tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY!,
  serviceName: 'my-express-app',
});

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

// Your routes
app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000);

NestJS

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

@Module({
  imports: [
    TracekitModule.forRoot({
      apiKey: process.env.TRACEKIT_API_KEY!,
      serviceName: 'my-nestjs-app',
    }),
  ],
})
export class AppModule {}

That's it! Your app is now automatically traced.

Local Development

Debug your application locally without creating a cloud account using TraceKit Local UI.

Quick Start

# Install Local UI globally
npm install -g @tracekit/local-ui

# Start it
tracekit-local

The Local UI will start at http://localhost:9999 and automatically open in your browser.

How It Works

When running in development mode (NODE_ENV=development), the SDK automatically:

  1. Detects if Local UI is running at http://localhost:9999
  2. Sends traces to both Local UI and cloud (if API key is present)
  3. Falls back gracefully if Local UI is not available

No code changes needed! Just set NODE_ENV=development:

export NODE_ENV=development
export TRACEKIT_API_KEY=your-key  # Optional - works without it!
node app.js

You'll see traces appear in real-time at http://localhost:9999.

Features

  • Real-time trace viewing in your browser
  • Works completely offline
  • No cloud account required
  • Zero configuration
  • Automatic cleanup (1000 traces max, 1 hour retention)

Local-Only Development

To use Local UI without cloud sending:

# Don't set TRACEKIT_API_KEY
export NODE_ENV=development
node app.js

Traces will only go to Local UI.

Disabling Local UI

To disable automatic Local UI detection:

export NODE_ENV=production
# or don't run Local UI

Learn More

Code Monitoring (Live Debugging)

TraceKit includes production-safe code monitoring for live debugging without redeployment.

Enable Code Monitoring

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

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

Add Debug Points

Add checkpoints anywhere in your code to capture variable state and stack traces:

// In any service or controller
app.post('/checkout', async (req, res) => {
  const cart = req.body.cart;
  const userId = req.body.userId;

  // Capture snapshot at this point
  await client.captureSnapshot('checkout-validation', {
    userId,
    cartItems: cart.items.length,
    totalAmount: cart.total,
  });

  // Process payment...
  const result = await processPayment(cart);

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

  res.json(result);
});

Automatic Breakpoint Management

  • Auto-Registration: First call to captureSnapshot() automatically creates breakpoints in TraceKit
  • Smart Matching: Breakpoints match by function name + label (stable across code changes)
  • Background Sync: SDK polls for active breakpoints every 30 seconds
  • Production Safe: No performance impact when breakpoints are inactive

View Captured Data

Snapshots include:

  • Variables: Local variables at capture point
  • Stack Trace: Full call stack with file/line numbers
  • Request Context: HTTP method, URL, headers, query params
  • Execution Time: When the snapshot was captured

NestJS Usage

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

@Injectable()
export class PaymentService {
  constructor(
    @Inject('TRACEKIT_SNAPSHOT_CLIENT')
    private snapshotClient?: SnapshotClient
  ) {}

  async processPayment(order: Order) {
    // Automatic snapshot capture
    await this.snapshotClient?.checkAndCaptureWithContext('payment-processing', {
      orderId: order.id,
      amount: order.amount,
    });

    // ... payment logic
  }
}

Get your API key at https://app.tracekit.dev

Metrics

TraceKit APM includes a powerful metrics API for tracking application performance and business metrics.

Metric Types

TraceKit supports three types of metrics:

  • Counter: Monotonically increasing values (requests, errors, events)
  • Gauge: Point-in-time values that can go up or down (active connections, queue size)
  • Histogram: Value distributions (request duration, payload sizes)

Basic Usage

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

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

// Create metrics
const requestCounter = client.counter('http.requests.total', {
  service: 'my-app'
});

const activeRequestsGauge = client.gauge('http.requests.active', {
  service: 'my-app'
});

const requestDurationHistogram = client.histogram('http.request.duration', {
  unit: 'ms'
});

// Use metrics in your handlers
app.use((req, res, next) => {
  const startTime = Date.now();

  activeRequestsGauge.inc();

  res.on('finish', () => {
    requestCounter.inc();
    activeRequestsGauge.dec();

    const duration = Date.now() - startTime;
    requestDurationHistogram.record(duration);
  });

  next();
});

Counter

Counters track monotonically increasing values:

const counter = client.counter('events.processed', { type: 'order' });

// Increment by 1
counter.inc();

// Add custom amount
counter.add(5);

Gauge

Gauges track values that can increase or decrease:

const gauge = client.gauge('queue.size', { queue: 'orders' });

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

// Increment
gauge.inc();

// Decrement
gauge.dec();

Histogram

Histograms track distributions of values:

const histogram = client.histogram('api.response.size', { unit: 'bytes' });

// Record a value
histogram.record(1024);
histogram.record(2048);

Express Example

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

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

app.use(tracekit.middleware());

// Initialize metrics
const requestCounter = client.counter('http.requests.total');
const activeRequests = client.gauge('http.requests.active');
const requestDuration = client.histogram('http.request.duration', { unit: 'ms' });
const errorCounter = client.counter('http.errors.total');

// Metrics middleware
app.use((req, res, next) => {
  const start = Date.now();
  activeRequests.inc();

  res.on('finish', () => {
    requestCounter.inc();
    activeRequests.dec();
    requestDuration.record(Date.now() - start);

    if (res.statusCode >= 400) {
      errorCounter.inc();
    }
  });

  next();
});

app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(3000);

NestJS Example

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import * as tracekit from '@tracekit/node-apm';

@Injectable()
export class MetricsMiddleware implements NestMiddleware {
  private requestCounter = tracekit.getClient().counter('http.requests.total');
  private activeRequests = tracekit.getClient().gauge('http.requests.active');
  private requestDuration = tracekit.getClient().histogram('http.request.duration', { unit: 'ms' });

  use(req: Request, res: Response, next: NextFunction) {
    const start = Date.now();
    this.activeRequests.inc();

    res.on('finish', () => {
      this.requestCounter.inc();
      this.activeRequests.dec();
      this.requestDuration.record(Date.now() - start);
    });

    next();
  }
}

Tags

Add tags to metrics for dimensional analysis:

const counter = client.counter('api.requests', {
  service: 'payment-api',
  region: 'us-east-1',
  environment: 'production'
});

counter.inc();

Common Use Cases

HTTP Request Tracking

const requests = client.counter('http.requests', { method: 'POST', endpoint: '/api/orders' });
const duration = client.histogram('http.duration', { endpoint: '/api/orders' });
const errors = client.counter('http.errors', { code: '500' });

Database Metrics

const queries = client.counter('db.queries', { operation: 'SELECT' });
const queryDuration = client.histogram('db.query.duration', { unit: 'ms' });
const connections = client.gauge('db.connections.active');

Business Metrics

const orders = client.counter('orders.created');
const revenue = client.histogram('orders.amount', { unit: 'usd' });
const inventory = client.gauge('inventory.stock', { product: 'laptop' });

Metric Export

Metrics are automatically buffered and exported in batches:

  • Buffer size: 100 metrics
  • Flush interval: 10 seconds
  • Endpoint: Automatically resolved to /v1/metrics

Metrics are sent to TraceKit using OTLP format and appear in your dashboard with full dimensional analysis.

Configuration

Basic Configuration

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

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 (default: 'https://app.tracekit.dev/v1/traces')
  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 live code debugging (default: false)
  enableCodeMonitoring: true, // Enable breakpoints and snapshots

  // Optional: Map hostnames to service names for service graph
  serviceNameMappings: {
    'localhost:8082': 'payment-service',
    'localhost:8083': 'user-service',
  },
});

NestJS Async Configuration

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'),
        enabled: config.get('NODE_ENV') !== 'development',
        enableCodeMonitoring: config.get('TRACEKIT_CODE_MONITORING_ENABLED', false),
      }),
    }),
  ],
})
export class AppModule {}

Automatic Service Discovery

TraceKit automatically instruments outgoing HTTP calls to create service dependency graphs. This enables you to see which services talk to each other in your distributed system.

How It Works

When your service makes an HTTP request to another service:

  1. ✅ TraceKit creates a CLIENT span for the outgoing request
  2. ✅ Trace context is automatically injected into request headers (traceparent)
  3. ✅ The receiving service creates a SERVER span linked to your CLIENT span
  4. ✅ TraceKit maps the dependency: YourService → TargetService

Supported HTTP Clients

TraceKit automatically instruments these HTTP libraries:

  • http / https (Node.js built-in modules)
  • fetch (Node 18+ native fetch API)
  • axios (works via http module)
  • node-fetch (works via http module)
  • got, superagent, etc. (work via http module)

Zero configuration required! Just make HTTP calls as normal:

import axios from 'axios';
import fetch from 'node-fetch';

// All of these automatically create CLIENT spans:
await fetch('http://payment-service/charge');
await axios.get('http://inventory-service/check');
http.get('http://user-service/profile/123', callback);

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 |

This works seamlessly with:

  • Kubernetes service names
  • Internal DNS names
  • Docker Compose service names
  • External APIs

Custom Service Name Mappings

For local development or when service names can't be inferred from hostnames, use serviceNameMappings:

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',
    'localhost:5001': 'analytics-service',
  },
});

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

This is especially useful when:

  • Running microservices locally on different ports
  • Using Docker Compose with localhost networking
  • Testing distributed tracing in development

Viewing Service Dependencies

Visit your TraceKit dashboard to see:

  • Service Map: Visual graph showing which services call which
  • Service List: Table of all services with health metrics
  • Service Detail: Deep dive on individual services with upstream/downstream dependencies

Disabling Auto-Instrumentation

If you need to disable automatic HTTP client instrumentation:

tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY,
  autoInstrumentHttpClient: false, // Disable auto-instrumentation
});

What Gets Traced?

Incoming HTTP Requests (SERVER spans)

Every HTTP request to your service is automatically traced with:

  • Route path and HTTP method
  • Request URL and query parameters
  • HTTP status code
  • Request duration
  • User agent and client IP
  • Controller and handler names (NestJS)

Outgoing HTTP Requests (CLIENT spans)

Every HTTP request from your service is automatically traced with:

  • Target URL and HTTP method
  • HTTP status code
  • Request duration
  • peer.service attribute for service dependency mapping

Database Queries (CLIENT spans)

All database operations are automatically traced with zero configuration:

PostgreSQL (pg library):

  • SQL query statements
  • Query parameters
  • Database name
  • Response time

MySQL (mysql/mysql2 libraries):

  • SQL query statements
  • Query parameters
  • Database name
  • Response time

MongoDB:

  • Collection operations (find, insert, update, delete)
  • Query filters
  • Database and collection names
  • Response time

Redis:

  • Commands (GET, SET, HGET, etc.)
  • Keys accessed
  • Response time

Example trace hierarchy:

GET /users/:id (kind: Server)
  ├─ SELECT * FROM users WHERE id = $1 (kind: Client, db.system: postgresql)
  ├─ GET user:123:cache (kind: Client, db.system: redis)
  └─ INSERT INTO audit_logs... (kind: Client, db.system: postgresql)

Errors and Exceptions

All exceptions are automatically captured with:

  • Exception type and message
  • Full stack trace
  • Request context
  • Handler information

Advanced Usage

Manual Tracing (Express)

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

app.get('/custom', async (req, res) => {
  const client = getClient();

  const span = client.startSpan('my-operation', null, {
    'user.id': req.user?.id,
    'custom.attribute': 'value',
  });

  try {
    const result = await doSomething();

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

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

Manual Tracing (NestJS)

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

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

  async doSomething() {
    const span = this.tracekit.startSpan('custom-operation', null, {
      'operation.type': 'database',
    });

    try {
      const result = await this.database.query();

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

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

Environment-Based Configuration

Disable tracing in development

tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY!,
  enabled: process.env.NODE_ENV === 'production',
});

Sample only 10% of requests

tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY!,
  sampleRate: 0.1, // Trace 10% of requests
});

Performance

TraceKit APM is designed to have minimal performance impact:

  • < 5% overhead on average request time
  • Asynchronous trace sending (doesn't block responses)
  • Automatic batching and compression
  • Configurable sampling for high-traffic apps

TypeScript Support

Full TypeScript support with type definitions included:

import { TracekitClient, TracekitConfig, Span } from '@tracekit/node-apm';

const config: TracekitConfig = {
  apiKey: 'your-key',
  serviceName: 'my-app',
};

const attributes: Record<string, any> = {
  'user.id': 123,
  'request.path': '/api/users',
};

// Using the client
const client = new TracekitClient(config);
const span: Span = client.startSpan('my-operation', null, attributes);

Requirements

  • Node.js 16.x or higher
  • Express 4.x or 5.x (for Express support)
  • NestJS 10.x (for NestJS support)

Examples

Express Example

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

const app = express();

tracekit.init({
  apiKey: process.env.TRACEKIT_API_KEY,
  serviceName: 'express-example',
});

app.use(tracekit.middleware());

app.get('/users', async (req, res) => {
  const users = await db.getUsers();
  res.json(users);
});

app.listen(3000);

NestJS Example

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

// 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: 'nestjs-example',
    }),
    UsersModule,
  ],
})
export class AppModule {}

// users.controller.ts
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {
  constructor(private usersService: UsersService) {}

  @Get()
  findAll() {
    return this.usersService.findAll();
  }
}

Support

License

MIT License. See LICENSE for details.

Credits

Built with ❤️ by the TraceKit team.