Guides

How to track Anthropic Claude cost per user

In short: every Claude response reports how many tokens it used. Read those numbers, price each kind at its own rate, add them to a total keyed by your user ID, and compare it with what that user pays you.

The Anthropic console shows usage by workspace, key and model. It can't tell you which of your users caused it, which is the number you need when everyone pays the same flat price.

1. Read the usage fields

A Messages API response has a usage object. Claude splits input into three separate counts, which matters for pricing:

const message = await anthropic.messages.create({ model, max_tokens, messages });

const u = message.usage;
// u.input_tokens                  new input tokens (NOT including cache reads or writes)
// u.cache_read_input_tokens       input served from the prompt cache
// u.cache_creation_input_tokens   input written to the cache on this call
// u.output_tokens                 output tokens (includes extended-thinking tokens)

Streaming: usage arrives in the stream events: input counts at the start and the final output count at the end. The SDK's helper that returns the final assembled message gives you the complete usage in one place, so use that instead of adding up events by hand.

2. Turn tokens into dollars

Anthropic publishes prices per million tokens. Cache reads are far cheaper than normal input, and cache writes cost a bit more than normal input, so each of the four counts gets its own rate:

cost = input_tokens                 × input_rate
     + cache_read_input_tokens     × cache_read_rate
     + cache_creation_input_tokens × cache_write_rate
     + output_tokens               × output_rate      (rate = price per million ÷ 1,000,000)
// Example rates only. Check the current numbers on Anthropic's pricing page.
const PRICE_PER_MTOK = { "claude-sonnet-5-5": { input: 3, cacheRead: 0.3, cacheWrite: 3.75, output: 15 } };

function costUsd(model: string, u: Anthropic.Usage) {
  const p = PRICE_PER_MTOK[model];
  if (!p) return null; // unknown model: flag it, don't count it as $0
  return (
    (u.input_tokens * p.input +
      (u.cache_read_input_tokens ?? 0) * p.cacheRead +
      (u.cache_creation_input_tokens ?? 0) * p.cacheWrite +
      u.output_tokens * p.output) / 1e6
  );
}

Mistakes that make Claude numbers wrong:

3. Store it per user

Insert one row per call with a unique event ID (so a retry can't count twice) and keep a per-user, per-day rollup that dashboards read. Do the write off the request path so a database problem never slows or fails a Claude call.

events(id uuid primary key, user_id, ts, model, input_tokens, cache_read_tokens, cache_write_tokens, output_tokens, cost_usd, feature)
daily_user_cost(user_id, day, cost_usd, requests)

4. Compare it with what they pay

A user who costs $8 a month is fine on a $30 plan and a loss on a $7.49 plan. Bring in net revenue per user (after store fees and tax) under the same user ID, and margin is net revenue − AI cost. Sort by it and the users losing you money come first.

The shortcut

FiscaLLM does steps 2 to 4. One line after each call sends the model and the token counts, including the cache fields. It never reads the answer text or your prompts.

import { createMeter } from "fiscallm";
const meter = createMeter({ apiKey: process.env.FISCALLM_KEY, waitUntil });

const message = await anthropic.messages.create({ model, max_tokens, messages });
meter.trackAnthropic(message, { userId, feature: "summary" });
from fiscallm import Meter
meter = Meter(api_key=os.environ["FISCALLM_KEY"])

message = client.messages.create(model=model, max_tokens=1024, messages=messages)
meter.track_anthropic(message, user_id=user_id, feature="summary")

Free and open source. Try the demo dashboard (no sign-up), see how it works, or start free. Using OpenAI too? Read the OpenAI version.

Questions

Can the Anthropic console show cost per user?

Not by your own users. It groups by workspace, API key and model. Per-user cost needs usage tracked in your own code.

Does prompt caching change how I track cost?

Yes. Cache reads and writes are billed at different rates from normal input, so they have to be counted separately.

Do I need to send prompts to track cost?

No. Cost depends only on the model and the token counts. Never send message content.