dexcost
TypeScript

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.

OptionTypeDefaultDescription
apiKeystringundefined — falls back to DEXCOST_API_KEYAPI key for cloud push. Must start with dx_live_ (production) or dx_test_ (sandbox).
autoInstrumentstring[]All supported providersWhich LLM SDKs to auto-patch. Pass [] to disable auto-instrumentation. Valid names: "openai", "anthropic", "vercel-ai", "gemini", "bedrock", "cohere", "mcp".
trackHttpbooleantruePatch globalThis.fetch and Node's http/https modules to record non-LLM HTTP costs.
environmentstringundefined — falls back to DEXCOST_ENVSet to "development" to enable dev mode (events printed to stderr, no cloud push).
batchSizenumber100Maximum number of events per batch sent to the Control Layer.
flushIntervalMsnumber30000Milliseconds between background sync pushes.
redactFieldsstring[]undefined (no redaction)Field names to remove from details before storage (e.g. ["prompt", "completion"]).
hashCustomerIdbooleanfalseSHA-256 hash customerId before storing it, so raw identifiers never leave the process.
storage"local" | "cloud"Auto-detect from API keyForce "local" to disable cloud push regardless of API key; "cloud" requires a valid key.
dbPathstring~/.dexcost/buffer.dbPath to the local SQLite buffer file. Override to get per-test or per-process isolation.
serviceCatalogUrlstringundefinedURL to refresh the HTTP service catalog from at startup.
enableRetryHeuristicsbooleanfalseEnable the RetryHeuristicEngine for automatic retry detection on recordLlmCall.
retryHeuristicWindownumber30Sliding-window size in seconds for heuristic retry detection.
retryHeuristicThresholdnumber0.8Minimum 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

VariableDescription
DEXCOST_API_KEYAPI key. Read when apiKey is not passed to init() and storage is not "local".
DEXCOST_ENVSet to development to enable dev mode without passing environment to init().
DEXCOST_ENDPOINTOverride 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_call and external_cost event is printed to stderr as it is recorded.
  • Task completion is printed with aggregated cost totals.
  • No data is written to the cloud — the EventPusher is 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',
});
ParameterTypeDescription
customerIdstringIdentifier for the customer being served.
projectIdstringIdentifier for the project or product.
metadataRecord<string, unknown>Arbitrary key-value pairs attached to the context.
agentstringAgent 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.db

Output 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-stubs

scan 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.

On this page