Troubleshooting

Fixes by symptom: no data, SDK cannot reach ApiTraffic, missing bodies, redaction, firewall, APM spans, outbound calls, MCP, API errors and plan limits.

This page as Markdown

Find your symptom below. Each answer lists the likely causes in the order they usually turn up.

Turn on SDK debug logging first

Most SDK problems explain themselves once debug logging is on. Set the environment variable and restart your app:

bash
API_TRAFFIC_DEBUG=true

Or pass debug: true to the framework call, for example apitraffic.express({ debug: true }). The SDK then logs its activity to the console, including why a send failed and whether it will retry ((will retry) or (permanent, not retrying)). Turn it off again when you are done; it is noisy.

Some problems are logged even without debug: a missing token, and requests dropped because redaction rules could not be loaded.

No data in ApiTraffic

Nothing arrives after installing the SDK

  1. Restart the process. The token and bucket are read at startup.
  2. Load your .env file. Node does not read it on its own. Start with node --env-file=.env server.js (Node 20.6 and later), or make require('dotenv/config'); the first line of your entry file. Without it, the SDK starts with no token and logs that API_TRAFFIC_TOKEN is missing.
  3. Check the credentials. API_TRAFFIC_TOKEN must be an Ingest token and API_TRAFFIC_BUCKET the bucket ID shown on the setup page. A value passed in code (token, bucket) overrides the environment variable.
  4. Check the runtime. SDK 2.x needs Node 20 or later.
  5. Check the network. See The SDK cannot reach ApiTraffic.

The setup page (Getting Started) shows whether ApiTraffic has heard from your SDK at all: Listening for your application means it has not, SDK connected - waiting for a request means the credentials work but nothing has been captured.

The SDK is connected, but no requests appear

  • Middleware order. Register ApiTraffic before your routes. Middleware added after a route never sees its requests.
  • The route you called. A health check or static file served before ApiTraffic in the middleware chain is not captured.
  • Exclusions. An exclusion rule drops matching requests in the SDK before they are sent. Check Account → Exclusions for a rule that is broader than you meant. See Exclusions.
  • Sampling. If you set requestSampleRate (or API_TRAFFIC_REQUEST_SAMPLE_RATE) below 1, only that share of requests is sent. Server errors (5xx) are always kept.

Requests appear in the wrong bucket or environment

The bucket comes from API_TRAFFIC_BUCKET (or the bucket option); the environment comes from the ingest token, because each token belongs to one environment. Check the environment menu at the top of the app, then check which token that deployment uses. To send staging traffic separately, create an ingest token in the staging environment. See Environments.

Data stopped arriving after it was working

  • Your plan or trial. If capture stopped at a specific time for every service at once, check Plan limits and usage caps.
  • A revoked token. If someone revoked the ingest token under Account → API Tokens, ingest refuses it permanently. Create a new one and redeploy.
  • A new exclusion. Someone may have added an exclusion that matches your traffic. Exclusions reach running servers without a deploy.
  • ApiTraffic itself. Check status.apitraffic.io.

The SDK cannot reach ApiTraffic

Firewalls, proxies and egress rules

The SDK makes outbound HTTPS connections to ingest.apitraffic.io (telemetry) and api.apitraffic.io (settings), plus a realtime connection that pushes setting changes. Allow outbound HTTPS from wherever your app runs: containers, serverless functions and locked-down VPCs often block it by default.

With API_TRAFFIC_DEBUG=true, failed sends are logged with the reason. Timeouts, resets and refused connections are retried briefly from a small in-memory queue, then dropped.

Will my app break if ApiTraffic is down?

No. Capture never blocks your responses or your startup, and the firewall keeps enforcing its last-known policy. The only setting with which an outage can affect your traffic is offlineWafMode: 'closed', which is off unless you turn it on. See If ApiTraffic is unreachable for the full behavior.

Request or response bodies are missing or truncated

The request body is empty

The SDK reads the body your framework parsed. In Express and Koa, register your body parser (express.json(), @koa/bodyparser) before ApiTraffic. A body nobody parsed is not captured, and the firewall cannot inspect it either.

The body shows a placeholder in square brackets

The SDK replaces bodies it cannot or should not send with a short placeholder:

