Per-user LLM budgets compared: LiteLLM, Helicone, Langfuse, and doing it in-process
Vendor facts were checked against their documentation on October 11, 2026, and may have changed since. LLMBrake is our project, so weigh this accordingly, and tell us if we got something wrong.
If you charge customers a flat monthly price for an AI feature, you eventually need a rule like "each customer can spend at most $X of model cost per month." There are four common places to put that rule. Each makes a real trade-off, and for many teams the honest answer isn't the tool I wrote.
The question each tool answers
| Where it runs | Enforces a $ cap per customer? | What happens at the cap | Needs | |
|---|---|---|---|---|
| LiteLLM proxy | A proxy between your app and providers | Yes: budgets per customer/end-user, key, user and team | Proxy rejects the request (429 budget_exceeded), or reroutes to a cheaper model with per-key budget fallbacks |
Running the proxy and its database |
| Helicone | A gateway in the request path (hosted or self-hosted) | Yes: cost-based rate limit per user | Gateway returns 429 |
Routing requests through Helicone, plus headers |
| Langfuse | Observability (SDK/OTel traces, async) | No: tracks cost per user and alerts | You get an alert (Slack, webhook…) | Langfuse SDK/integration |
| In-process (e.g. llmbrake) | Inside your app code, around the client call | Yes: monthly budget per customer, plus downgrade | Throws before calling the provider | A store you own (memory, Redis, DB) |
LiteLLM proxy
LiteLLM's proxy has first-class budgets. You create customers (end users) with a max_budget and a budget_duration, or attach a shared budget created via /budget/new (which can also carry rpm/tpm limits). You pass the customer ID on each request, and the proxy tracks spend and rejects requests over budget. Keys, internal users and teams can have budgets too. Docs: https://docs.litellm.ai/docs/proxy/customers and https://docs.litellm.ai/docs/proxy/users
LiteLLM also has budget fallbacks (https://docs.litellm.ai/docs/proxy/budget_fallbacks): per-model caps on a virtual key (model_max_budget) with a chain of cheaper models (budget_fallbacks) to reroute to when a cap is hit. That's configured per key, not per customer, so check whether it maps onto your plans.
Things to know:
- Budgets and spend live in the proxy's database. Customer budgets are global per deployment: one budget per customer ID, shared across all keys and teams.
- LiteLLM caches budget objects for up to 60 seconds, so edits take up to a minute to apply.
- It's a whole gateway: routing, fallbacks, virtual keys, logging. That's a lot of value if you want it, and one more service to run if you don't.
Choose it if: you already run (or want) a central LLM gateway. If you're on LiteLLM's proxy today, use its customer budgets. You don't need another library.
Helicone
Helicone is an observability platform and gateway. Its custom rate limits can be cost-based and per user: send Helicone-RateLimit-Policy: 500;w=3600;u=cents;s=user plus Helicone-User-Id, and that user can spend 500 cents per hour before Helicone starts returning 429. The minimum window is 60 seconds. You also get cost per user and per custom property in the dashboard. Docs: https://docs.helicone.ai/features/advanced-usage/custom-rate-limits
Things to know:
- Requests go through Helicone's gateway (hosted, or self-hosted).
- The limit is a rolling-window rate limit. That's good for abuse protection; it maps less directly to "this customer's plan includes $20 per calendar month" with a downgrade step at 80%.
Choose it if: you want observability and per-user cost limits in one product and are fine routing through a gateway.
Langfuse
Langfuse traces your LLM calls and computes token usage and cost, broken down by user, session, feature and model. You can alert on cost metrics, filtered by user, model or tag, via Slack, webhooks or GitHub Actions (Langfuse Cloud plans include 2 to 100 alerts), and query everything via the Metrics API. If you route through OpenRouter or LiteLLM, Langfuse can record the cost they report directly. Docs: https://langfuse.com/docs/observability/features/token-and-cost-tracking
Things to know:
- It observes; it doesn't block. Langfuse's own guide on LLM cost management is clear about this: "For hard enforcement rather than notification, set budgets at your gateway." (https://langfuse.com/resources/engineering/llm-cost-management)
- Tracing is asynchronous, so alerts come after the spend.
Choose it if: you need visibility (which customers and features cost what) and evaluations. Pair it with an enforcement layer. They don't conflict.
In-process (llmbrake)
The fourth option skips the proxy. A small wrapper in your app checks the customer's spend before each call, picks a cheaper model near the cap or refuses at the cap, and records the cost from the response's token usage into a store you control.
const guard = createGuard({
budgetUsd: (ctx) => (ctx.plan === "pro" ? 20 : 2),
downgradeAt: 0.8,
downgradeMap: { "gpt-5.5": "gpt-5.4-mini" },
store: redisStore, // your Redis/DB
});
const create = guard.wrap(chat.create.bind(chat));
await create({ model: "gpt-5.5", messages }, { customerId: user.id, plan: user.plan });
What you get: no extra hop or service, your own provider keys, budgets computed from your own plan data, a downgrade step tied to each customer's budget, a typed error to drive an upgrade prompt, and metadata only (prompts and completions are never stored). That's llmbrake, MIT, on npm.
Things to know (honestly):
- It's v0.1.0. Chat-completions-style usage only: images, audio, embeddings and tool fees aren't priced.
- You maintain prices. It ships a dated price table you must verify. A gateway that reads provider-reported cost (OpenRouter returns
usage.cost) doesn't have this problem. - Concurrent overshoot. Spend is checked before a call and recorded after it, so parallel calls can overshoot the cap by their own cost. LiteLLM narrows this window by reserving estimated cost before each request.
- Dashboard: coming soon. The SDK gives you events (
onUsage) and astatus()call to feed your own logs. The hosted dashboard (per-customer cost, alerts, margin) is coming soon, with early access for founding members on the waitlist. - Every service needs it. If you call models from several services or languages, each one needs the wrapper (TypeScript and Python exist today). A central gateway enforces in one place.
Choose it if: you don't want a proxy in your request path, you want budgets tied to your own plans with a downgrade step, and you're fine owning a small store.
Combining them
These aren't exclusive:
- Langfuse + llmbrake: Langfuse for visibility and evals, llmbrake to enforce. Forward llmbrake's
onUsageevents as trace metadata if you want them in one place. - LiteLLM or Helicone alone: if you already route everything through a gateway, its budgets are the simpler choice. Adding an in-process layer only makes sense if you need plan-aware downgrades in app code.
- OpenRouter + llmbrake: wrap the OpenAI-compatible client and add OpenRouter model IDs to the price table.
A quick decision guide
- Already running a gateway (LiteLLM, Helicone)? → Use its per-customer budgets.
- Only need to see cost per customer? → Langfuse (or Helicone) dashboards and alerts.
- Need to enforce per-customer dollar caps, without a proxy, with plan-based budgets and downgrades? → In-process: llmbrake, or ~150 lines of your own using the same check → call → charge pattern.
If I've got something wrong about any of these tools, tell me and I'll fix it. Corrections are welcome: https://github.com/llmbrake/llmbrake/issues
Try the live demo (a browser simulation, no API keys needed), read the README, or see how LLMBrake compares with LiteLLM, Helicone and Langfuse.