SCRAPPY_
system live
self-hosted · zero paid apis · honest by design

Scrappy

It fetches. It diffs. It never forgets what it saw.

One codebase, two instruments. A mirror that keeps the full history of OpenRouter's public catalog — pricing changes, deprecations, rankings — because the origin stores none of it. And an engine that turns any URL into clean markdown with an honest receipt: which path fetched it, how old the copy is, what it cost, and — when a site says no — what it said no with.

422 models mirrored 503 endpoint records in the fleet sweep
2,161 events stored real transitions, both sides recorded
267 requests logged zero failures · one ledger, never edited
$0 paid API spend self-hosted, no keys, no metered calls
I

The mirror — a memory the origin doesn't have

spec

Once an hour Scrappy fetches OpenRouter's public surfaces, diffs them against what it already holds, and writes only the differences to an append-only event log. Nothing is overwritten in place: the entity table holds the current truth, the event table holds every transition with its before and after. Both are guarded by SQLite triggers that abort any UPDATE or DELETE.

combined daily budget — rolling 24h267 of 2,000
05001,0001,5002,000
Every request the mirror has ever made — read straight from the ledger file, because the budget is counted from disk, not from a process counter. A crash-and-restart loop cannot bill the same requests twice. Today's dial sits at 13.4% of the ceiling.
In plain english The ceiling is a politeness dial, not a legal permission. The site publishes data; we take it in tiny sips, paced so the origin never notices us — and the number on the dial is the truth of what we actually consumed, survivable across restarts.

Class budgets

S1model list · hourly1 / hour · 24 / day
S2per-provider endpoints60 / hour · 1,500 / day
S3robots.txt gate1 / day
S4frontend catalog JSON12 / hour · 200 / day
S5changelog.md exception1 / day
Σcombined120 / hour · 2,000 / day
In plain english S1 is the expensive, polite view of the world — fetched once an hour on purpose. S2 peers at every model's per-provider pricing, so it gets the big flag: 60 an hour, and never more than 1,500 a day. S3 reads the site's own kill-switch. S4 is the sanctioned frontend JSON namespace — the catalog holds hidden and private records. S5 is the one documented exception in the whole policy: the changelog has no JSON route, so once a day Scrappy takes the docs platform's markdown variant, 27 KB, instead of 498 KB of HTML.
pace

The engine is a silent guest — one request, one IP, one door

RuleThe specIn plain english
Serialized One request at a time, from one egress IP, paced ~1.5 s apart with ±10% jitter. No parallel bursts, no rotating addresses. To the origin it reads like a calm visitor, not a fleet.
300 s floor An identical URL is never re-fetched inside the origin's own max-age — enforced even though the hourly cadence already guarantees it. If the site says "don't ask again for 5 minutes", the code believes it, twice. The floor is the origin's own instruction, treated as a contract.
Backoff 60 s × 2ⁿ, capped at 4 hours. A server Retry-After header overrides our math. Failures double the waiting window, so the hammer fades. If the origin says "come back at noon", we come back at noon, exactly.
Hourly park The 4th consecutive failure parks the class until the hour flips. ≥50% failures in the last hour pauses it too. Two trips to the same locked door is patience; four is bad manners — and we stop on purpose, until a new hour resets the meter.
Origin stress If recent latency runs ≥10× the class baseline, the class pauses for an hour. We see the origin struggling before it breaks. Never add load to a machine that is on its knees.
spec

The six gates — and nothing routes around them

Every gate persists to data/killswitch.json with a reason and a full history. A tripped switch stops the cycle, and no retry logic exists on the other side of it.

