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

apidepth

v0.3.2

Published

Track outbound API latency, error rates, and rate-limit quota across third-party vendors

Downloads

13

Readme

apidepth

npm version Node.js License: MIT

Most API monitoring tools measure latency from their servers to the vendor. That's not what your users feel. Apidepth instruments http, https, and fetch directly — every outbound call your app makes to Stripe, OpenAI, or Twilio is timed at the socket level, from your server. Then it benchmarks your numbers against anonymized fleet data, so when Stripe is slow you can tell if it's you or everyone.

No payload capture. No credentials touch our infrastructure. No changes to your application code beyond a one-time initializer.


How it works

Real traffic, not synthetic probes. Every outbound HTTP call your application makes to a known vendor is timed at the socket level, tagged with outcome and environment metadata, and batched to the Apidepth collector in the background. The latency number in your dashboard is the number your users feel — not a probe running from a data center somewhere else.

Fleet benchmarking. Because Apidepth aggregates anonymized timing data across all customers, your dashboard shows not just "your Stripe p95 is 420ms" but "the fleet median is 280ms — you may have a regional routing issue." That comparison is only possible with real traffic from real deployments.

Proof of Innocence. When all endpoints to a vendor spike simultaneously, Apidepth surfaces a verdict: isolated (the spike is yours alone) or tracking (the fleet sees the same thing — vendor-side). The attribution card makes it fast to tell ops "it's Stripe, not us."

Rate limit intelligence. Apidepth tracks 429 patterns and projects quota burn-down before you hit the ceiling — with a burn-down card showing time-to-throttle at current request rate.


Installation

npm install apidepth

Getting started

import Apidepth from "apidepth";

Apidepth.configure({
  apiKey: process.env.APIDEPTH_API_KEY,
  environment: process.env.NODE_ENV,
});
Apidepth.instrument();

Call instrument() once at process startup, before any outbound requests are made. After that, all calls via node:http, node:https, and the global fetch to recognised vendor hosts are captured automatically — no changes at call sites.

Get your API key at apidepth.io.


Framework integrations

Express

import express from "express";
import { apidepthMiddleware } from "apidepth/integrations/express";

const app = express();

app.use(
  apidepthMiddleware({
    apiKey: process.env.APIDEPTH_API_KEY,
    environment: process.env.NODE_ENV,
  })
);

The middleware configures and instruments on first mount, then calls next() on every request — it adds no per-request overhead.

Next.js

Create or add to src/instrumentation.ts in your Next.js app:

import { register as apidepthRegister } from "apidepth/integrations/nextjs";

export async function register() {
  await apidepthRegister({
    apiKey: process.env.APIDEPTH_API_KEY,
    environment: process.env.NODE_ENV,
  });
}

Next.js calls instrumentation.ts once per runtime. Apidepth instruments only the Node.js runtime — it skips the Edge runtime because edge workers use Web APIs rather than node:http/https.

Enable the instrumentation hook in next.config.ts if you haven't already:

const nextConfig = {
  experimental: { instrumentationHook: true },
};
export default nextConfig;

CLI

The package ships two subcommands for setup and connectivity verification.

npx apidepth setup

Interactive wizard that detects your framework (Express, Next.js, or generic), generates the correct initializer snippet, and optionally writes it to disk.

npx apidepth setup

For CI/CD pipelines, skip all prompts:

npx apidepth setup --api-key $APIDEPTH_API_KEY --no-prompt

| Flag | Description | | ---------------------------- | ---------------------------------------------------------------------------------- | | --api-key <key> | Inject your API key into the generated snippet. | | --no-prompt | Non-interactive mode — print snippet to stdout and exit. | | --framework <name> | Override auto-detection (express, nextjs, generic). | | --ignored-hosts <patterns> | Comma-separated host patterns to add to ignoredHosts (glob wildcards supported). | | --collector-url <url> | Override the collector URL in the generated snippet. |

npx apidepth test

Sends a synthetic test event to the collector and confirms the pipeline is working end-to-end. Reads APIDEPTH_API_KEY (and optionally APIDEPTH_COLLECTOR_URL) from the environment. Prints the round-trip time on success, or a per-failure-mode error message with next steps on failure.

npx apidepth test
# ✓ received in 142ms
# Visit your dashboard: https://apidepth.io/dashboard

Exits with code 1 on any error (bad key, unreachable, SSL failure, timeout).


Configuration

All options with their defaults:

Apidepth.configure({
  // Required. Your account API key.
  apiKey: process.env.APIDEPTH_API_KEY,

  // Tag applied to every event. Use this to distinguish environments
  // in your dashboard. Default: null
  environment: "production",

  // Set false to disable all instrumentation (e.g. in test environments).
  // Default: true
  enabled: true,

  // Fraction of events to capture. 1.0 = 100%, 0.1 = 10%.
  // Lower this if your application makes thousands of vendor calls per minute.
  // Default: 1.0
  sampleRate: 1.0,

  // Hostnames to exclude from instrumentation entirely.
  // Default: []
  ignoredHosts: ["api.internal.mycompany.com"],

  // How often (in seconds) queued events are batched and sent.
  // Default: 20
  flushInterval: 20,

  // Path for the local vendor registry cache.
  // Default: '/tmp/apidepth_registry.json'
  registryCachePath: "/tmp/apidepth_registry.json",

  // Custom vendors your app calls that aren't in the global registry.
  // Key: vendor name shown in your dashboard.
  // Value: the hostname the SDK should watch for.
  // Mappings sync to your dashboard on the next event flush.
  // Default: {}
  extraVendors: {
    "my-payments-api": "api.payments.internal.com",
    fulfillment: "fulfillment.myco.io",
  },

  // Called on every flush failure, in addition to the built-in warn log.
  // Use this to route failures to your existing error tracker.
  // Default: null
  onFlushError: (err, ctx) => {
    Sentry.captureException(err, { extra: ctx });
  },

  // Override the collector endpoint. Only useful for self-hosted deployments.
  // Default: 'https://collector.apidepth.io/v1/events'
  collectorUrl: "https://collector.apidepth.io/v1/events",
});

