# OpenRouter now routes by speed and reliability: what to re-check

URL: https://infro.io/blog/openrouter-now-routes-by-speed-and-reliability-what-to-re-check
Author: INFRO Editorial (https://infro.io/blog/editorial)
Publisher: INFRO
Published: 2026-10-30
Last modified: 2026-10-30
Last reviewed: 2026-10-30 (next review due 2026-11-29)
Topic: Routing and reliability
Format: Brief

> Requests with no explicit sort and no provider order now go through a router that scores effective price, latency, throughput and errors, so the upstream provider, latency and cost can shift without a code change. Re-check by logging which provider served, pinning where you need determinism, and replaying a fixed prompt set against each setting.[^or-blog]

Key takeaways:
- Any request with no provider.sort and no provider.order now uses the new router; provider.order and an explicit sort bypass it.
- OpenRouter's own week-long test, on a sample of open-source models, reported lower latency and fewer 429s at a higher cost per request, so measure cost on your own traffic.
- Log openrouter_metadata on a sample of requests to see which provider served and whether a fallback fired.
- Set require_parameters, zdr and only/ignore explicitly if your traffic depends on tool calls, structured output or data rules.
- If OpenRouter sits behind your own gateway, check that the two layers do not both retry the same failure.

## What changed on Oct 28

Until now the default router sent most traffic to the provider with the lowest input-token price, and a failed request went to the next cheapest.[1] The new default scores each provider endpoint on a "Routing Cost": effective price, time spent waiting (throughput and time to first token), and the expected cost of retries when a provider errors, rate limits or returns unusable output.[1] If 1 in 5 tries fails, OpenRouter counts 1.25 tries per good answer.[1]

Effective price is computed from recent measured traffic, including the provider's real cache hit rate and the model's usual input/output mix, so it can differ a lot from list price.[1] Traffic is shared among providers inside a competitive edge, every provider keeps a trickle, a failing provider gets less, and a cap spills load once a provider starts returning 429s.[1]

## What OpenRouter reports, and what it does not tell you

In a switchback experiment over one week, 24 million requests and a sample of open-source models, OpenRouter reported these results for new versus legacy routing:[1]

| Measure | Legacy | New |
| --- | --- | --- |
| TTFT p50 | 1,007 ms | 837 ms |
| Whole request p95 | 41.5 s | 34.9 s |
| Requests hitting a 429 | 7.1% | 3.8% |
| Cost per M tokens | $0.301 | $0.324 |

Table: OpenRouter's reported results, open-source model sample, before providers adapted.

Treat these as direction, not a forecast. Your model, prompt size, cache pattern and streaming mix decide where you land. The cost line is the one to watch: OpenRouter says the new router can pick a faster or more reliable provider over the cheapest one.[1]

## Which settings bypass the new router

The rule is per request, so audit what your clients actually send.

| Request sets | Behavior |
| --- | --- |
| Nothing | New router[1] |
| `provider.sort` (price, throughput, latency) | That sort replaces the new algorithm[1] |
| `provider.order` | Bypasses the new router; providers tried in the order given[1] |
| `provider.only` / `provider.ignore` | Filters candidates; new router picks among the rest[1] |
| `:floor` on the model slug, or account default sort set to price | Price-only routing[1] |

An ongoing conversation is pinned to its first provider so the prompt cache stays warm, and falls back automatically if that provider becomes unavailable.[1] The post does not say how a conversation is identified, so check with your own client whether your multi-turn traffic really sticks.

## Pin it, and see what served

A deterministic request names the order, turns off fallbacks if you want a hard failure, and asks for routing metadata:

```python
import requests

r = requests.post(
    "https://openrouter.ai/api/v1/chat/completions",
    headers={
        "Authorization": "Bearer " + KEY,
        "X-OpenRouter-Metadata": "enabled",
    },
    json={
        "model": "vendor/model",
        "messages": [{"role": "user", "content": "ping"}],
        "provider": {
            "order": ["provider-a", "provider-b"],
            "allow_fallbacks": True,
            "require_parameters": True,
        },
    },
    timeout=60,
)
meta = r.json().get("openrouter_metadata", {})
print(meta.get("attempt"), meta.get("attempts"), meta.get("endpoints"))
```

The header surfaces `openrouter_metadata` with the selected endpoint, candidates considered, and `attempt` (above 1 means earlier attempts failed and fell back).[2] For streams it arrives on the final chunk; cache hits never carry it.[2] The fields `order`, `allow_fallbacks`, `require_parameters`, `zdr`, `only` and `ignore` are documented provider-object fields.[3] Provider slugs above are placeholders.

## What to re-check

- [ ] **Serving provider.** Sample `openrouter_metadata` and count requests per provider before and after Oct 28.
- [ ] **Cost per request.** Compare your own spend per request against the week before; effective price follows cache hits and output mix, not list input price.[1]
- [ ] **Tool calls and structured output.** The router's quality check today is mainly whether tool calls come back well formed.[1] `require_parameters` is false by default, so set it where a provider ignoring a parameter would break you.[3]
- [ ] **Data rules.** Confirm `zdr`, `data_collection` and `only` are set on requests that need them rather than assumed.[3]
- [ ] **Timeouts.** A faster median does not change your tail; re-measure p95 with streaming on.
- [ ] **Double retries.** OpenRouter retries a failed try with the next ranked provider.[1] If your own gateway also retries, a single outage can multiply attempts; cap one layer.

## Test it against your own rules

Replay a fixed prompt set in three arms: default, `sort: "price"`, and your `order`. Run each long enough that the trickle traffic to weaker providers shows up, compare latency, cost per request and tool-call validity, and keep the arm that meets your SLO. Repeat after a provider incident, since the router reacts in real time.[1]

If part of your traffic goes through INFRO routes, those routes use priority or weighted targets over your own connections, retry before the response starts, and never restart a stream that has begun.[4] INFRO's request log records latency and estimated provider cost per request, which gives you the before/after series on your side; the upstream provider behind OpenRouter still comes from OpenRouter's metadata.

## Questions

### Do I have to change code for the new routing?

No. OpenRouter says requests with no explicit provider sort and no provider order use the new router automatically, with the same key, body and model ids.[1] That is also why the change is easy to miss.

### Does provider.only keep my old behavior?

No. provider.only and provider.ignore filter the candidate set, but the new algorithm still picks among the providers that remain when more than one is left.[1] Use provider.order or an explicit sort if you need the old selection.

## Sources

1. How we rebuilt provider routing for better, faster inference — OpenRouter. https://openrouter.ai/blog/announcements/how-we-rebuilt-provider-routing/ (accessed 2026-10-30)
2. Router Metadata — OpenRouter. https://openrouter.ai/docs/guides/features/router-metadata (accessed 2026-10-30)
3. Provider Routing — OpenRouter. https://openrouter.ai/docs/guides/routing/provider-selection (accessed 2026-10-30)
4. Smart routing — INFRO. https://infro.io/docs/features/routing (accessed 2026-10-30)