GateTriggerAction
1 · 403Forbidden on any classFull stop, 24 hours — likely an anti-bot measure or an IP block. We stop, always.
2 · CloudflareA Cloudflare mitigation header appears on any responseFull stop, 24 hours. We halt at a defensive measure; we never route around it, never vend a browser.
3 · robots turns hostilerobots.txt disallows any path we touchFull stop until a human resets reality. Until then, silence.
4 · budget breachOver 2× the combined cap in an hour or a dayThe circuit-breaker trips the kill-switch itself — the only switch that watches our own hands.
5 · origin struggling≥50% failures in an hour, or latency ≥10× its baselineThat class pauses for an hour. Do not poke the exhausted.
6 · ToS change / written requestTerms page changes; OpenRouter writes to usA human trips the switch by hand — scrappy mirror killswitch trip --reason. Nothing polls the terms page.
Gate 2 is the unwritten rule of the whole project, in one sentence: a number that exists only by pretending to be Chrome is not a pass rate worth publishing. And gate 4 is the confession that accountability to the origin isn't trust — it's a self-trip.
spec

The ledger — written before the body is even looked at

One row per request: ISO-8601 UTC timestamp, method, full URL, status, bytes, latency, cf-cache-status, rate-limit headers, the exact user-agent we sent, the cycle id, and a SHA-256 of the body. The row lands in SQLite and is mirrored to the JSONL file committed to this repo, all before any response body is read. Rows are never deleted — by anyone, including us.

# one real row — last evening's fleet sweep
{
  "ts": "2026-08-24T05:26:21.553Z",
  "cycle_id": "20260824T052538Z-bfd86a",
  "surface_class": "S2",
  "url": "https://openrouter.ai/api/v1/models/anthropic/claude-sonnet-4.6:batch/endpoints",
  "status": 200, "bytes": 1437, "latency_ms": 35.0,
  "cf_cache_status": "BYPASS",
  "ua": "Scrappy-Mirror/0.1 (hourly OpenRouter public-surface mirror; contact: lucadefantini@gmail.com)",
  "content_sha256": "0e6eb21a0ba8076a0ebd71e130ece8ea…"
}
In plain english No doctored history is possible: the receipt is written at the moment of the ask, not after a human or a script has decided what to keep. It is the evidence file — you can trust every dial on this page because every number on it is a count of rows that cannot be redacted.
spec

The store — current truth on one side, every transition on the other

Two tables, two jobs. entities mirrors the world as it stands; events append-only keeps every transition with its before/after. SQLite triggers make both unbreakable.

entities

Today's truth: 1,974 rows

models 422 · catalog 942 · endpoints 503 · providers 82 · apps 25

Current state, keyed and clean. This is what a snapshot answer is built from.

events

Every change, both sides: 2,161 rows

added 1,974 · updated 134 · price moved 24 · health thrash 17 · expired 1

Each event stores the before and the after. That is the history — and the origin has none of it.

II

The engine — URL in, clean markdown out

spec

A general URL-to-markdown engine with no API keys and no paid calls. One page in — clean markdown plus an honest paper trail out. Escalation exists, but only in one direction, and never through a challenge.

path 01

fast

One HTTP GET, then HTML or PDF flattened to markdown by a local converter. No browser anywhere.

In plain english The normal case. Cheap, quick, quiet: a static page becomes text in tens of milliseconds.
path 02

render

Drives headless Chromium and converts the DOM. Reserved for pages that cannot be read as raw HTML.

In plain english The heavy case: JavaScript-heavy SPAs and canvases. You pay browser time only when the page truly needs a browser.
path 03

auto — the default

Starts fast; escalates to render only when the fetched body looks like an empty framework shell — a root element with almost no visible text. Never escalates a challenged response.

In plain english Rendering past a bot check would be a way around the site's rules. So when a page answers with a challenge, the engine names it, records it, and moves on — no retry, no browser, no pretend.
spec

The freshness contract

RuleSpecIn plain english
Age budget Every request carries a max_age. Inside the budget: the stored copy, stamped with the true age, and no packet leaves the machine — free: true. A cache hit costs nothing because there is nothing to bill. That is a structural difference from a metered API, not a discount.
Conditional revalidation Outside the budget: ETag / If-Modified-Since. A 304 refreshes the stamp without re-downloading the body. If nothing changed, the origin says exactly that, and we keep a fresh stamp for the price of a whisper instead of a download.
Default stance max_age = 0 — a request with no opinion gets live content. Freshness is our bias, not staleness. The five-minute reuse rule and --max-age -1 for "any age, no fetch" are deliberate knobs, not the default.
Stale-on-error If the origin is unreachable, the stored copy is served rather than a blank page. When the source stalls, you still get the last known truth, with a stamp showing exactly which truth it is.
spec