Placeholder Why
[body not captured: N bytes exceeds the M-byte capture limit] The body is larger than maxBodyBytes (512 KB by default). It is replaced whole, not cut, so redaction rules never see half a document. Raise the limit with maxBodyBytes or API_TRAFFIC_MAX_BODY_BYTES if you need more.
…[truncated by ApiTraffic: N bytes total] The body was within the limit but grew past it during redaction, so the end was cut.
[streamed body not captured] The body was a stream the SDK could not copy as it was sent, such as a file download. Streams your app writes itself, such as server-sent events, are usually captured from the bytes sent, up to maxBodyBytes.
[binary body omitted: N bytes, type] The content type is not text.
[body not captured: could not be read] The body could not be read or serialized.
[body not captured: could not be redacted] Redaction failed for this body, so it was dropped rather than sent unredacted.
[body not captured: nested deeper than 256 levels] The JSON is nested too deeply to process safely.

Outbound calls made with fetch have their own cap, maxFetchBodyLength (512 KB by default). See Outbound requests.

The app shows only part of a large body

To keep the page responsive, request details show the first 100 KB of a large body with Show full body to load the rest. The full captured body is stored.

Redaction is not applied

A value I redacted still appears

  • Older requests. Rules apply to requests captured after you save them. Requests already stored are not changed.
  • Scope. Check that the rule covers the bucket, the environment and the part of the request (header, query, body) where the value appears.
  • Proxy and capture traffic. Redact at API rules run inside the SDK. Traffic that reaches ApiTraffic without an SDK, through the proxy or a capture URL, only gets Redact at server rules.
  • The SDK has turned default masking off. Credential-shaped keys (password, token, secret and similar) are masked by default unless the app sets redactSensitiveKeys: false or API_TRAFFIC_REDACT_SENSITIVE_KEYS=false.

See Redactions.

The SDK logged that it dropped requests waiting on redaction rules

The SDK does not send anything until your account’s redaction rules have loaded. If they cannot be loaded at startup, held requests are dropped rather than sent unredacted, and the SDK logs how many. This usually means the app cannot reach api.apitraffic.io; see The SDK cannot reach ApiTraffic.

A redacted value is missing from my workflow

Workflows receive the request as captured, before Redact at server rules run, so those rules never hide a value from a workflow. A value is missing when it was redacted inside your app, by a Redact at API rule or the SDK’s default masking of credential-shaped keys, because it never left your app; or when it’s a credential header such as Authorization, which is always masked. If a workflow needs the value, narrow the Redact at API rule that covers it (a specific scope, key or pattern), or change it to Redact at server so the value reaches the workflow but still isn’t stored. See Redactions.

The firewall blocks legitimate traffic

Stop the blocking now

Pick the fastest option for your situation:

  • Switch the policy’s Request Protection to Monitor under Account → Firewall (WAF). It keeps recording what it would block, but blocks nothing. Running servers pick up the change without a deploy.
  • Set API_TRAFFIC_WAF_ENABLED=false on the affected servers and restart them. This works even when ApiTraffic is unreachable.

Only owners and admins can change firewall policies.

Find out what matched and fix it

Open the blocked request and its WAF tab to see the decision, the policy, and each matched rule with its category, severity and score. Then, in the policy:

  • disable the managed rule if it does not apply to your API,
  • add a False Positive Exclusion for the route or field that triggers it (for example a rich-text field that looks like HTML), or
  • lower the paranoia level or raise the anomaly threshold.

Test the change in Monitor before you go back to Enforcing. See Firewall policies.

Every request is refused with 503

Your servers run with offlineWafMode: 'closed' and could not load a policy at startup, usually because they cannot reach ApiTraffic. Fix the network path, or use the default open mode. See If ApiTraffic is unreachable.

APM spans are missing

Requests have no waterfall

  • The start command. APM needs the preload: node -r @apitraffic/node/register ./server.js. ES-module apps use --import instead; see Set up APM.
  • The OpenTelemetry packages. If they are missing, APM is skipped and the console says otel-peers-missing.
  • Load order. If your database or cache client is loaded before APM starts, it is never instrumented. The preload exists to avoid this; register() lists the modules it found already loaded.
  • Another tracer. With Datadog or New Relic running (other-apm-detected), or an OpenTelemetry tracer provider already registered (provider-already-active), the bundled setup steps aside. Add the ApiTraffic span processor to your existing setup instead.
  • Capture settings. Check the APM Capture tab in Bucket Settings. See APM capture settings.