What gets captured

Every event contains:

| Field | Description | | -------------- | ----------------------------------------------------------------------------------------- | | vendor | Vendor slug, e.g. "stripe", "openai" | | endpoint | Normalized path, e.g. "/v1/charges/:id" | | method | HTTP verb: "GET", "POST", etc. | | status | HTTP status code, or null on timeout | | outcome | "success", "client_error", "server_error", "timeout", "unknown" | | duration_ms | Wall-clock time in milliseconds, including DNS and TLS on first connection | | cold_start | true if this request paid for the TLS handshake; excluded from p95 calculations | | env | Environment tag from environment config option | | ts | Unix timestamp in milliseconds | | rl_remaining | Remaining quota, e.g. 4999 — present when vendor rate limit headers are found | | rl_limit | Total quota, e.g. 5000 — present when vendor rate limit headers are found | | rl_reset_at | Quota reset time in epoch milliseconds — present when vendor rate limit headers are found |

What is never captured

  • Request or response bodies
  • Request or response headers (including Authorization)
  • Query string parameters
  • Any credential, token, or secret your application uses to authenticate with a vendor
  • User identifiers or PII of any kind

Path normalization strips resource IDs before the event leaves your server. /v1/charges/ch_3Ox4Kz2e becomes /v1/charges/:id.


Rate limit headers

Apidepth automatically reads vendor rate-limit headers on every response. No configuration required. The following header names are checked in priority order:

| Field | Headers checked | | --------- | ----------------------------------------------------------------------------------- | | remaining | x-ratelimit-remaining-requests, x-ratelimit-remaining, ratelimit-remaining | | limit | x-ratelimit-limit-requests, x-ratelimit-limit, ratelimit-limit | | reset_at | x-ratelimit-reset-requests, x-ratelimit-reset, ratelimit-reset, retry-after |

The reset_at value is normalized to epoch milliseconds regardless of vendor format:

  • Unix timestamp (n ≥ 1 × 10⁹) — GitHub, HubSpot, IETF draft
  • Seconds from now (small integer) — Stripe Retry-After on 429
  • Duration string ("1s", "20ms", "1m30s") — OpenAI, Anthropic

Vendors with no quota headers on 2xx responses still contribute to 429 frequency tracking — the collector counts status = 429 events regardless of header availability.


Cluster / worker processes

Each worker process needs its own collector instance. Call Apidepth.reset() in each worker on startup:

// cluster setup
cluster.on("fork", (worker) => {
  worker.once("online", () => {
    // workers run this in their own process
  });
});

// inside each worker process
Apidepth.reset();
Apidepth.configure({ apiKey: process.env.APIDEPTH_API_KEY });
Apidepth.instrument();

To flush the primary process queue before forking:

import { Collector } from "apidepth";

// before fork
await Collector.getInstance().flush();

// in each worker
Apidepth.reset();

Debugging

Inspect the collector's internal state at any time:

import { Collector } from "apidepth";

console.log(Collector.getInstance().stats());
// {
//   queueSize: 0,
//   consecutiveFailures: 0,
//   totalDropped: 0,
//   lastFlushAt: 1747959127000
// }

lastFlushAt is only updated when events are actually delivered to the collector. If it's null or stale, check your apiKey and network connectivity.

totalDropped counts events discarded due to backpressure (queue full, max 5,000 events). A non-zero value means your flush interval is too long for your traffic volume — lower flushInterval or reduce sampleRate below 1.0.

To enable debug-level logging:

Apidepth.setLogger({
  debug: (msg) => console.debug(msg),
  info: (msg) => console.info(msg),
  warn: (msg) => console.warn(msg),
  error: (msg) => console.error(msg),
});

The default logger writes warn and error to console. Set a no-op logger to silence all output:

Apidepth.setLogger({ debug: () => {}, info: () => {}, warn: () => {}, error: () => {} });

Compatibility

| | Minimum | | ---------- | -------------- | | Node.js | 18 | | TypeScript | 5.0 (optional) |

The SDK instruments node:http and node:https at the module level. Most HTTP clients in the Node.js ecosystem (axios, got, node-fetch, undici in Node.js ≥ 18 via fetch) make requests through these modules and are instrumented automatically without additional configuration.

ESM and CJS are both supported. The package ships dual bundles (dist/index.mjs for ESM, dist/index.js for CJS) with full TypeScript declarations.


Contributing

git clone https://github.com/apidepth-io/apidepth-javascript
cd apidepth-javascript
npm install
npm test

The test suite requires no external services.

To verify the build:

npm run build
npm run typecheck

License

MIT. See LICENSE.