Anti-bot posture

One honest user-agent with a reachable contact address, and a per-site override only where the site's own policy asks for one. No browser impersonation, no TLS fingerprint spoofing, no proxy pools, no CAPTCHA solving, no retry through a challenge. When a site blocks us, the engine names what stopped it:

cloudflarecaptchaakamaidatadomelogin_wallrate_limitedblockedserver_error
In plain english An honest name, recorded — but not a loophole to stay a guest forever: the benchmark column publishes the pass rate we actually earn, one honest attempt per target, no evasion. A number that only exists by pretending to be a browser is a number that should not be a number.
III

The field — vs Exa, vs Firecrawl, honest numbers

benchmark

One frozen corpus of 91 real URLs. One machine. One pass each. Scrappy and Crawl4AI were actually run; Firecrawl and Exa were never called — their numbers are transcribed from their own published pages and are labelled as published, not measured. That is the whole honesty contract of this section: everything we claim we did, everything they claim we left alone.

pages acquired — measured

90.1%

82 of 91 targets returned real content. Crawl4AI got 63.

scrappy
82/91
crawl4ai
63/91
firecrawl
n/a
exa
n/a

markdown fidelity F1 — measured

0.840

Token F1 of the output markdown vs the rendered DOM.

scrappy
0.840
crawl4ai
0.720
firecrawl
n/a
exa
n/a

cost per 1,000 pages

$0.0014

Scrappy is compute-only. The vendors' numbers bundle infra. Not to linear scale: the two local engines are ~0.02% of Exa's bar.

scrappy
$0.0014
crawl4ai
$0.0003
firecrawl
$0.83
exa
$8.00

anti-bot pass — one try, no evasion

53.3%

Class 3 targets: one honest attempt each, challenge reported.

scrappy
8/15
crawl4ai
8/15
firecrawl
n/a
exa
n/a
head to head

The table — measured on the left, published on the right

DimensionScrappy (measured)Firecrawl (published)Exa (published)
Pages acquired 82/91 · 90.1% not published not published
Markdown fidelity F1 0.840 not published not published
Table preservation 95.8% not published not published
Heading preservation 83.3% (Crawl4AI: 89.1%) not published not published
Code-block preservation 73.9% (Crawl4AI: 85.3%) not published not published
Anti-bot pass (one try) 8/15 · 53.3% not published (third party: 85–98% on unprotected sites, unverified) not published
Latency p50 / p95 584 ms / 5,935 ms not published not published
Cost per 1,000 pages $0.0014 compute only $0.83 (Standard yearly; cached hit still bills) — 403/404 pages are charged $8.00 ($7/1k search + $1/1k contents) — livecrawl adds +500–2,000 ms
Cache hit 0 requests, $0 — inside the age budget served, but a full credit is still billed pre-indexed hourly; a cached copy is what you get
Self-hostable yes — the whole thing, no keys no (cloud API) no (closed source, cloud only)
Why the right column says "not published": Firecrawl and Exa publish no acquisition rate, no fidelity score, no table or heading preservation figures. The values that do appear — price, cache policy, rate limits — are from their own pricing and docs pages, transcribed on 2026-08-23. The "measured" column is ours, from a frozen corpus and a published harness.
we win

Freshness is a contract, not a lag

Scrappy fetches on demand and honors a per-request age budget. Inside the budget: a cache hit costs 0 requests and $0. Firecrawl bills a full credit for a cached hit, and Exa serves from an index it refreshes hourly — a change at the origin can wait up to an hour, plus a +500–2,000 ms livecrawl surcharge when you force it.

Measured: a change at the origin is reflected in 0.00 s with max-age 0. That is the difference between a mirror and a cache.
we win

Every request has a receipt

