Your free model will disappear: tracking OpenRouter's rotating free tier
If you build on OpenRouter's free models, you already know the deal: a model is free today, and one morning it just isn't. The free lineup rotates — models get listed, delisted, or moved to paid — and nothing announces it. Your app doesn't get a deprecation email. It gets a failed API call.
I ran into this the usual way: a hardcoded free model ID in a side project stopped working, and I lost an embarrassing amount of time suspecting my own code before checking whether the model was still free at all. (It wasn't.)
A concrete example
While I was building the tracker described below, it caught this on 2026-10-31:
2026-10-31 13:31 UTC delisted_free poolside/laguna-s-2.1:free 2026-10-31 13:31 UTC delisted_free poolside/laguna-xs-2.1:free Two models, gone from the free tier between one check and the next. If either of those was your fallback model, your fallback silently stopped being free.
What I built: FreeModel Radar
FreeModel Radar is a small, boring tracker:
- A poller queries OpenRouter's public
/modelsendpoint every 30 minutes - A model counts as free only when its API pricing is fully $0 — prompt and completion pricing present and zero, and no non-zero charge on any other pricing component
- Each run diffs the free set against the previous snapshot and records listing/delisting events
- An empty or sharply shrunken upstream response is refused rather than recorded, so an upstream glitch never wipes the baseline
The outputs are public:
- Status page — current free list (17 models as of this writing) and recent changes
-
data.json— the machine-readable snapshot behind the page, mirrored in the GitHub repo - Free Telegram channel — @freemodelradar posts a daily digest of listing/delisting changes
Using the data instead of hardcoding and praying
The snapshot format is deliberately plain:
{ "ts": "2026-11-02T14:45:21Z", "free_count": 17, "free_ids": ["cohere/north-mini-code:free", "google/gemma-4-31b-it:free", "..."], "events": [ {"ts": "2026-10-31T13:31:52Z", "type": "delisted_free", "model": "poolside/laguna-s-2.1:free"} ] } That makes a basic sanity check a few lines of code — verify your pinned model is still in the free set before you route production traffic to it:
import json, urllib.request snap = json.load(urllib.request.urlopen( "https://raw.githubusercontent.com/original0211/freemodel-radar/main/data.json")) PINNED = "poolside/laguna-s-2.1:free" if PINNED not in snap["free_ids"]: print(f"{PINNED} is no longer free — fail over or alert") That's not a complete resilience strategy — you still want fallback chains and real error handling — but "check the list before you depend on it" removes the dumbest failure mode.
What the radar deliberately does not do
It tracks listing and free/paid status only. It does not run, benchmark, or test individual models, and it makes no claim about any model's quality, speed, or reliability. Every model on the status page is labelled "Not tested". Whether a free model is good is a separate question, and I'd rather the tool be honest about not answering it.
Free vs. Pro
The status page, data.json, and the daily Telegram digest are free. A Pro tier ($19/year) adds instant Telegram alerts the moment a change is detected (within one 30-minute check cycle) and access to the full change-history archive since launch.
If you build on free tiers anywhere — not just OpenRouter — I'm curious how you handle the churn: pinned lists with checks like the above, automatic fallbacks, or just paying for stability?

