# Troubleshooting

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

Source: https://www.apitraffic.io/docs/troubleshooting

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-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](https://www.apitraffic.io/docs/data/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](https://www.apitraffic.io/docs/account/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](#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](https://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](https://www.apitraffic.io/docs/reference/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](https://www.apitraffic.io/docs/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](https://www.apitraffic.io/docs/data/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](#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](https://www.apitraffic.io/docs/data/redactions#where-a-rule-runs).

## 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](https://www.apitraffic.io/docs/waf/policies#handle-false-positives) 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](https://www.apitraffic.io/docs/waf/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](https://www.apitraffic.io/docs/reference/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](https://www.apitraffic.io/docs/apm/setup).
- **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](https://www.apitraffic.io/docs/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](https://www.apitraffic.io/docs/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](https://www.apitraffic.io/docs/integrations/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](https://www.apitraffic.io/docs/integrations/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](https://www.apitraffic.io/docs/api-reference/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](https://www.apitraffic.io/docs/account/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](https://www.apitraffic.io/docs/sample-data).

## Still stuck?

Choose **Ask for help** on the setup page, or email [support@apitraffic.io](mailto:support@apitraffic.io). Include your bucket ID, the SDK version and the console output with `API_TRAFFIC_DEBUG=true`, with tokens removed.

## Related

- [Quickstart](https://www.apitraffic.io/docs/quickstart):
    The install steps, from the start.

- [SDK configuration](https://www.apitraffic.io/docs/integrations/configuration):
    Every option and environment variable.

- [If ApiTraffic is unreachable](https://www.apitraffic.io/docs/reference/unreachable):
    What the SDK does during an outage.

- [FAQ](https://www.apitraffic.io/docs/faq):
    Data, performance and compatibility questions.
