Methodology
Methodology
This report is built from the Cornelson Advisory analytics BigQuery dataset, which is populated daily by the llm-usage-pipeline Cloud Run Job. This page is the source of truth for what the numbers mean and where they can be wrong.
Data sources
Anthropic — Admin API (organization-level):
GET /v1/organizations/usage_report/messages(token volumes)GET /v1/organizations/cost_report(USD cost)
OpenAI — Admin API (organization-level):
GET /v1/organization/usage/completionsGET /v1/organization/usage/embeddingsGET /v1/organization/costs
Both endpoints require admin-scope keys. Personal API keys cannot read org-level usage.
Refresh cadence
| Step | When |
|---|---|
| Provider data settles | end of UTC day |
| Cloud Run Job pulls yesterday | 06:00 UTC daily |
| BigQuery freshness check | 08:00 UTC daily (alerts on miss) |
| Evidence rebuilds this site | 07:00 UTC daily |
What's exact, what's approximate
Exact (provider-canonical):
- All Anthropic token volumes — by model, workspace, service tier, day.
- All Anthropic USD cost — by model, workspace, service tier, cost type, day.
- All OpenAI token volumes — by endpoint, model, project, batch flag, day.
- OpenAI per-provider total cost — by day.
Approximate:
- OpenAI per-model cost. OpenAI's Costs API groups by
line_item, not by model. Per-model attribution comes from parsing strings like"gpt-4o input tokens"with a regex. Strings that don't match the pattern (fine-tuning, niche line items) keep model = NULL. Per-provider totals reconcile to OpenAI's bill; per-model rows do not. - Cache token semantics across providers. Anthropic exposes cache_read and cache_creation explicitly. OpenAI's
cached_input_tokensis reported in the cache_read column; cache_write is NULL. Don't directly compare cache columns across providers.
Known caveats
- Late-arriving data. Provider APIs occasionally publish corrections to past days. The MERGE-based ingestion picks these up on the next scheduled run, so historical days may shift slightly between report builds. If a number you quoted to a client changes, it's almost always this.
- Workspace / project NULLs. Default workspaces (Anthropic) and unprojected calls (OpenAI) appear with NULL in
workspace_or_project. They are real rows, not missing data. - Service tiers. Anthropic distinguishes
standard,batch,priority. Pricing differs. We split by tier in raw and roll up in analytics — be careful when comparing pre/post-batch days. - Schema drift. Both Admin APIs are relatively new (2024–2025). The pipeline raises an explicit schema error if response shapes change. After any such failure, verify against the current API docs before treating downstream numbers as authoritative.
What's NOT in here
- ChatGPT consumer subscriptions (chat product, not API).
- Claude.ai consumer subscriptions (chat product, not API).
- Token usage from local / open-weight models.
- Usage from any API not owned by the Cornelson Advisory org.
Definitions
- MTD spend — sum of
cost_usdacross both providers from the first of the current calendar month (UTC) through the most recent ingested day. - Model family — derived from the model name in the analytics view. Anthropic models starting with
claude-map toclaude; OpenAI followsgpt-4,gpt-3,o1,o3,embedding,other. - Offload signal — declining cost on premium models (
claude-opus-4,gpt-4o,o1,o3) paired with rising cost on cheaper alternatives (claude-haiku-4,gpt-4o-mini).
How to verify any number on this site
Every chart and table on this site reads from a single SQL query. The queries live in sources/bigquery/ of the report repo. Run any query directly against BigQuery to reproduce the number:
bq query --location=US --use_legacy_sql=false \
"SELECT * FROM \`cornelson-advisory-analytics.analytics.llm_spend_daily\`
WHERE usage_date = '2026-04-23' ORDER BY cost_usd DESC LIMIT 20"
