Metrics / routstr / model_activity
model_activity
Per-model Routstr activity over included providers - reported revenue (msats), successful requests and tokens per model identifier, at grain=day one row per (bucket, model), at grain=total one row per model summed over the from/to window (omit both for all time). The data behind the Models tab's 'Daily revenue by model' chart, served for EVERY model rather than the chart's top-6 fold.
unit
msats+requests+tokens
grain
day | total (UTC)
series
sparse, full history
key
routstr.model_activity@day
Parameters
| param | accepted values |
|---|---|
| grain | day | total - default day (omit to get the default) |
| from | optional inclusive ISO UTC calendar day (YYYY-MM-DD); omit for the series start |
| to | optional inclusive ISO UTC calendar day (YYYY-MM-DD); omit for today UTC (that day still in progress) |
| model | optional model identifier, exact match on the provider-reported string as listed by routstr.model_leaderboard (max 60 chars; '(other)' is a valid value) |
| format | csv | markdown |
Columns per grain: day: utc_day, grain, model, msats, requests, tokens, providers - total: model, msats, requests, tokens, daily_buckets, weekly_buckets, first_day, last_day.
Query it
MCP tool call against https://dev.nostrolo.gy/mcp (connect your agent):
{
"name": "nostrology_query_metric",
"arguments": {
"metric": "model_activity",
"domain": "routstr",
"grain": "day"
}
} Windowed (inclusive UTC days; both optional):
{
"name": "nostrology_query_metric",
"arguments": {
"metric": "model_activity",
"domain": "routstr",
"grain": "day",
"from": "2026-07-01",
"to": "2026-07-31"
}
} Response: a plain-text envelope (window, freshness, column contract, this page's
caveats) followed by the data table (csv, or format: "markdown") at the grain you request.
Response columns
| name | type | description |
|---|---|---|
| utc_day | date | bucket START day (UTC); a weekly bucket covers the 7 days from it |
| grain | text | d = daily bucket; w = weekly bucket (pre-daily era only) |
| model | text | provider-reported model identifier, verbatim (clipped at 60 chars); '(other)' = the providers' own residual plus any named tail folded past 100 rows |
| msats | integer | revenue reported, integer millisats - per bucket at grain=day, summed over the window at grain=total |
| requests | integer | successful requests reported - per bucket at grain=day, summed over the window at grain=total |
| tokens | integer | tokens billed - per bucket at grain=day, summed over the window at grain=total |
| providers | integer | distinct included providers reporting the model in the bucket |
What is counted
Included providers only; every model identifier that any included provider reported, plus '(other)'. Network aggregates cover INCLUDED providers only: test/staging-marked nodes and private-endpoint-only nodes are excluded (still listed, with the reason, by routstr.provider_leaderboard and the routstr.provider_profile record), and kind-38421 (routstr-provider-announcements) squatters are never providers.
Caveats
- Every usage number is SELF-REPORTED by each provider's own node in kind-38422 (routstr-analytics-snapshots) events and is unverifiable by construction (RIP-01 payments travel as Cashu tokens in HTTP headers, invisible on Nostr): a node can overstate, understate or stay silent, so read these as what the network says about itself.
- Model identifiers are the providers' own strings, verbatim (clipped at 60 chars): the same model appears both as 'openai/gpt-...' and 'gpt-...' and no normalization is applied; '(other)' is the providers' own residual for models they truncated off the wire and is part of the data.
- Daily figures come from a ledger reconstructed by merging the UTC-grid buckets of EVERY archived snapshot's trailing windows (full-coverage-only, newest-wins); observed history is a FLOOR - a day a node later omits is kept, a gap longer than the windows' reach stays a gap - and today is never a ledger day.
- Grain 'w' rows are weekly buckets (Thursday-start, keyed by their start day) kept only for a provider's PRE-daily era, so the two grains never overlap and summing every row gives the all-time figure. A from/to window includes exactly the DAILY buckets STARTING inside it and no weekly bucket at all - the page's own windowed rule - so weekly_buckets is 0 whenever a window is given.
- Revenue is integer MILLI-satoshis (divide by 1000 for sats; sum msats first, convert once).
- Responses are capped at 2,000 rows with an explicit truncated: line, and unfiltered this series exceeds it (every model on every active day): pass model= or a from/to window, or use grain=total. Series is sparse.
Freshness in every response is data-derived: the newest routstr refresh's generation instant (nightly 02:45 UTC; the newest ledger day is the previous UTC day).