OpenRouter Analytics
Query your OpenRouter usage data programmatically. Answer questions like "What was my spend this month?", "Which models cost the most?", and "How can I reduce my bill?" using the Analytics API.
Prerequisites
- An OpenRouter management key (provisioning key). Regular API keys will get a 403.
- Get a management key at https://openrouter.ai/settings/management-keys (separate from the regular API keys page)
- Pass it via
--api-key <key> or set the OPENROUTERAPIKEY environment variable
First-Time Setup
cd <skill-path>/scripts && npm install
Decision Tree
| User wants to… |
Do this |
| Know what data is available |
Run discover-schema.ts to see metrics, dimensions, and filters |
| See spend / usage / volume |
Run query-analytics.ts with appropriate metrics |
| Break down by model, provider, API key |
Add --dimensions to the query |
| See trends over time |
Add --granularity day (or hour, week, month) |
| Reduce costs |
Run suggest-queries.ts, find the cost optimization template, execute it |
| Inspect individual generations |
Add --dimensions generation_id, then use the openrouter-generations skill for details |
| Break down by classifier labels |
Use classifier_dimensions in the request body (see openrouter-analytics-query skill) |
| Filter by classifier labels |
Use classifier_filters in the request body (see openrouter-analytics-query skill) |
| Answer a specific question |
Map the question → metrics + dimensions, then query |
Workflow
The recommended workflow for answering a user's analytics question:
- Discover — Call
discover-schema.ts to see available metrics and dimensions
- Map — Translate the user's question into metrics, dimensions, filters, and time range
- Query — Execute via
query-analytics.ts
- Interpret — Analyze the returned data and explain the results
For common questions, suggest-queries.ts provides ready-made query templates.
Discover Available Data
cd <skill-path>/scripts && npx tsx discover-schema.ts
Returns the full schema: metrics, dimensions, filter operators, and granularities.
Filter to a specific section:
npx tsx discover-schema.ts --section metrics
npx tsx discover-schema.ts --section dimensions
npx tsx discover-schema.ts --section operators
npx tsx discover-schema.ts --section granularities
See the openrouter-analytics-schema skill for detailed guidance on interpreting the schema response and mapping user questions to the right metrics and dimensions.
Query Analytics Data
cd <skill-path>/scripts && npx tsx query-analytics.ts --metrics request_count,total_usage
See the openrouter-analytics-query skill for the full parameter reference and query construction guide.
Quick Examples
Spend over the last 7 days, broken down by day:
npx tsx query-analytics.ts --metrics total_usage --granularity day
Top 10 models by cost:
npx tsx query-analytics.ts --metrics total_usage,request_count --dimensions model --order-by total_usage --limit 10
Usage by API key:
npx tsx query-analytics.ts --metrics request_count,tokens_total --dimensions api_key_id --order-by request_count --limit 10
Latency by provider (limited to 31-day range):
npx tsx query-analytics.ts --metrics avg_latency,p90_latency --dimensions provider --order-by p90_latency
Usage cost breakdown (credits, BYOK, upstream, cache, data logging, web search):
npx tsx query-analytics.ts --metrics credits_usage,byok_usage,byok_fees,usage_upstream,usage_cache,usage_data,usage_web --granularity day
Common Query Templates
cd <skill-path>/scripts && npx tsx suggest-queries.ts
Returns a list of pre-built query templates for common questions, each with:
- The natural-language question it answers
- The query parameters (metrics, dimensions, filters, time range)
- The CLI flags to pass to
query-analytics.ts
- Interpretation guidance (where applicable)
Interpreting Results
The query endpoint returns an array of data rows. Each row is a flat object with keys matching the requested metrics and dimensions.
When interpreting results for the user:
- Spend metrics (
totalusage, creditsusage, openrouterusage, byokusage, byokfees, usageupstream, usagecache, usageweb, usageupstreamweb, usagefile, usageupstreamfile, usagewebfetch, usageupstreamwebfetch) are in USD. totalusage includes BYOK inference cost. usagedata is typically negative (a data logging discount)
- Token counts (
tokenstotal, tokensprompt, tokens_completion) are in native model tokens
- Latency (
avglatency, p50latency, etc.) is in milliseconds
- Rates (
cachehitrate) are 0–1 ratios
- Throughput (
avg_throughput) is tokens per second
- When
granularity is set, rows include a date<granularity> field for the time bucket (e.g., dateday, datehour, datemonth)
- Label resolution: dimensions
apikeyid, app, user, and workspace have their raw IDs replaced with human-readable names (key name, app title, user name, workspace name) directly in the data rows; generationid and sessionid return raw values
- Truncation: when consuming output programmatically, check
metadata.truncated. If true, the result was capped at --limit and is a partial dataset — raise --limit or paginate before reporting totals or rankings
Cost Optimization Guidance
When the user asks "How can I spend less?" or similar:
- Query top models by spend:
--metrics totalusage,tokenstotal,cachehitrate,requestcount --dimensions model --order-by totalusage --limit 10
- Query cost breakdown:
--metrics creditsusage,byokusage,byokfees,usageupstream,usagecache,usagedata,usageweb,usagefile --granularity day to see where spend goes
- Look for:
- Models with high spend but low cachehitrate — prompt caching can help - Expensive models that could be replaced by cheaper alternatives for specific tasks - High token counts with low request counts — may indicate oversized prompts - Models where reasoningtokens are a large fraction of total — consider disabling extended thinking if not needed - High usageweb or usagefile relative to usageupstream — web search and file processing add-on costs may be significant
Drilling Down to Individual Generations
To inspect specific generations or sessions from your analytics results, add generationid or sessionid as a dimension. Both are generations-only dimensions (31-day limit). generationid returns the unique ID for each generation in the result set. sessionid groups and filters sessionless requests as the literal none: the ClickHouse column defaults to an empty string, and the query builder coalesces it to none. Use neq 'none' to exclude sessionless requests; filtering on '' matches nothing.
npx tsx query-analytics.ts --metrics total_usage,tokens_total --dimensions generation_id --order-by total_usage --limit 10
Once you have a generation ID (e.g., gen-aBcDeFgHiJkLmNoPqRsT), use the openrouter-generations skill to get detailed information:
get-generation — Fetch full request metadata: cost breakdown, token counts, latency, provider routing chain, finish reason, and more
get-generation-content — Fetch the stored prompt and completion text (unless Zero Data Retention was enabled)
cd <openrouter-generations-skill-path>/scripts
npx tsx get-generation.ts gen-aBcDeFgHiJkLmNoPqRsT
npx tsx get-generation-content.ts gen-aBcDeFgHiJkLmNoPqRsT
This workflow is useful for identifying your most expensive or slowest requests via analytics, then inspecting the actual prompt/completion to understand why.
API Reference
Both endpoints require a management key via Authorization: Bearer sk-or-v1-....
| Endpoint |
Method |
Description |
/api/v1/analytics/meta |
GET |
Returns available metrics, dimensions, operators, granularities |
/api/v1/analytics/query |
POST |
Executes an analytics query and returns structured data |
Full documentation: https://openrouter.ai/docs/api/api-reference/analytics