sergey-homenko/llm_cost_tracker
sergey-homenko/llm_cost_tracker has 45 GitHub stars and 4 forks. GitHot measured 0 stars in 24 hours and 0 in 7 days. Last checked 2026-11-09 10:27 UTC. Last push 2026-11-05.
LLM spend tracking and budgets for Rails — by user, feature, or any tag, in your own database, no proxy.
Measured star growth
- in 24h
- 0
- in 7 days
- 0
- in 15 days
- Update delayed
- in 1 month
- Update delayed
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
README.md
OriginalLLM Cost Tracker
LLM spend tracking and budgets for Rails: by user, feature, or any tag, in your own database, no proxy.
No prompts, no traces, no replay. Spend attribution only.
Requires Ruby 3.3+, Rails 8.0+, PostgreSQL or MySQL. Built for a Rails monolith, not multiple services.
Quickstart
Shown with RubyLLM; the flow is identical for the official OpenAI and Anthropic SDKs: swap the gem and the instrument name (see the cookbook).
# Gemfile
gem "llm_cost_tracker"
gem "ruby_llm"
bin/rails llm_cost_tracker:setup
Runs the install generator, writes a local price file, migrates the database, and verifies via llm_cost_tracker:doctor. Then enable the integration in the generated config/initializers/llm_cost_tracker.rb:
LlmCostTracker.configure do |config|
config.tags.default = -> { { environment: Rails.env } }
config.instrument :ruby_llm
end
Your RubyLLM calls stay unchanged, and every chat, embedding, transcription, image, and moderation call now lands in the ledger. Tag them to attribute spend:
LlmCostTracker.with_tags(user_id: Current.user&.id, feature: "chat") do
RubyLLM.chat.ask("Hello")
end
Mount the dashboard in config/routes.rb. The engine ships without authentication, so put it behind yours:
authenticate :admin do
mount LlmCostTracker::Engine => "/llm-costs"
end
What it records
- Calls. Provider, model, total tokens, total cost, latency, status.
- Line items. Per-component breakdown: text/audio/cached tokens, tool charges (web search, grounding, container sessions).
- Tags. Whatever attribution you pass: user, feature, tenant, env.
- Provider IDs. Response, plus project, API key and workspace when you pass them to
trackortrack_stream, for downstream audits. - Pricing snapshot. So historical numbers don't drift when prices change.
Budgets
Daily, monthly, and per-call limits, plus per-tag limits such as one monthly budget per tenant_id, or a lifetime cap in dollars or calls per agent run (run_id, which RubyLLM.workflow sets on its calls). A crossed limit calls your on_exceeded hook, raises, or blocks the next call before it is sent. See Budgets.
Supported clients
| Client | Captured through |
|---|---|
| RubyLLM | Instrumentation events (2.x) or the provider layer (1.x) |
| OpenAI, Anthropic | Official SDK or Faraday |
| Azure OpenAI | Official SDK or Faraday, on *.openai.azure.com, and Foundry *.services.ai.azure.com or *.cognitiveservices.azure.com |
Google Gemini, ruby-openai |
Faraday |
| OpenRouter, DeepSeek, Groq, xAI, Mistral, Perplexity | Faraday, or the official OpenAI SDK with base_url on that host |
| Other OpenAI-compatible gateways | The same, once the host is added to config.capture.openai_compatible_providers |
| Anything else | LlmCostTracker.track |
Streams are recorded from the provider's final usage; see Streaming.
Pricing
Captured does not always mean priced:
| Cost comes from | Calls |
|---|---|
The billed amount in the response or final stream chunk: usage.cost, xAI's usage.cost_in_usd_ticks, or Perplexity's usage.cost.total_cost |
OpenRouter, xAI, Perplexity, and other OpenAI-compatible gateways that return one (through RubyLLM 1.x, OpenRouter, xAI, and Perplexity chats only) |
Bundled prices.json, read from each provider's own pricing page or API |
The OpenAI, Anthropic, Gemini, Groq, OpenRouter, xAI, Mistral, DeepSeek, and Cohere models it lists, DeepSeek at its off-peak rates in its off-peak hours, and the same Claude models on Bedrock through RubyLLM |
| The OpenAI, Anthropic, or Gemini price for the same model name | Azure OpenAI (by the model in the response, not the deployment name), Vertex AI through RubyLLM, gateways that pass a listed model name through |
Nothing: recorded with cost_status: unknown |
Perplexity without a billed amount (its Router) when no price lists its model, calls through the official OpenAI SDK's Bedrock provider, and through RubyLLM also Ollama, Cohere models without a bundled price (such as Command A+, Embed 4, and Rerank 3.5), other Bedrock models, and Claude on GovCloud (us-gov. profiles) |
Add missing prices to config.pricing.file or config.pricing.overrides (Pricing), then run bin/rails llm_cost_tracker:backfill_unknown_pricing to price the calls already recorded. bin/rails llm_cost_tracker:prices:refresh runs it after writing a new config.pricing.file if the database is reachable.
Manual tracking
For batch jobs, internal gateways, or anything without an SDK or Faraday hook:
LlmCostTracker.track(
provider: :anthropic,
model: "claude-sonnet-4-6",
tokens: { input_tokens: 1500, output_tokens: 320 },
tags: { feature: "summarizer", user_id: current_user.id }
)
Docs
- Configuration
- Pricing
- Budgets
- Data model
- Querying
- Dashboard
- Streaming
- Cookbook
- Extending
- Operations
- Architecture
- EU AI Act record-keeping
- Upgrading
- Changelog
Development
bundle install
bin/check
License
MIT. See LICENSE.txt.
Explore related projects
affaan-m/ECC
The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.
300,313 starsNousResearch/hermes-agent
The agent that grows with you
262,134 starsmultica-ai/andrej-karpathy-skills
A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls.
231,460 starsfirecrawl/firecrawl
Supercharge your AI agents with data from the web and beyond. Building the library for superintelligence. 🔥
200,178 stars