burn

Know what every LLM call costs.

burn is a local proxy. Point your SDK at it, and every request is priced and written to a SQLite ledger on your machine. Prompts and responses are not stored.

$npx @xnah/burn proxy

or install globally: npm install -g @xnah/burn

Node 22.5 or newer. MIT. No runtime dependencies.

Example ledger

Last 30 days

Total spend

$38.4200

Today

$4.2831

30d agotoday
Top modelsCost
  • claude-sonnet-4-5$12.84
  • gpt-4o$9.12
  • gemini-2.5-flash$1.46
  • other models$15.00

Example data. Your ledger stays in ~/.burn.

6
providers built in
0
runtime dependencies
24h
price cache
1
SQLite file, local

How it works

There is no account and no service to run. The proxy is a process on 127.0.0.1, and the database is a file you own.

  1. 01

    Start the proxy

    It prints the export lines and listens on 127.0.0.1. Leave it running while you work.

    npx @xnah/burn proxy
  2. 02

    Point your SDK at it

    Use the OpenAI or Anthropic route. The request is forwarded unchanged.

    OPENAI_BASE_URL=http://127.0.0.1:8787/openai/v1
  3. 03

    Read the ledger

    One command for the terminal, one for the dashboard. Both read the same SQLite file.

    burn today | burn ui

What it prints

The table shapes are the CLI's own. The numbers below are example data, not a claim about your traffic.

The same rows feed the reports, the dashboard, and the export. One request, one row, one price.

burn today
$ burn today

today: 128 requests, $4.2831

model                 requests   input   output   cached       cost
--------------------  --------  ------  -------  -------  ---------
claude-sonnet-4-5           41  284,102   61,330   18,204  $2.1042
gpt-4o                      52  120,994   44,812    9,300  $1.4021
gemini-2.5-flash            30   88,411    9,220        0  $0.0421
deepseek-chat                5    9,882    2,104        0  $0.0052

3 requests have no price. Run "burn price update" to fetch prices,
then "burn price recalc" to fill them in.
proxy log
$ npx @xnah/burn proxy
burn proxy listening on http://127.0.0.1:8787
providers: openai, anthropic, openrouter, deepseek, groq, gemini

export OPENAI_BASE_URL=http://127.0.0.1:8787/openai/v1
export ANTHROPIC_BASE_URL=http://127.0.0.1:8787/anthropic

point your SDK at those URLs. Ctrl+C to stop.

burn  openai  gpt-4o  $0.0124  in 1,842, out 316, cached 1,024
burn  anthropic  claude-sonnet-4-5  $0.0211  in 2,104, out 428, cache write 512
burn  gemini  gemini-2.5-flash  $0.0009  in 1,208, out 184

What is inside

The proxy does one job: forward the request, read the usage, price it, write a row. Everything else is a report on that row.

Providers

Six routes are built in. The first path segment picks the provider and the format.

  • openai/openai
  • anthropic/anthropic
  • openrouter/openrouter
  • deepseek/deepseek
  • groq/groq
  • gemini/gemini

Add any OpenAI-compatible endpoint with burn provider add.

The rest of the surface

Streaming responses
Reads usage from server-sent events as they arrive. Adds stream_options.include_usage for OpenAI chat streams when the caller did not ask for it.
A public price list
A LiteLLM-compatible map from CloudPrice, cached for 24 hours, with a bundled fallback for first runs and offline machines.
Budgets that can block
Set a daily limit. burn warns once per process, or answers HTTP 429 at the proxy once today passes it.

Tags per project

Send x-burn-tag with a request. The row is tagged and the header is stripped before forwarding.

CSV and JSON export

Every logged request, with token counts and cost, ready for a spreadsheet or another tool.

Zero dependencies

One package, Node 22.5 or newer, and the SQLite module that ships with Node.

MIT licensed

Read the source, change it, ship it. The CLI and this site are separate repositories.

The dashboard is the ledger.

burn ui serves one self-contained page from 127.0.0.1. No CDN, no external fonts, nothing loading from the network.

  • Range tabs for 24h, 7d, 30d, 90d, and all time.
  • Total spend, the previous period, and the last hour.
  • Spend by model, token split, and the 40 most recent requests.
  • Refreshes every 5 seconds and respects reduced motion.

burn ui --demo

Example data. Your ledger is untouched.

burn dashboard showing total spend, a spend graph, model breakdown, token split, and recent requests from demo data.
Captured from burn ui --demo. The page says "demo data, not your real ledger" while it runs.

Prompts do not go in the database.

burn writes metadata only. Not prompts, not completions, not request bodies. The database is a local file, and the dashboard reads from it on 127.0.0.1.

The only outbound call burn makes itself is the price list download. CloudPrice publishes it. Set BURN_OFFLINE=1 to turn even that off.

Read the security model

Stored

  • Timestamp
  • Provider
  • Model
  • Tag
  • Token counts
  • Cost
  • Latency
  • HTTP status
  • Stream flag

Never stored

  • Prompt text
  • Response text
  • Request bodies
  • Response bodies
  • API keys
  • Cookies
  • Client IP addresses
  • User identifiers

From zero to a row in SQLite.

Requires Node 22.5 or newer. Nothing else. The proxy prints the export lines for you.

  1. Start the proxy and leave it running.
  2. Point your SDK at 127.0.0.1:8787.
  3. Use your app, then run burn today or burn ui.
Full getting started guide
shell
$ npx @xnah/burn proxy

# in a second terminal, point your SDK at the proxy
export OPENAI_BASE_URL=http://127.0.0.1:8787/openai/v1

# use your app as usual, then read the ledger
burn today
burn ui

Questions

More detail lives in the documentation.

Does burn send my prompts or responses anywhere?

No. The proxy forwards the request to the provider and writes only metadata to the local SQLite database: timestamp, provider, model, tag, token counts, cost, latency, status, and whether the response was streamed. The only network call burn makes itself is the price list download.

Which providers work?

OpenAI, Anthropic, OpenRouter, DeepSeek, Groq, and Gemini are built in. Any OpenAI-compatible endpoint can be added with burn provider add, and Anthropic-format endpoints are supported too.

Does it work with streaming responses?

Yes. burn reads usage from server-sent events as they pass through. Only requests where the provider reports usage are logged. Nothing is estimated from text.

What happens when a model has no price?

The row is stored with no cost and the reports count it as unpriced. burn never guesses. Run burn price update and burn price recalc, or set a price by hand with burn price set.

Can I use it on a shared server?

The proxy binds to 127.0.0.1 and has no authentication. Anyone who can reach the port can use your provider credentials through it. Keep it on your own machine and do not expose it on a network interface.

Why does the number differ from my provider invoice?

Prices are best effort from a third-party list, and providers bill with their own rules: batch discounts, long-context tiers, priority tiers, free tiers, regions, and negotiated rates. burn is for watching trends and catching surprises, not for reconciling an invoice.