One ledger row per request, written before the body is read: status, bytes, latency, cache status, SHA-256. Append-only, in git. Neither vendor publishes an equivalent. Firecrawl does not tell you its cache hit rate; Exa does not tell you what its index served.

If a number changes on this page, the row that caused it is in the repo. That is auditable by anyone, including enemies.
we win

We publish the ugly numbers ourselves

53.3% anti-bot pass, 73.9% code-block preservation, a 5.9 s p95. Those are our scores, on our page, with our methodology printed underneath. Firecrawl publishes none of these. Exa publishes none of these. The third-party Firecrawl figure (85–98% on unprotected sites) is unverified, and it does not say what happens on the protected ones.

A number that only exists by pretending to be a browser is a number that should not be a number. We would rather lose a column than fake a pass rate.
we win

Zero paid API calls, self-hosted, no keys

The whole run — 267 requests, 41.7 MB — cost $0 of metered API spend. Exa's search+contents stack bills about $8 per 1,000 pages before any livecrawl premium; Firecrawl's $0.00083/page still charges a credit for a 403 or 404. Ours are free, ledgered, and named.

The ceiling is a politeness dial, not a metered meter. We choose what to take and when; nobody else chooses for us.
we lose

Global index coverage

Exa serves a pre-built index of billions of pages; we have only what was fetched. Measured: 0 pages served from an index — every one of the 91 benchmark pages was fetched on demand.

This is the honest frontier. A vertical owned index — bounded but auditable, with per-URL crawl timestamps — is the next lever, not a fake universal crawl.
we lose

Hard anti-bot targets

8 of 15 class-3 targets acquired (53.3%), one honest attempt each. Amazon, Booking, Walmart, Zillow, Bloomberg answered; Indeed, The Economist, FT, G2, Leboncoin did not.

Firecrawl's managed anti-bot stack exists to beat these. Ours exists to name them. That is a design decision, and the pass rate is published, not hidden behind a "stealth mode".
we lose

Latency tail, code blocks, headings

p95 5,935 ms vs Crawl4AI's 1,876 ms (same corpus, same machine), code-block preservation 73.9% vs 85.3%, headings 83.3% vs 89.1%. Tables are a win (95.8% vs 93.8%); the tail is not.

The p95 is mostly serialization and politeness pacing on one node; the structure gap is a converter issue, not a browser issue.
we lose

Managed infrastructure

One process, one browser, serialized per host, ~1.5 s apart. A hosted fleet answers hundreds of concurrent scrapes. Our compute cost ($0.0014/1k pages) is also higher than Crawl4AI's ($0.0003/1k) — honorably cheap against Exa, not the cheapest on the block.

No OCR, no JS interaction, no pagination walking, no proxy pools. Capabilities gap, named, not underestimated.
next levers

Where the improvement lives

Ranked by honest return, not by marketing. Each one keeps the politeness and honesty rules; none of them pretends a challenge away.

LeverWhat it fixesConstraint
Vertical owned index Bounded coverage beyond on-demand fetch, with crawl manifests and per-URL timestamps. Never a claim of total coverage; the manifest is the proof.
Converter structure pass Headings 83.3% → 95%+, code blocks 73.9% → 90%+. Measurable, offline, table-tested. Highest certainty per unit of work.
Worker pool, one politeness ledger Concurrency up, per-host request rate unchanged, p95 down. The ledger is global; no host ever exceeds its own polite cadence.
Optional OCR (Tesseract) Scanned PDFs score 0 today because they have no text layer. Off by default — it changes the cost model; the receipt says so.
Declarative per-site actions Scroll, wait-for, next-page on the render path, without turning into a browser bot. Only where the site asks for it; a challenge is still reported, never defeated.
Clean-network run Our latency numbers come from one machine in Berlin; publish a cloud-region p95 too. Same harness, same corpus, both numbers side by side.
The benchmark harness itself is in bench/, the corpus is frozen in research/corpus-freeze/, and the numbers regenerate with make bench. No figure on this page was typed by hand.
IV

The honest gaps — quirks, boundaries, admissions

quirks

