Outbound requests
How the ApiTraffic SDK captures the API calls your app makes, links them to the inbound request, and the cases where a body or a call is not captured.
ApiTraffic records the calls your application makes out to other APIs - payment providers, shipping and tax services, your own internal services - and links each one to the inbound request that caused it. A request in the dashboard then shows its downstream calls with their own timing, status, headers and bodies, so a slow or failing endpoint points at the dependency responsible.
Outbound capture is on by default in every Node SDK package and the Strapi plugin. It needs no code beyond registering ApiTraffic.
How outbound calls are captured
The SDK hooks the two ways Node.js makes HTTP calls:
| Your code uses | Captured by | What is recorded |
|---|---|---|
http.request, http.get, https.request, https.get, and clients built on them (axios, got, node-fetch, SOAP and SDK clients) |
The http/https hook |
URL, method, headers, request and response bodies, status, timing |
Global fetch, and libraries built on it |
The fetch hook |
The same, including the headers actually sent on the wire |
undici.request, undici.Client or undici.Pool used directly |
APM, when installed | Timing and metadata only, no bodies |
Both hooks produce the same record, so an axios call and a fetch call to the same service look the same in the dashboard.
Capture is read-only. Your call is sent exactly as your code wrote it, and bodies are read from copies. If anything about capture fails, the call still goes through: you lose the record, never the request.
Where outbound calls appear
- Inside a request. A call made while handling an inbound request appears on that request as an
http.outspan in its waterfall, and as an outbound record linked to it. Requests made in parallel keep their own calls, even on shared keep-alive connections. - Outside a request. Calls made by background jobs, timers or startup code have no inbound request. They are still recorded as outbound requests on their own.
- Failed calls. A call that gets no response at all (a DNS failure, a refused or reset connection, a timeout) is shown as a failed
http.outspan on the request that made it.
Outbound traffic has its own view in each bucket. In the sample data, for example, calls from the Acme Store API to payments.acme-pay.example and api.acme-freight.example appear under each checkout.
Outbound calls from the sample Acme Store API.

Turn outbound capture off
| To | Set |
|---|---|
| Stop capturing all outbound calls | interceptOutbound: false, or API_TRAFFIC_INTERCEPT_OUTBOUND=false |
Stop capturing only fetch calls |
captureFetch: false, or API_TRAFFIC_CAPTURE_FETCH=false |
| Capture smaller bodies | maxFetchBodyLength (bytes), or API_TRAFFIC_MAX_FETCH_BODY_LENGTH |
With interceptOutbound off, the SDK leaves http, https and fetch untouched. With only captureFetch off, an egress firewall policy still applies to fetch calls. See SDK configuration.
When a body is not captured
A record can arrive with a body shown as not captured. This is deliberate: it happens when reading the body would interfere with your call or hold too much data in memory.
- The body is over the size cap. Outbound bodies are captured up to
maxFetchBodyLength, 512 KB by default. Onhttp/httpsa larger body is cut at the cap. Onfetch, a response that declares aContent-Lengthover the cap is recorded without its body; a response without one (chunked) is captured as your code reads it, and cut at the cap. - The body is not text. Images, archives,
application/octet-streamand other binary types are recorded as[binary body omitted: …]with their size. - The response is compressed (
Content-Encodingsuch as gzip or br) on anhttp/httpscall. It is recorded as[compressed body not captured: …].fetchresponses are decompressed by Node, so their bodies are captured. - It is a stream on
fetch. Server-sent events (text/event-stream), NDJSON and similar streaming responses are recorded with metadata only, so ApiTraffic never keeps a stream open that your code has cancelled. Onhttp/https, server-sent events are captured as your code reads them, up to the cap. - Your code never reads a chunked
fetchresponse. A response without aContent-Lengthis captured as your code reads it, so one it has not read within 10 seconds is recorded with metadata only. One your code stops reading part way for 10 seconds, or is still reading a minute after it started, is recorded with what it read so far, marked truncated. - The
fetchrequest body is a stream,FormDataorBlob. Reading it would consume the body your call is about to send, so it is left untouched.
Once captured, outbound bodies go through the same limits as inbound ones, including maxBodyBytes.
When an outbound call is not captured
- Outbound capture is off, through
interceptOutboundor, forfetchonly,captureFetch. - The call was made before ApiTraffic started. The hooks are installed when the SDK sets up, which begins when you call the framework function (
apitraffic.express()and so on). A call made at import time, before that, is not seen. - Something replaced
globalThis.fetchafterwards. Libraries that wrapfetchare fine: ApiTraffic’s hook keeps working underneath, and installing it twice never stacks wrappers. A library that assigns a brand-new function toglobalThis.fetch(some mocking and polyfill packages do) removes the hook. Set up ApiTraffic after any library that replacesfetchwholesale. - The client bypasses both hooks, such as
undici.requestor an undiciPool. With APM installed these still appear, with timing and metadata but no bodies. - The call is to ApiTraffic itself. The SDK’s own traffic to the ingest and settings hosts is never reported.
Watch for new hosts
Every host your app calls out to can be kept in a list per bucket, with an alert the first time the app calls one it has never called before. A dependency that starts calling home after an update shows up the first time it does. See Watch for new outbound destinations.
Redaction and exclusions
Outbound records go through the same redaction rules and exclusions as inbound traffic, in your process, before anything is sent. Credential headers such as Authorization on an outbound call are always masked.
Related
-
SDK configuration: Capture switches and size limits.
-
Request details: See a request’s outbound calls in its waterfall.
-
How APM works: Database, cache and queue work alongside outbound calls.
-
Firewall policies: Inspect and block outbound calls with egress rules.