Configuration
All TrackerOptions fields, environment variables, development mode, attribution context, and the dexcost CLI.
Configuration options
Pass any of these to init() or the CostTracker constructor. All fields are optional.
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | undefined — falls back to DEXCOST_API_KEY | API key for cloud push. Must start with dx_live_ (production) or dx_test_ (sandbox). |
autoInstrument | string[] | All supported providers | Which LLM SDKs to auto-patch. Pass [] to disable auto-instrumentation. Valid names: "openai", "anthropic", "vercel-ai", "gemini", "bedrock", "cohere", "mcp". |
trackHttp | boolean | true | Patch globalThis.fetch and Node's http/https modules to record non-LLM HTTP costs. |
environment | string | undefined — falls back to DEXCOST_ENV | Set to "development" to enable dev mode (events printed to stderr, no cloud push). |
batchSize | number | 100 | Maximum number of events per batch sent to the Control Layer. |
flushIntervalMs | number | 30000 | Milliseconds between background sync pushes. |
redactFields | string[] | undefined (no redaction) | Field names to remove from details before storage (e.g. ["prompt", "completion"]). |
hashCustomerId | boolean | false | SHA-256 hash customerId before storing it, so raw identifiers never leave the process. |
storage | "local" | "cloud" | Auto-detect from API key | Force "local" to disable cloud push regardless of API key; "cloud" requires a valid key. |
dbPath | string | ~/.dexcost/buffer.db | Path to the local SQLite buffer file. Override to get per-test or per-process isolation. |
serviceCatalogUrl | string | undefined | URL to refresh the HTTP service catalog from at startup. |
enableRetryHeuristics | boolean | false | Enable the RetryHeuristicEngine for automatic retry detection on recordLlmCall. |
retryHeuristicWindow | number | 30 | Sliding-window size in seconds for heuristic retry detection. |
retryHeuristicThreshold | number | 0.8 | Minimum confidence score (0–1) required to flag an event as a retry. |
init() returns the CostTracker instance it created, which is stored globally and returned by getTracker() thereafter. Calling init() when a global instance already exists throws an Error — call close() or closeAsync() first to reset.
Environment variables
| Variable | Description |
|---|---|
DEXCOST_API_KEY | API key. Read when apiKey is not passed to init() and storage is not "local". |
DEXCOST_ENV | Set to development to enable dev mode without passing environment to init(). |
DEXCOST_ENDPOINT | Override the Control Layer URL. Defaults to https://api.dexcost.io. |
Environment variables are read during CostTracker construction (inside resolveConfig), so they take effect when init() is called.
Development mode
Pass environment: "development" (or set DEXCOST_ENV=development) to enable dev mode:
import { init, track } from 'dexcost';
init({ environment: 'development' });
await track({ taskType: 'my_task', customerId: 'local-test' }, async (task) => {
task.recordCost('pdf_parser', 0.002);
});In dev mode:
- Every
llm_callandexternal_costevent is printed to stderr as it is recorded. - Task completion is printed with aggregated cost totals.
- No data is written to the cloud — the
EventPusheris not started. - An API key is not required.
Dev mode is detected by isDevMode(), which returns true when enableDevMode() has been called (triggered by environment === "development" or DEXCOST_ENV=development).
Attribution & context
setContext() stores attribution values in an AsyncLocalStorage store so every subsequent auto-instrumented LLM call and track() call in the same async chain inherits them automatically. Call it once at the beginning of a request or job:
import { setContext, clearContext } from 'dexcost';
setContext({
customerId: 'acme-corp',
projectId: 'chatbot-v2',
metadata: { tier: 'enterprise', region: 'us-east-1' },
agent: 'support_agent',
});| Parameter | Type | Description |
|---|---|---|
customerId | string | Identifier for the customer being served. |
projectId | string | Identifier for the project or product. |
metadata | Record<string, unknown> | Arbitrary key-value pairs attached to the context. |
agent | string | Agent name label — available in the context for downstream use. |
setContext() uses AsyncLocalStorage.enterWith() (Node 18+), so it affects the remaining async chain without wrapping in a callback. For concurrent request isolation (e.g., an Express server), call setContext() inside per-request middleware — each request's async context is isolated by Node's AsyncLocalStorage.
getContext() returns the current DexcostContext, or undefined if setContext() has not been called. clearContext() replaces the current context with an empty object, effectively clearing it for the remaining async chain.
const ctx = getContext();
// ctx?.customerId, ctx?.projectId, ctx?.metadata, ctx?.agent
clearContext();CLI
The dexcost CLI requires no API key and works offline against the local SQLite buffer.
dexcost status
Show the state of the local buffer:
dexcost status
dexcost status --db /path/to/buffer.dbOutput includes: DB location, event count, task count, pending/synced event counts, last task timestamp, pricing engine version, and detected versions of LLM SDKs (openai, @anthropic-ai/sdk).
dexcost rates
Manage the per-service cost rate registry:
# List all registered rates
dexcost rates --list
# Import rates from a YAML file
dexcost rates --import rates.yaml
# Export current rates to a YAML file
dexcost rates --export rates.yaml--import and --export can be combined. Import runs first, so --list after --import shows the loaded rates.
YAML format expected by --import:
rates:
maps.googleapis.com:
per: request
cost_usd: "0.005"
ocr-api.com:
per: page
cost_usd: "0.01"YAML support requires js-yaml to be installed (npm install js-yaml).
dexcost scan
Static-analysis scan of your TypeScript/JavaScript codebase to find cost points that are not yet tracked:
dexcost scan ./src
dexcost scan ./src --generate-stubsscan walks .ts, .tsx, .js, .jsx, and .mjs files (skipping node_modules, dist, .git, coverage), detects LLM calls (reported as auto-instrumentable), and flags external API calls that likely incur cost but have no recordCost() call nearby (reported as needing manual recording).
--generate-stubs prints ready-to-paste recordCost() snippets for each untracked cost point found. No API key or network connection is required.