Every limit on this page is either physics upstream, a written boundary we gave ourselves, or a choice designed to keep the signal clean. None of them are hidden.

deliberate

Health events are threshold-gated

Noise control, on purpose. A status change, uptime_1d moving ≥1pp, uptime_30m ≥5pp: an event. Small wobbles stay in the snapshot but do not write to the log.

Otherwise the event log becomes a noise log. The dials stay honest because they are not twitching every minute.
upstream

Endpoint fleet takes ~8 hours to sweep

S2's budget is 60 models/hour and there are 422 of them. Bootstrap covers the first 60; the hourly cycles fill in the rest. The fleet reached all 503 endpoint records across cycles.

Coverage is real but fill-in is slow by design — the politeness cap and the fleet size are both true, and we accept the math rather than race it.
upstream

Year-long rankings: weekly, top-10 only

Upstream buckets ?days=365 into 52 weekly points, each carrying only that week's top 10 — 70 distinct names across the year, not the full 422.

For long windows the origin itself only exposes a leaderboard, so the mirror keeps the leaderboard faithfully and says so.
upstream

Daily rankings: a rolling fetch, not an archive

Bootstrap held 5 distinct dates. Anything older than the mirror's first hours is not in upstream's window — the API serves recent days, not history.

We keep every day we observe; earlier days are genuinely unrecoverable. The mirror doesn't invent the past.
policy

Changelog: a rolling window of 10

The markdown changelog holds ten entries (all ten captured, oldest 2026-07-03). Scroll-offs stay in our DB; anything published before the mirror started is gone unless still on the page.

One documented exception to the no-HTML rule — and even it refuses the HTML page, taking the platform's own machine-readable variant.
policy

Benchmark scores are not mirrored

benchmarkScores (Artificial Analysis) live only inside server-rendered model pages. HTML page scraping is out of scope by ruling, so those pages are never touched.

The line is drawn before the server pages, and we do not cross it — even for something that would print nicely on a dashboard.
deliberate

Catalog endpoints: a projection, not a full copy

The catalog nests an endpoint sub-document. We keep what matters — pricing, deprecation date, data policy, provider identity — and drop what moves every fetch (status, capacity_tpm). Proper detail arrives through S2.

Two sources, one job each. The catalog says what the price is; S2 says how healthy the doors are.
deliberate

Verify can't cross-check S1 in the same hour

By policy the models list costs 1 request/hour. So verify — exit 0 match, 1 mismatch, 2 undecided — cross-checks through the catalog and per-provider endpoints instead.

The check stays honest by never buying extra budget to verify itself. Exit 2 right after a cycle? Wait five minutes and re-run.
deliberate

No alerting

Price changes, expirations, new models: events land in the log, and nothing knocks on your door.

The mirror watches; the watchdog does not bark. Alerting is a still-unbuilt knob, listed here so it cannot be assumed built.
policy

Two kill-switches are human-tripped

The self-tripping gates are automatic. The ToS-change gate and the "OpenRouter wrote us" gate are deliberately hand-operated, using killswitch trip --reason.

A rule that only a human can flip stays a rule; it never becomes a habit of the algorithm.
V

The data — real rows, straight out of the mirror

excerpts

Every table below is a live excerpt from this machine's SQLite store: the first 10 rows of the entity tables, the most recent 10 events, and the newest telemetry samples. Nothing is hand-typed.

events by type

2,161

Everything that ever changed, broken into its kinds.

catalog add
942
endpoint add
503
model add
422
model update
134
provider add
82
app add
25
price moved
24
health thrash
17
changelog
10
expired
1

requests by surface class

267

The ledger, grouped. S2 is the pacer's loudest voice, by design.

S2 endpoints
220
S4 catalog
39
S1 models
6
S3 robots
1
S5 changelog
1

top throughput — p50 tokens/s

961

Median tokens per second, one hour ago, per model.

gpt-oss-120b
961
gpt-oss-20b
426
safeguard-20b
333
minimax-m2.7
268
qwen3-32b
238

requests per hour

69

