SDK configuration reference
Every ApiTraffic Node SDK option and environment variable, its default and effect, how code, environment and account settings combine, and the per-request APIs.
This page lists every setting the ApiTraffic Node SDK reads, with its type, default and effect, and the functions you can call from your request-handling code. It applies to @apitraffic/node and to the per-framework packages (@apitraffic/express, @apitraffic/fastify, @apitraffic/koa, @apitraffic/hapi), which accept the same options. The Strapi plugin takes them through its plugin configuration; see Strapi.
Most applications need only two values, API_TRAFFIC_TOKEN and API_TRAFFIC_BUCKET. Everything that decides what is captured, redacted or blocked is set in your ApiTraffic account and delivered to the SDK, not configured here.
Where settings come from
The SDK combines three sources:
- Options you pass in code, to
apitraffic.express({...}),apitraffic.fastify({...})and the other framework calls. API_TRAFFIC_*environment variables, read when the SDK starts.- Settings delivered from your ApiTraffic account: redaction rules, exclusions, the firewall policy, APM capture switches and host telemetry. The SDK loads them on startup and receives changes in real time, without a restart.
Precedence
For every option in the tables below: an option passed in code wins over its environment variable, which wins over the built-in default. You can mix the two, for example the token from the environment and debug in code.
A few settings follow a different rule, and each is called out in its table:
| Setting | Rule |
|---|---|
offlineWafMode |
The environment variable API_TRAFFIC_OFFLINE_WAF_MODE wins over the code option, so you can change it during an incident without a deploy. |
| Firewall on or off | Off if either waf: false is passed or API_TRAFFIC_WAF_ENABLED=false is set. Neither can turn on a firewall your account has not enabled. |
captureStatementParams, captureRedisKeys |
On if either your code or environment turns it on, or the bucket’s APM Capture settings do. The dashboard can add capture, never remove what your code asked for. |
captureCallSite, captureStackDepth |
The bucket’s APM Capture setting applies, unless you set the option in code or the environment, which then wins. |
interceptOutbound |
A blank value ("" or null, or an empty environment variable) turns outbound capture off. For every other option, a blank value counts as not set. |
How values are parsed
Options that switch something on or off, and numeric limits, accept strings as well as booleans and numbers, so { captureSpans: process.env.CAPTURE_SPANS } works:
- Switches accept
true/false,yes/no,on/offor1/0, in any case. - Byte caps and counts must be whole numbers greater than 0.
captureStackDepthmay be 0. - Sample rates are numbers from
0to1. - A blank value (
"", spaces, ornull) counts as not provided, so the environment variable, then the default, applies. A blank never means 0 or off (except forinterceptOutbound). - An invalid value (
"abc",-5,1.5for a rate) is reported once on the console and ignored, and the next source applies.
Warning:
debugandstrictare not parsed from strings in code: passtrueorfalse.API_TRAFFIC_DEBUGturns debug logging on only when it is exactlytrue(any case);1oryesdo not.
Credentials and connection
| Option | Environment variable | Type | Default | Effect |
|---|---|---|---|---|
token |
API_TRAFFIC_TOKEN |
string | - | Required. Your ingest token. Without it the SDK logs an error and disables telemetry for the process; your app still starts. |
bucket |
API_TRAFFIC_BUCKET |
string | - | Required. The ID of the bucket captured traffic is sent to: seven lowercase letters and digits, such as k3m9p2x. The setup page and Bucket Settings show it. |
accountSid |
API_TRAFFIC_ACCOUNT_SID |
string | Learned from your account settings | Only needed by a process that mints embed tokens without running the ApiTraffic middleware. |
| - | API_TRAFFIC_EMBED_TOKEN |
string | - | An Administrator API token that embedToken() mints embed tokens with. The ingest token in API_TRAFFIC_TOKEN can’t mint them. A token passed to embedToken() takes precedence. It is a read credential to your captured traffic: set it only on servers that mint embed tokens, and keep it secret. |
apiHost |
API_TRAFFIC_API_HOST |
string | api.apitraffic.io |
Host the SDK loads its settings from. A bare host name means https://. |
ingestHost |
API_TRAFFIC_INGEST_HOST |
string | ingest.apitraffic.io |
Host captured traffic is sent to. A bare host name means https://. |
debug |
API_TRAFFIC_DEBUG |
boolean | false |
Log SDK activity to the console. Useful while installing; leave it off in production. |
strict |
- | boolean | false |
Throw at startup on misconfiguration (missing token or bucket) instead of logging and disabling telemetry. For apps that would rather not start than run unmonitored. |
The SDK warns once if apiHost or ingestHost is plain http:// and not this machine, because the token and captured requests would cross the network unencrypted.
Proxies. Delivery to ApiTraffic honors the standard HTTPS_PROXY, HTTP_PROXY, ALL_PROXY and NO_PROXY environment variables (in upper or lower case).
Capture
| Option | Environment variable | Type | Default | Effect |
|---|---|---|---|---|
interceptOutbound |
API_TRAFFIC_INTERCEPT_OUTBOUND |
switch | true |
Capture outbound calls made with http, https and fetch. Off leaves those modules untouched. See Outbound requests. |
captureFetch |
API_TRAFFIC_CAPTURE_FETCH |
switch | true |
Capture outbound global fetch calls (requires interceptOutbound). Off affects telemetry only: an egress firewall policy still applies to fetch. |
redactSensitiveKeys |
API_TRAFFIC_REDACT_SENSITIVE_KEYS |
switch | true |
Mask credential-shaped body keys and query parameters (password, token, secret, api_key and similar) in addition to your redaction rules. Credential headers are always masked. |
maxBodyBytes |
API_TRAFFIC_MAX_BODY_BYTES |
bytes | 524288 (512 KB) |
Largest request or response body sent to ApiTraffic. A larger body is replaced by a placeholder. Applied after redaction. |
maxRedactBodyBytes |
API_TRAFFIC_MAX_REDACT_BODY_BYTES |
bytes | 1048576 (1 MB) |
Largest body the SDK redacts. A larger body is replaced by a placeholder before any redaction work, so redaction cost stays bounded. |
maxFetchBodyLength |
API_TRAFFIC_MAX_FETCH_BODY_LENGTH |
bytes | 524288 (512 KB) |
Largest outbound request or response body captured, for http, https and fetch calls. |
requestSampleRate |
API_TRAFFIC_REQUEST_SAMPLE_RATE |
rate | 1 |
Fraction of captured requests sent. Requests with a 5xx response status are always sent, so 0 (only when given as 0 or "0") sends server errors only. |
Bodies that cannot be captured safely - nested more than 256 levels deep, unreadable, or not processable by your redaction rules - are replaced with a [body not captured: …] placeholder and the rest of the request is still sent. A request whose redaction cannot be completed at all is dropped, never sent unredacted.
Delivery
| Option | Environment variable | Type | Default | Effect |
|---|---|---|---|---|
ingestBatch |
API_TRAFFIC_INGEST_BATCH |
switch | true |
Send several payloads per request to ApiTraffic when your account and the ingest host both support it. false sends one request per payload. |
ingestGzip |
API_TRAFFIC_INGEST_GZIP |
switch | true |
Compress those batches when your account asks for it. |
Delivery limits (timeouts, queue size, circuit breaker) are fixed; they are described in If ApiTraffic is unreachable.
Spans and APM
These options control the spans recorded inside each request: database, cache, queue and outbound work from the APM bridge, and your own spans from span() and startSpan(). Set them on the framework call or with their environment variables.
| Option | Environment variable | Type | Default | Effect |
|---|---|---|---|---|
captureSpans |
API_TRAFFIC_CAPTURE_SPANS |
switch | true |
Master switch for spans and per-request span rollups. |
captureStatements |
API_TRAFFIC_CAPTURE_STATEMENTS |
switch | true |
Include the normalized SQL or command text (where id = ?) in spans. |
captureStatementParams |
API_TRAFFIC_CAPTURE_STATEMENT_PARAMS |
switch | false |
Also keep statements as issued, with their bind values. These carry your users’ data. Combines with the bucket’s Query Parameters setting: either one turns it on. |
captureRedisKeys |
API_TRAFFIC_CAPTURE_REDIS_KEYS |
switch | false |
Include the concrete Redis key, unmasked and not run through redaction rules. Combines with the bucket’s Redis Keys setting: either one turns it on. |
captureCallSite |
API_TRAFFIC_CAPTURE_CALL_SITE |
switch | true (bucket setting) |
Record the application code location (file:line) that started each span. Unset follows the bucket’s Code Location setting; set, it wins. |
captureStackDepth |
API_TRAFFIC_CAPTURE_STACK_DEPTH |
whole number, 0 or more | 10 (bucket setting) |
Application frames kept per span; 1 keeps the call site alone. Unset follows the bucket. |
projectRoot |
API_TRAFFIC_PROJECT_ROOT |
string | Detected | Directory code locations are reported relative to. Detected from your workspace file, .git or package.json; set it when a bundled or serverless build has removed those. |
redisKeyPatterns |
- | array of strings or RegExps | [] |
Patterns for Redis keys whose variable parts the automatic masking cannot infer. |
maxSpansPerRequest |
API_TRAFFIC_MAX_SPANS_PER_REQUEST |
count | 500 |
Spans kept per request. Work past the cap is still counted in the request’s rollups. |
spanSampleRate |
API_TRAFFIC_SPAN_SAMPLE_RATE |
rate | 1 |
Fraction of requests that keep full span detail. Rollups are computed for every request. |
maxSpanMetaBytes |
API_TRAFFIC_MAX_SPAN_META_BYTES |
bytes | 2048 |
Size cap on each span’s metadata, after redaction. |
sendStatementTextOnce |
API_TRAFFIC_SEND_STATEMENT_TEXT_ONCE |
switch | false |
Send each query’s statement text and call stack once per process per resend window, instead of on every span, to reduce payload size. |
statementTextResendSeconds |
API_TRAFFIC_STATEMENT_TEXT_RESEND_SECONDS |
count | 3600 |
How long text already sent is left off before it is sent again. |
statementTextCacheSize |
API_TRAFFIC_STATEMENT_TEXT_CACHE_SIZE |
count | 5000 |
Queries remembered per process for sendStatementTextOnce. |
Options for the APM preload
register() (and node -r @apitraffic/node/register, which calls it) takes its own options, from the call or from these environment variables. The switches above that it shares (captureSpans, captureStatements, captureStatementParams, captureRedisKeys, captureCallSite, captureStackDepth, maxSpanMetaBytes, debug) read the same variables.
| Option | Environment variable | Type | Default | Effect |
|---|---|---|---|---|
enabledInstrumentations |
API_TRAFFIC_ENABLED_INSTRUMENTATIONS |
list | [] |
Instrumentations to turn on beyond the default set, by full name (@opentelemetry/instrumentation-graphql) or short name (graphql). Comma-separated in the variable. |
disabledInstrumentations |
API_TRAFFIC_DISABLED_INSTRUMENTATIONS |
list | [] |
Instrumentations to turn off. Wins over everything else. |
instrumentHttp |
API_TRAFFIC_INSTRUMENT_HTTP |
switch | false |
Enable OpenTelemetry’s http/https client instrumentation. Off because the SDK already records those calls with bodies. |
synthesizeOutboundRecords |
API_TRAFFIC_SYNTHESIZE_OUTBOUND_RECORDS |
switch | true |
Record outbound calls the SDK cannot see itself, such as undici.request used directly, from their spans (metadata only). |
flushTimeoutMs |
API_TRAFFIC_APM_FLUSH_TIMEOUT_MS |
milliseconds | 5000 |
Longest the span processor’s flush or shutdown waits for queued payloads to be delivered. |
serviceName |
API_TRAFFIC_SERVICE_NAME |
string | - | Service name reported to OpenTelemetry. |
force |
API_TRAFFIC_APM_FORCE |
switch | false |
Start even though Datadog or New Relic appears to be active. Never overrides OTEL_SDK_DISABLED or an OpenTelemetry provider already registered. |
What the default instrumentation set covers, and how to use APM with an OpenTelemetry setup of your own, is in Set up APM.
Firewall options
With @apitraffic/node the firewall is always mounted and runs once your account has a live policy. These local controls exist mainly as overrides and kill switches.
| Option | Environment variable | Type | Default | Effect |
|---|---|---|---|---|
waf (@apitraffic/node only) |
API_TRAFFIC_WAF_ENABLED |
false or an object |
Unset | false, or the variable set to false, 0 or off, keeps the firewall off whatever your account says. An object passes the options below to the firewall without changing whether it runs. true means the same as unset. |
waf.enabled |
API_TRAFFIC_WAF_ENABLED |
boolean | true |
With @apitraffic/waf used directly: the master kill switch. |
waf.offlineWafMode |
API_TRAFFIC_OFFLINE_WAF_MODE |
'inherit', 'open' or 'closed' |
'inherit' |
What a server that has never loaded a policy does. inherit and open allow traffic; closed answers every request with 503 until a policy loads. The variable wins over the option. |
waf.onEvent |
- | function | - | Called for every inbound block or detection. |
waf.onEgressEvent |
- | function | - | Called for every outbound block or detection. |
waf.debug |
API_TRAFFIC_DEBUG |
boolean | false |
Log firewall decisions to the console. |
app.use(apitraffic.express({
waf: {
onEvent: (event) => logger.warn({ waf: event }, 'firewall event')
}
}));
Warning:
offlineWafMode: 'closed'is the only setting with which an ApiTraffic outage can stop your application serving traffic: a server that starts while ApiTraffic is unreachable, with no cached or pinned copy of your policy, refuses every request. If you use it, commit offline definitions. See If ApiTraffic is unreachable.
Offline definitions
| Environment variable | Default | Effect |
|---|---|---|
API_TRAFFIC_DEFINITIONS_PATH |
Unset | Path of the pinned definitions file. When set, it is the only place the SDK and the CLI look. |
API_TRAFFIC_CACHE_DIR |
node_modules/.cache/apitraffic |
Where the SDK keeps its last-known-good copy of your settings. |
API_TRAFFIC_FALLBACK_MAX_AGE_DAYS |
Unset (no limit) | Skip a pinned file older than this many days. |
See Offline definitions.
Server labels
These variables label each server on the Servers page and on the requests it serves. The SDK checks each list in order and uses the first variable that is set, so common platform variables work without extra setup.
| Label | Variables, in order |
|---|---|
| Service | API_TRAFFIC_SERVICE_NAME, SERVICE_NAME, K_SERVICE, FLY_APP_NAME |
| Service version | API_TRAFFIC_SERVICE_VERSION, SERVICE_VERSION, APP_VERSION |
| Region | API_TRAFFIC_REGION, AWS_REGION, AWS_DEFAULT_REGION, FLY_REGION, GOOGLE_CLOUD_REGION |
| Commit | API_TRAFFIC_GIT_SHA, GIT_SHA, GIT_COMMIT, SOURCE_VERSION, VERCEL_GIT_COMMIT_SHA, HEROKU_SLUG_COMMIT |
A service version must be at most 64 characters of letters, digits, ., _, + and -; a commit must be 7 to 40 hexadecimal characters. Other values are ignored.
Settings from your ApiTraffic account
These are configured in ApiTraffic and reach every connected server within seconds of a change. None of them needs a restart or a deploy.
| Setting | Where you change it | How it combines with local settings |
|---|---|---|
| Redaction rules | Account → Redactions | Applied in your process before anything is sent, in addition to the built-in masking. Requests are held until the rules have loaded. |
| Exclusions | Account → Exclusions | Matching requests are not sent. |
| Firewall policy | Account → Firewall (WAF), on plans that include it | waf: false or API_TRAFFIC_WAF_ENABLED=false keeps it off locally. |
| APM capture | Bucket Settings → APM Capture | Query Parameters and Redis Keys add to local settings and can switch off automatically under Auto-Disable. Code Location applies unless set locally. |
| Host telemetry | Bucket Settings → Host Telemetry | Server-side only. Your plan sets the fastest reporting interval. |
Per-request APIs
Call these from code that runs while a request is being handled: route handlers, middleware after ApiTraffic, and anything they call, including across await. Each one attaches to the request in progress. Outside a request they do nothing, and none of them ever throws into your code.
They are exported by @apitraffic/node and by each framework package. Import them from the package you installed:
const apitraffic = require('@apitraffic/node'); // or '@apitraffic/express', and so on
Tag a request
tag(key, value) attaches a searchable key-value pair, for example a customer or tenant ID, so you can find every request for that customer in the request log.
apitraffic.tag('customerId', String(req.user.id));
apitraffic.tag('plan', req.user.plan);
keyis 1 to 64 characters: a letter first, then letters, digits,_,.or-. Keys starting withwaf.,redaction.,apitraffic.orat.are reserved.valueis a string, number or boolean; numbers and booleans are stored as text. Values longer than 255 characters are cut to 255.nullorundefinedadds no tag.- A request holds at most 32 tag keys. Setting an existing key again replaces its value and does not count twice.
- A tag that breaks a rule is dropped and counted in Settings → Dimensions, never thrown into your handler. See the tag rules.
Trace a code path
trace(message) records a timestamped note on the request, a console log you can read in production:
apitraffic.trace('cart total exceeded the free-shipping threshold');
Each message is a string of at most 255 characters, and a request keeps at most 250 of them.
Time your own work
span(type, name, fn, meta?) runs fn, times it and records it as a span on the request’s waterfall. It returns exactly what fn returns, works with synchronous functions and promises, and re-throws fn’s error unchanged after marking the span failed. time() is the same function under another name.
const rates = await apitraffic.span('http.out', 'tax lookup', () => taxClient.rates(cart), {
host: 'api.acme-tax.example'
});
startSpan(type, name, meta?) is for work that does not fit one function. It returns a handle; call end() once when the work finishes:
const span = apitraffic.startSpan('queue', 'publish order.created');
try {
await queue.publish('order.created', order);
span.end();
} catch (error) {
span.end({ ok: false, meta: { error: error.code } });
throw error;
}
typeis one ofdb.query,redis,cache,http.out,queue,rpc,graphqlorcustom.metais an object of extra detail, redacted and capped atmaxSpanMetaBytes.setMeta(meta)on a handle adds to it beforeend().end({ ok: false })marks the span failed. Callingend()again does nothing.- With
captureSpansoff, spans are not recorded and the function still runs.
Read the request context
getRequestManager() returns the object holding the current request’s tags, traces and spans, or undefined outside a request. getContext() returns the SDK’s context store for the current request, or undefined outside one. Most applications never need either; prefer tag, trace and span.
Process-level functions
| Function | Returns | Use it to |
|---|---|---|
stats() |
Delivery counters | Check that telemetry is leaving the process: in flight, queued, delivered, recovered, dropped by cause, and whether the circuit breaker is open. @apitraffic/node only; @apitraffic/hapi also exports deliveryStats(). |
flush({ timeoutMs }) |
Promise<{ flushed, remaining }> |
Deliver what has been captured without stopping, for example before a serverless function is frozen. Default timeout 2 seconds. |
shutdown({ flushTimeoutMs }) |
Promise<{ flushed, remaining }> |
Stop capturing, deliver what is queued, and release the realtime connection, timers and hooks so the process can exit. See Shutting down. |
embedToken(options) |
Promise<{ token, expiresAt, tabs, features }> |
Mint a token for the embeddable request log. Rejects on failure. |
escapeCriteriaValue(value) |
string | Escape a value you put in double quotes inside an embed criteria string. Prefer filters.tags, which escapes for you. |
register(options) |
{ registered, reason } |
Start the APM bridge from code (@apitraffic/node only). Must run before your app loads the libraries it instruments. |
Related
-
Node SDK: Install and register the SDK for your framework.
-
Outbound requests: What is captured for the calls your app makes.
-
APM capture settings: The bucket switches that control what spans carry.
-
If ApiTraffic is unreachable: Delivery limits and what happens during an outage.