cd /news/developer-tools/track-your-llm-api-spend-with-a-pyth… · home topics developer-tools article
[ARTICLE · art-89483] src=sourcefeed.dev ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Track Your LLM API Spend with a Python Token Usage Dashboard

Priya Nair published a tutorial for building a Python token usage dashboard that logs tokens and dollar cost for every OpenAI, Anthropic, and Gemini API call into SQLite and visualizes spend via a Streamlit app. The toolkit, verified against openai 2.41.1, anthropic 0.121.0, google-genai 2.17.0, and streamlit 1.61.0 as of August 2026, uses per-model price tables (e.g., gpt-5.6-terra at $2.00 input/$12.00 output per 1M tokens) and provider-specific wrappers to capture usage data. The dashboard helps developers identify which calls are driving up their LLM API costs.

read5 min views1 publishedAug 9, 2026
Track Your LLM API Spend with a Python Token Usage Dashboard
Image: Sourcefeed (auto-discovered)

Log tokens and cost for every OpenAI, Anthropic, and Gemini call, then chart spend in Streamlit.

Priya Nair

What you'll build #

A small Python toolkit that logs tokens and dollar cost for every call you make to OpenAI, Anthropic, and Gemini into SQLite, plus a Streamlit dashboard that shows total spend, cost per model, and cost per request — so you can spot which calls are burning your budget.

Prerequisites #

  • Python 3.10+ (required by both openai

andgoogle-genai

) - API keys for OpenAI,Anthropic, andGemini— each provider needs its own account - Verified against: openai

2.41.1,anthropic

0.121.0,google-genai

2.17.0,streamlit

1.61.0, and each provider's official pricing page as of August 2026 - Commands below are for macOS/Linux; on Windows PowerShell, replace export X="y"

with$env:X="y"

Step 1: Install the SDKs and set your keys #

mkdir llm-spend && cd llm-spend
python -m venv .venv && source .venv/bin/activate
pip install openai anthropic google-genai streamlit pandas

export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
export GEMINI_API_KEY="AIza..."

All three SDKs read their key from these exact environment variable names automatically — no key-passing code needed.

Step 2: Write the usage tracker #

Create tracker.py

. The price table is USD per 1M tokens, taken from each provider's official pricing page (August 2026) — prices change, so re-check them when you add models.

import sqlite3
import time

DB = "usage.db"

PRICES = {
    "gpt-5.6-terra":    {"input": 2.00, "output": 12.00},
    "claude-opus-5":    {"input": 5.00, "output": 25.00},
    "gemini-3.6-flash": {"input": 1.50, "output": 7.50},
}

def init_db():
    with sqlite3.connect(DB) as con:
        con.execute("""CREATE TABLE IF NOT EXISTS usage (
            ts REAL, provider TEXT, model TEXT,
            input_tokens INTEGER, output_tokens INTEGER, cost_usd REAL)""")

def log_usage(provider, model, input_tokens, output_tokens):
    p = PRICES[model]
    cost = (input_tokens * p["input"] + output_tokens * p["output"]) / 1_000_000
    with sqlite3.connect(DB) as con:
        con.execute("INSERT INTO usage VALUES (?, ?, ?, ?, ?, ?)",
                    (time.time(), provider, model, input_tokens, output_tokens, cost))
    return cost

Step 3: Instrument each provider #

Create llm.py

. Each wrapper makes the call, reads the provider's usage object, and logs it. The field names differ per provider — that's the whole reason to centralize this.

import anthropic
from google import genai
from openai import OpenAI
from tracker import init_db, log_usage

init_db()
openai_client = OpenAI()
anthropic_client = anthropic.Anthropic()
gemini_client = genai.Client()

def ask_openai(prompt: str) -> str:
    r = openai_client.responses.create(model="gpt-5.6-terra", input=prompt)
    log_usage("openai", "gpt-5.6-terra", r.usage.input_tokens, r.usage.output_tokens)
    return r.output_text

def ask_anthropic(prompt: str) -> str:
    r = anthropic_client.messages.create(
        model="claude-opus-5",
        max_tokens=8192,  # caps thinking + answer together; don't lowball it
        messages=[{"role": "user", "content": prompt}],
    )
    log_usage("anthropic", "claude-opus-5", r.usage.input_tokens, r.usage.output_tokens)
    return next(b.text for b in r.content if b.type == "text")

def ask_gemini(prompt: str) -> str:
    r = gemini_client.interactions.create(model="gemini-3.6-flash", input=prompt)
    out = r.usage.total_output_tokens + (r.usage.total_thought_tokens or 0)
    log_usage("google", "gemini-3.6-flash", r.usage.total_input_tokens, out)
    return r.output_text