The 19:00 bootstrap spike; the hourly cycle steadies at 31.

19:00
69
20:00
43
21:00
31
05:00
31
06:00
31
07:00
31
08:00
31

The model table

422 rows · 10 shown
slugnameprompt $/Mcompletion $/M
aion-labs/aion-2.0AionLabs: Aion-2.00.801.60
aion-labs/aion-3.0AionLabs: Aion-3.03.006.00
aion-labs/aion-3.0-miniAionLabs: Aion-3.0-Mini0.701.40
aion-labs/aion-rp-llama-3.1-8bAionLabs: Aion-RP 1.0 (8B)0.801.60
allenai/olmo-3-32b-thinkAllenAI: Olmo 3 32B Think0.150.50
amazon/nova-2-lite-v1Amazon: Nova 2 Lite0.302.50
amazon/nova-lite-v1Amazon: Nova Lite 1.00.060.24
amazon/nova-micro-v1Amazon: Nova Micro 1.00.040.14
amazon/nova-premier-v1Amazon: Nova Premier 1.02.5012.50
amazon/nova-pro-v1Amazon: Nova Pro 1.00.803.20

Provider table

82 rows · 10 shown
keynameslug
aion-labsAionLabsaion-labs
akashmlAkashMLakashml
alibabaAlibabaalibaba
amazon-bedrockAmazon Bedrockamazon-bedrock
ambientAmbientambient
anthropicAnthropicanthropic
arcee-aiArcee AIarcee-ai
atlas-cloudAtlasCloudatlas-cloud
azureAzureazure
baiduBaidubaidu

Endpoint table

503 rows · 10 shown
model | provider | routeprovider
google/lyria-3-clip-previewGoogle AI Studio
google/lyria-3-pro-previewGoogle AI Studio
gryphe/mythomax-l2-13bDeepInfra
gryphe/mythomax-l2-13bMancer 2
gryphe/mythomax-l2-13bNextBit
gryphe/mythomax-l2-13bParasail
ibm-granite/granite-4.0-h-microCloudflare
ibm-granite/granite-4.1-8bCoreWeave
inception/mercury-2Inception
inclusionai/ling-2.6-1tNovita

Event table — latest 10

2,161 rows · 10 shown
timestamp (UTC)evententity
2026-08-24 08:28:08app_updated4706207
2026-08-24 08:28:08endpoint_addedgoogle/lyria-3-clip-preview
2026-08-24 08:28:08endpoint_addedgoogle/lyria-3-pro-preview
2026-08-24 08:28:08endpoint_addedgryphe/mythomax-l2-13b | NextBit
2026-08-24 08:28:08endpoint_addedgryphe/mythomax-l2-13b | Parasail
2026-08-24 08:28:08endpoint_addedgryphe/mythomax-l2-13b | DeepInfra
2026-08-24 08:28:08endpoint_addedgryphe/mythomax-l2-13b | Mancer 2
2026-08-24 08:28:08endpoint_addedibm-granite/granite-4.0-h-micro
2026-08-24 08:28:08endpoint_addedibm-granite/granite-4.1-8b
2026-08-24 08:28:08endpoint_addedinception/mercury-2

Performance samples — fastest 10

1,145 rows · 10 shown
sample time (UTC)modelrequestsp50 latency msp50 tokens/sproviders
2026-08-23 21:14:19openai/gpt-oss-120b15.3M19196120
2026-08-23 20:13:57openai/gpt-oss-120b15.6M19095620
2026-08-23 19:15:02openai/gpt-oss-120b16.0M19495120
2026-08-24 08:28:08openai/gpt-oss-120b13.9M18992320
2026-08-24 07:27:19openai/gpt-oss-120b14.0M19092120
2026-08-24 05:25:39openai/gpt-oss-120b14.1M19092020
2026-08-24 06:26:28openai/gpt-oss-120b14.0M18892020
2026-08-24 05:25:39openai/gpt-oss-20b5.8M25642612
2026-08-24 07:27:19openai/gpt-oss-20b5.8M25442312
2026-08-24 06:26:28openai/gpt-oss-20b5.8M25541712

