router-arena
Live OpenRouter provider intelligence — uptime, price volatility, and quantization map per (model, provider).
router-arena watches OpenRouter's public API every 5 minutes, snapshots the per-provider uptime + price + quantization metadata for ~25 high-traffic open-weights models, and surfaces:
- a model arena (every provider serving a given model side-by-side),
- a provider leaderboard (avg uptime, avg pricing, catalog size),
- a price-change feed (hikes / drops above 1%),
- an outage feed (uptime drops below 90% over the last 30 minutes),
- 24h uptime sparklines per (model, provider) pair.
All read-only. No authentication required to use the dashboard, no auth on any endpoint, no user accounts.
Data sources
router-arena calls only two public OpenRouter endpoints:
| URL | Frequency |
|---|---|
| https://openrouter.ai/api/v1/models | hourly (catalog refresh) |
| https://openrouter.ai/api/v1/models/:author/:slug/endpoints | every 5 minutes per hot model |
Both endpoints are unauthenticated for read access. router-arena does not require an OpenRouter API key.
This project is not affiliated with or endorsed by OpenRouter. It is a third-party dashboard built on top of OpenRouter's published public read API.
No mocked data, no synthetic numbers, no seed providers. If the cron has not run yet, the UI shows empty-state copy.
Stack
- Node.js 20+, ES modules
- Express 4, helmet, compression, cors
- better-sqlite3 (WAL mode) for storage
- node-cron for scheduling
- Vanilla JS SPA, dark theme, Chart.js (CDN) for sparklines
Run locally
npm install
npm start
Then open <http://127.0.0.1:4732/router-arena/>.
The dashboard also responds at <http://127.0.0.1:4732/> (root) — the same routes are mounted twice so the product works both behind nginx with the /router-arena/ prefix and directly on its port.
Configuration
Every knob is optional; defaults are baked in. See .env.example.
| Variable | Default | Purpose |
|---|---|---|
| PORT | 4732 | HTTP listen port |
| OPENROUTER_BASE | https://openrouter.ai/api/v1 | API base (override for testing) |
| HOT_MODELS_REFRESH_CRON | /5 | Snapshot cadence for hot models |
| CATALOG_REFRESH_CRON | 0 * | Catalog refresh cadence |
| HOT_MODELS_LIST | (25 models, see config.js) | Comma-separated override |
| PRICE_CHANGE_THRESHOLD_PCT | 1 | Sub-1% price diffs ignored as noise |
| UPTIME_OUTAGE_THRESHOLD | 90 | Open an outage event when uptime_30m drops below this |
| UPTIME_CLEAR_THRESHOLD | 95 | Clear an open outage when uptime_30m recovers above this |
| FETCH_TIMEOUT_MS | 8000 | Per-fetch timeout |
| MAX_FETCH_RETRIES | 3 | Exponential-backoff retries |
| SNAPSHOT_RETENTION_DAYS | 30 | History trim window |
Endpoints
All HTTP, all GET unless noted, all unauthenticated.
| Method + Path | Returns |
|---|---|
| GET /router-arena/health | Service health + last-refresh timestamps |
| GET /router-arena/api/stats | Top-line counters (models, providers, endpoints, …) |
| GET /router-arena/api/models | Models list with cheapest-now / best-uptime aggregates |
| GET /router-arena/api/models/:author/:slug | Model detail + every current endpoint + quantization map |
| GET /router-arena/api/models/:author/:slug/history?provider=&tag=&hours=24 | Time-series for one (model, provider, tag) pair |
| GET /router-arena/api/providers | Provider leaderboard |
| GET /router-arena/api/providers/:name | Provider profile + hosted models |
| GET /router-arena/api/price-changes?hours=&direction=&provider= | Price-change feed |
| GET /router-arena/api/outages?open=1 | Outage events (open first) |
| GET /router-arena/api/refresh-log?limit=20 | Last N cron runs |
| POST /router-arena/api/refresh/catalog | Trigger catalog refresh |
| POST /router-arena/api/refresh/hot | Trigger hot-models refresh |
Database schema
SQLite, WAL mode. See db.js for the canonical schema. Six tables:
models— every model OpenRouter exposes (with anis_hotflag).endpoints_current— latest snapshot per (model, provider, tag), upserted.endpoint_snapshots— append-only time-series for charts.price_changes— one row per detected price hike / drop.outage_events— one row per detected uptime drop, withcleared_atset when recovered.refresh_log— one row per cron run.
Acknowledgments
OpenRouter publishes the per-provider uptime and pricing metadata that router-arena visualizes. The aggregation, historization, change detection, and dashboard are router-arena's own work. If OpenRouter ships an official equivalent, this product becomes redundant — that is the right outcome.