Some operations are missing

The bundled setup instruments a curated set of libraries: pg, mysql, mysql2, mongodb, tedious, oracledb, cassandra-driver, redis, ioredis, memcached, undici (fetch), amqplib, kafkajs and the AWS SDK. Others are opt-in with enabledInstrumentations. A request records up to 500 spans by default (maxSpansPerRequest).

Outbound calls are not captured

No outbound requests appear

  • The switch. Outbound capture is on by default. Check that the app does not set interceptOutbound: false or API_TRAFFIC_INTERCEPT_OUTBOUND=false.
  • The client. Calls through http/https (axios, got, node-fetch) and global fetch are captured. Calls made with undici.request, undici.Client or undici.Pool directly are recorded only as APM spans, without bodies.
  • The SDK version. Capturing global fetch needs SDK 2.x on Node 20 or later.

See Outbound requests.

MCP and OAuth connection problems

My MCP client cannot connect

  • Use the server URL https://api.apitraffic.io/mcp.
  • Check that your plan includes the MCP server.
  • For OAuth, sign in to ApiTraffic in the browser window your client opens, and approve the connection. If the client offers fields for an OAuth client ID and secret, leave them empty.
  • For a static token, create it under Account → MCP Tokens (owners and admins) and send it as your client’s configuration describes.

See MCP server.

The agent connects but sees no data, or the wrong data

MCP tokens and OAuth connections are limited to the environment and buckets chosen when they were created or approved. Check the selection under Account → MCP Tokens or Account → Connected Apps. The sample bucket is never visible to MCP connections.

A connection that worked has stopped

An OAuth connection ends when it is disconnected under Account → Connected Apps, when the person who approved it leaves the account or is signed out everywhere (for example after a password change), when its environment is deleted, or after 30 days without use. Reconnect from your client. See Connected apps and OAuth.

The API returns 401, 403 or 429

401 Unauthorized

The token is missing, invalid, revoked or expired. Check the Authorization header and that the token still exists under API Tokens. See Authentication.

403 Forbidden

Read the numeric code in the response body:

Code Meaning
2010 Your role, or the token’s role, cannot do this. Creating tokens, generating embed tokens, changing redactions, exclusions, firewall policies, the MFA policy and account settings, and turning on SQL parameter or Redis key capture need an owner or admin (or an Administrator token). Ingest tokens can only send traffic and read SDK settings; use an Administrator or User token for the REST API. To mint embed tokens with the Node SDK, set an Administrator token as API_TRAFFIC_EMBED_TOKEN.
2221 Your plan does not include this feature. data.feature names it.
2509 The call tried to change the read-only sample bucket.
2510 Sample data is turned off for the account.
2012 The account requires multi-factor authentication.

429 Too Many Requests

Either you exceeded the API’s per-minute rate limit, or a hard-capped plan allowance (such as MCP calls) is used up for this billing period (code 2222). Rate-limit responses carry Retry-After and RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers: wait the number of seconds in Retry-After and retry.

Plan limits and usage caps

Capture stopped and the SDK logs a 429

A hard-capped allowance, such as included requests, is used up for the billing period. Ingest answers 429 with a Retry-After that points to the end of the period, when the counter resets. The SDK honors it and resumes on its own. To resume sooner, upgrade your plan. Plans that bill overage are never blocked. Check Account → Usage.

We email you when an allowance reaches 80% and again at 100%.

Capture stopped and the SDK logs a 402

Your account has no active subscription: the trial ended, or the subscription was cancelled, paused, unpaid or never completed. The response explains which. Choose or fix your plan under Account → Billing; capture resumes shortly after. Your application keeps running either way. See Plan, usage and billing.

I cannot create another bucket or environment

Your plan limits how many you can have. Delete one you no longer use, or upgrade. The sample bucket does not count.

A page shows an upgrade prompt

The feature is not included in your plan. You can still see it fully populated on the sample bucket.

Still stuck?

Choose Ask for help on the setup page, or email [email protected]. Include your bucket ID, the SDK version and the console output with API_TRAFFIC_DEBUG=true, with tokens removed.