App usage samples — biggest 10

420 rows · 10 shown
sample time (UTC)app idranktotal tokenstotal requests
2026-08-23 21:14:193067167141.93T430.5M
2026-08-24 06:26:283067167141.82T427.8M
2026-08-24 07:27:193067167141.82T427.8M
2026-08-24 08:28:083067167141.82T427.8M
2026-08-23 19:15:023067167141.59T427.2M
2026-08-23 20:13:573067167141.59T427.2M
2026-08-24 05:25:393067167141.54T425.0M
2026-08-23 21:14:193067167113.30T134.2M
2026-08-23 19:15:023067167112.96T130.9M
2026-08-23 20:13:573067167112.96T130.9M

Fetch ledger — newest 10 requests

267 rows · 10 shown
time (UTC)classurlstatusbyteslatencycf-cache
08:28:58S2…/models/meta/muse-glimmer-30b/endpoints2004.7 KB1.68 sBYPASS
08:28:57S2…/models/meta-llama/llama-guard-4-12b/endpoints2002.0 KB37.5 msBYPASS
08:28:55S2…/models/meta-llama/llama-4-scout/endpoints2003.4 KB36.3 msBYPASS
08:28:54S2…/models/meta-llama/llama-4-maverick/endpoints2004.4 KB41.7 msBYPASS
08:28:52S2…/models/meta-llama/llama-3.3-70b-instruct/endpoints20010.8 KB39.4 msBYPASS
08:28:50S2…/models/meta-llama/llama-3.2-3b-instruct/endpoints2002.1 KB43.1 msBYPASS
08:28:49S2…/models/meta-llama/llama-3.2-1b-instruct/endpoints2001.2 KB48.6 msBYPASS
08:28:47S2…/models/meta-llama/llama-3.1-8b-instruct/endpoints2004.4 KB42.8 msBYPASS
08:28:45S2…/models/meta-llama/llama-3.1-70b-instruct/endpoints2002.8 KB75.1 msBYPASS
08:28:44S2…/models/meituan/longcat-2.0/endpoints2001.3 KB72.1 msBYPASS

Daily rankings — latest 10

1,066 rows · 10 shown
datemodel
2026-08-23z-ai/glm-5v-turbo-20260401
2026-08-23z-ai/glm-5.3-20260816
2026-08-23z-ai/glm-5.2-20260616
2026-08-23z-ai/glm-5.2-20260616
2026-08-23z-ai/glm-5.2-20260616
2026-08-23z-ai/glm-5.1-20260406
2026-08-23z-ai/glm-5-turbo-20260315
2026-08-23z-ai/glm-5-20260211
2026-08-23z-ai/glm-4.7-flash-20260119
2026-08-23z-ai/glm-4.7-20251222
Prices converted to $ per 1M tokens for legibility. Bytes and latencies are the exact values written to the ledger row: nothing here is rounded twice.

The keys — every spec has a door

Nothing on this page is a claim you have to take on faith. These are the doors; the receipts are the rows.

mirror queries

# the dials
  scrappy mirror status
# a price history, with before/after
  scrappy mirror query price-history deepseek/deepseek-chat-v3-0324
# per-provider endpoint history
  scrappy mirror query price-history deepseek/deepseek-chat-v3-0324 --endpoints
# what arrived
  scrappy mirror query new-models --since 2026-08-01
# expiring and retired models
  scrappy mirror query deprecations
# the world as it was
  scrappy mirror query snapshot --at 2026-08-23T20:00:00Z --type model
# honest re-check
  scrappy mirror verify

engine calls

# markdown to stdout
  scrappy scrape https://example.com/
# markdown + the honest receipt
  scrappy scrape https://example.com/ --json
# force the browser path
  scrappy scrape https://example.com/ --path render
# reuse a copy under 5 minutes old
  scrappy scrape https://example.com/ --max-age 300
# any cache age, no fetch at all
  scrappy scrape https://example.com/ --max-age -1
# localhost-only HTTP API
  scrappy serve --port 8787