# OpenRouter Scraper — LLM Pricing Comparison & Uptime (`kaankaan2635/openrouter-models-scraper`) Actor

LLM pricing comparison across every model on OpenRouter, in dollars per million tokens, with per-provider quantization, status and uptime.

- **URL**: https://apify.com/kaankaan2635/openrouter-models-scraper.md
- **Developed by:** [Kaan Salgır](https://apify.com/kaankaan2635) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 model scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## OpenRouter Scraper — LLM Pricing Comparison & Uptime

An **LLM pricing comparison** across every model on [OpenRouter](https://openrouter.ai), with prices converted to **dollars per million tokens** — the unit the market actually quotes — plus, for each serving provider, its price, quantization, status and measured uptime.

No account, no API key. It reads OpenRouter's documented public API.

### LLM pricing comparison table, in usable units

OpenRouter quotes prices per token, as strings:

```json
"pricing": { "prompt": "0.0000007", "completion": "0.0000014" }
```

Nobody compares models in those units. This scraper returns `inputPerMTok: 0.7` and `outputPerMTok: 1.4`, plus `blendedPerMTok` — a 3:1 input-to-output blend, the usual chat workload mix — so you can rank the whole catalogue by what it will really cost you and drop it straight into a pricing table or a spreadsheet.

**The `-1` trap.** OpenRouter uses `-1` to mean "the price depends on which model this request gets routed to" for `openrouter/auto` and its siblings. Multiply that naively and you publish a price of **minus one million dollars per million tokens**, which sorts straight to the top of any cheapest-first list. Those models come back with `variablePricing: true` and null prices instead.

### Compare LLM providers: price, quantization and uptime

Turn on **Include provider endpoints** and every model also yields one row per provider actually serving it:

`providerName` · `quantization` · `contextLength` · `maxCompletionTokens` · `inputPerMTok` · `outputPerMTok` · `uptimeLast5m` · `uptimeLast30m` · `uptimeLast1d` · `status` · `supportsToolChoice` · `supportsImplicitCaching`

The same model often costs different amounts, is quantized differently, and is up a different share of the time depending on who serves it. That is the data behind a routing decision, and no model list gives it to you.

**On latency and throughput:** those two fields are part of OpenRouter's response shape and are passed straight through, but OpenRouter currently returns them empty for every provider we have measured — 0 of 47 endpoints across a sample. They are in the output for the day that changes; do not plan around them today. `uptimeLast1d` is populated for about 9 in 10 endpoints, `quantization` and `status` for all of them.

### LLM model list API: what you get per model

`modelId` · `name` · `provider` · `description` · `createdAt` · `contextLength` · `maxCompletionTokens` · `inputPerMTok` · `outputPerMTok` · `blendedPerMTok` · `cacheReadPerMTok` · `cacheWritePerMTok` · `imageInputPerMTok` · `audioInputPerMTok` · `isFree` · `variablePricing` · `modality` · `inputModalities` · `outputModalities` · `tokenizer` · `supportsTools` · `supportsReasoning` · `reasoningMandatory` · `supportedParameters` · `knowledgeCutoff` · `huggingFaceId`

### How to use it

Run it with no input at all for the full catalogue. Filters combine with AND:

```json
{
  "excludeFree": true,
  "requireTools": true,
  "minContextLength": 200000,
  "maxInputPerMTok": 3,
  "includeProviderEndpoints": true
}
```

Filter by `providers` (`anthropic`, `openai`, `google`, `meta-llama`), by required `inputModalities` (`image`, `audio`), by `search` text, or by reasoning support.

Provider endpoints cost one extra request per model, so pair that option with filters rather than running it across all several hundred models.

### FAQ

**Do I need an OpenRouter API key?**
No. This reads the public `/api/v1/models` endpoint, which needs no authentication.

**How often does the catalogue change?**
Models and prices move weekly. Schedule this on Apify and you get a dated price history, which is the thing you cannot reconstruct later.

**Why is a model showing no price?**
Either it is genuinely free (`isFree: true`, both prices zero) or it is a router model whose price depends on where the request lands (`variablePricing: true`, prices null). The two are kept distinct on purpose.

**What is `blendedPerMTok`?**
Input and output weighted 3:1, the usual ratio for chat workloads. It gives you one number to sort the catalogue by. If your workload is output-heavy, sort on `outputPerMTok` instead.

**Can I get per-provider prices for one model?**
Yes — set a `search` filter to the model id and turn on **Include provider endpoints**.

**Does this scrape the OpenRouter website?**
No. It uses the documented public API only, so it does not break when the site is redesigned and involves no personal data at any point.

### Pricing

Pay per event: one charge per model and one per provider endpoint. Nothing is charged for compute time or failed requests.

### Development

```bash
npm install
npm test          # offline regression tests against a saved API response
npm start         # local run; put an INPUT.json in storage/key_value_stores/default/
```

# Actor input Schema

## `search` (type: `string`):

Free-text match against model id, name and description. Leave empty for everything.

## `providers` (type: `array`):

Match the vendor prefix of the model id, for example <code>anthropic</code>, <code>openai</code>, <code>google</code>, <code>meta-llama</code>.

## `inputModalities` (type: `array`):

Keep only models accepting all of these, for example <code>image</code> or <code>audio</code>.

## `minContextLength` (type: `integer`):

Drop models with a smaller context window.

## `maxInputPerMTok` (type: `integer`):

Dollars per million input tokens. Leave empty for no ceiling.

## `onlyFree` (type: `boolean`):

Keep only models priced at zero for both input and output.

## `excludeFree` (type: `boolean`):

Drop zero-priced models, which are usually rate-limited.

## `requireTools` (type: `boolean`):

Keep only models that accept a tools parameter.

## `requireReasoning` (type: `boolean`):

Keep only models exposing reasoning controls.

## `includeProviderEndpoints` (type: `boolean`):

For every matching model, also fetch each serving provider with its price, quantization, measured latency, throughput and uptime. This is one extra request per model, so pair it with filters.

## `maxModels` (type: `integer`):

Hard cap on matching models returned.

## `maxConcurrency` (type: `integer`):

Parallel requests when fetching provider endpoints.

## `proxyConfiguration` (type: `object`):

Optional. The OpenRouter API is public and usually needs no proxy.

## Actor input object example

```json
{
  "search": "",
  "providers": [],
  "inputModalities": [],
  "minContextLength": 0,
  "onlyFree": false,
  "excludeFree": false,
  "requireTools": false,
  "requireReasoning": false,
  "includeProviderEndpoints": false,
  "maxModels": 1000,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `models` (type: `string`):

One row per model, plus one row per provider endpoint when those are requested.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("kaankaan2635/openrouter-models-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("kaankaan2635/openrouter-models-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call kaankaan2635/openrouter-models-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kaankaan2635/openrouter-models-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/oLPktLb1xchPP1oey/builds/9KlCoQQispoSOVObj/openapi.json