Claude's usage.output_tokens

already includes thinking tokens; Gemini's Interactions API splits them into total_thought_tokens

, so we add them back before pricing.

Step 4: Generate some traffic #

Create demo.py

and run it with python demo.py

:

from llm import ask_anthropic, ask_gemini, ask_openai

q = "In one sentence, why is the sky blue?"
for name, fn in [("OpenAI", ask_openai), ("Anthropic", ask_anthropic), ("Gemini", ask_gemini)]:
    print(f"{name}: {fn(q)[:100]}")

Step 5: Build the dashboard #

Create dashboard.py

:

import sqlite3
import pandas as pd
import streamlit as st

st.title("LLM API Spend")

with sqlite3.connect("usage.db") as con:
    df = pd.read_sql_query("SELECT * FROM usage", con)
df["ts"] = pd.to_datetime(df["ts"], unit="s")

c1, c2, c3 = st.columns(3)
c1.metric("Total spend", f"${df.cost_usd.sum():.4f}")
c2.metric("Requests", len(df))
c3.metric("Avg cost / request", f"${df.cost_usd.mean():.4f}")

st.subheader("Spend by model")
st.bar_chart(df.groupby("model")["cost_usd"].sum())

st.subheader("Cost per request over time")
st.scatter_chart(df, x="ts", y="cost_usd", color="model")

st.subheader("Raw log")
st.dataframe(df.sort_values("ts", ascending=False))

Launch it:

streamlit run dashboard.py

Verify it works #

python demo.py

should print one answer per provider, then confirm the rows landed:

python -c "import sqlite3; [print(r) for r in sqlite3.connect('usage.db').execute(
    'SELECT provider, model, input_tokens, output_tokens, round(cost_usd, 6) FROM usage')]"

Expected (token counts will vary):

('openai', 'gpt-5.6-terra', 18, 24, 0.000324)
('anthropic', 'claude-opus-5', 16, 310, 0.00783)
('google', 'gemini-3.6-flash', 11, 245, 0.001854)

streamlit run dashboard.py

prints Local URL: http://localhost:8501

and opens a page with three metric tiles, a bar chart of spend per model, and a scatter of cost per request. The Anthropic bar will dominate — Claude Opus 5's $25/1M output rate plus thinking tokens is exactly the kind of thing this dashboard exists to surface.

Troubleshooting #

— the key isn't in this shell.openai.AuthenticationError: Error code: 401 ... Incorrect API key provided

export OPENAI_API_KEY=...

in the same terminal you run Python from (env vars don't persist across sessions), then retry.— same cause on the Anthropic side:anthropic.AuthenticationError: Error code: 401 ... {'type': 'authentication_error', 'message': 'invalid x-api-key'}

ANTHROPIC_API_KEY

is unset or pasted with whitespace. Re-export it.— Gemini keys come fromgoogle.genai.errors.ClientError: 400 INVALID_ARGUMENT ... API key not valid. Please pass a valid API key.

Google AI Studio, not Google Cloud Console; make sureGEMINI_API_KEY

holds an AI Studio key.when opening the dashboard — you ran Streamlit before any calls were logged. Runsqlite3.OperationalError: no such table: usage

python demo.py

first sousage.db

exists.

Next steps #

  • Log cached-token counts ( cache_read_input_tokens

on Anthropic,total_cached_tokens

on Gemini) — cached input is billed at a steep discount, and separating it shows whether prompt caching is actually working. - Set a daily budget: query today's SUM(cost_usd)

before each call and raise if you're over. - For production, ship the rows to Postgres instead of SQLite and tag each one with a feature or user ID so spend maps to product areas.

Sources & further reading #

API Pricing— developers.openai.com - Developer quickstart— developers.openai.com - Gemini API Pricing— ai.google.dev - Interactions API reference— ai.google.dev - Pricing— platform.claude.com - 2026 release notes— docs.streamlit.io

Priya Nair· AI & Developer Experience Writer

Priya covers AI frameworks, developer productivity tooling, and the startup ecosystem across South and Southeast Asia, bringing a researcher's rigour and a practitioner's empathy to every story. She is deeply sceptical of benchmarks and asks hard questions so her readers don't have to.

Discussion 0 #

No comments yet

Be the first to weigh in.

── more in #developer-tools 4 stories · sorted by recency
── more on @priya nair 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/track-your-llm-api-s…] indexed:0 read:5min 2026-08-09 ·