Skip to main content
With interceptOutbound: true (the default), ApiTraffic records the calls your application makes out to other APIs and correlates each one with the inbound request that caused it, so a request in the dashboard shows its downstream calls with their own timing, headers and payloads. Capture is read-only by design: your outbound call is issued exactly as your code wrote it, and payloads are read from copies. If anything about capture fails, the call still goes through — you lose the record, never the request.

What is captured

Two hooks cover the two ways Node.js makes an HTTP call: Both hooks produce the same record shape, so an axios call and a fetch call to the same service look the same in the dashboard.
Global fetch does not go through http.request — it drives Node’s built-in undici client straight onto a socket. That is why it has a separate hook, and why anything using fetch needs a client version that includes it. Requires Node 18 or later.

When a body is not captured

A record can arrive with the body marked as not captured. This is deliberate, not a failure, and happens when reading the payload would mean interfering with your call or holding a large amount of data in memory:
  • The payload is over the size cap. Bodies are capped per call (maxFetchBodyLength for fetch, 512 KB by default; API_TRAFFIC_MAX_FETCH_BODY_LENGTH to change it). Oversized payloads are stored truncated, or skipped when the server declares a length above the cap up front.
  • The payload is not text. Binary content types (images, archives, application/octet-stream) are recorded as metadata only. Server-sent event streams (text/event-stream) are captured up to the size cap on http/https calls, and recorded as metadata only on fetch, where reading a copy of a stream would keep it running after your code cancels it.
  • The request body is a stream, FormData or Blob. Reading it would consume the body your call is about to send, so it is left untouched.

When an outbound call is not captured at all

  • interceptOutbound is off, or captureFetch / API_TRAFFIC_CAPTURE_FETCH is off for fetch specifically.
  • Calls made before ApiTraffic is set up. The hooks are installed during setup, so a call issued at import time, before the middleware or plugin is registered, is not seen.
  • Something else replaced globalThis.fetch after setup. Instrumentation and mocking libraries normally wrap fetch, which is fine — ApiTraffic’s hook keeps working underneath, and installing it twice never stacks wrappers. But a library that assigns a brand new function to globalThis.fetch (some HTTP mocking and polyfill packages do this) removes ApiTraffic’s hook, and those calls are not recorded. If fetch calls are missing from your requests, check the order of your setup: ApiTraffic should be initialised after any library that replaces fetch wholesale.
  • Calls to ApiTraffic itself are excluded, so reporting traffic never shows up as your application’s outbound traffic.
  • The call goes through a client that bypasses both hooks, such as undici.request or a Pool. With APM installed these still appear on the request timeline, with timing and metadata but no bodies.

Redaction and exclusions

Outbound records go through the same redaction and exclusion rules as inbound traffic, so credentials in an outbound Authorization header or a payload field are masked by the same policy.