How-to

Migrate from a scraper

Mapping the concepts you already have onto this API, and what changes.

If you're arriving from a scraped HTML pipeline, most of the work is mapping vocabulary. Here's the translation.

Concept mapping

Scraper conceptHere
Match page URLid (UUIDv7) or a list filter
Team page slugslug — works directly as a path id
Event pagetournament_id, or ?tournament= on the match list
Scoreboard table/matches/{id}/stats
Round history graphic/matches/{id}/rounds
Map veto box/matches/{id}/vetoes
Rating columnrating on a stat line — ours, not a third party's
Odds comparison tableA single de-vigged line; per-book prices are not served

What gets easier

No parsing, no breakage on redesign. Field names are a versioned contract locked by tests.

Pagination that doesn't skip rows. Cursors are stable under concurrent inserts, unlike ?page=N over a table that's being written to.

Coverage is declared. data_available on each match tells you which layers exist, and /v1/cs2/coverage states what the product does and doesn't have — including what's not built yet.

Change is pushed. A WebSocket subscription replaces a polling loop entirely.

What's different

No per-book odds. The API serves one de-vigged aggregate line (eo_market) with a book_count, never individual bookmaker prices or names. If your pipeline compared books, that's not something this API replaces — see the market line.

Requests are metered. A scraper's cost is bandwidth; here it's 50,000 requests a month on Standard and 150,000 on Pro. The habit to unlearn is polling everything on one timer. See budget your requests.

rating is ours. It is not the number you scraped from elsewhere and won't match it. Compare trends, not absolute values.

logo_url is always empty. We hold no redistribution rights to team marks.

A first migration

Map your entities. Walk /v1/cs2/teams and /v1/cs2/players once at limit=500 and store the UUIDs against whatever keys you already use. A few requests, done weekly.

Replace your fixture scrape with a cached /v1/cs2/matches window — see build a fixtures cache. The list row already carries team and tournament names, so most schedule rendering needs nothing else.

Replace per-match scrapes with ?include=teams,tournament,odds plus the detail layers you actually use, gated on data_available.

Replace your live poller with a WebSocket subscription. This is usually the biggest single saving.

Backfilling what you already have

You probably have history you don't want to re-fetch. Match ids won't line up with your old keys, so join on (scheduled_at, team names) for a one-off reconciliation, then store our UUIDs and use them from then on. Pulling the historical archive covers the bulk endpoint that makes the walk cheap.

On this page