HLTVEvery HLTV API guide

HLTV data in Python, without the scraper.

There is no official HLTV API for Python. Python HLTV libraries download hltv.org pages, and scripted requests now get a Cloudflare 403 "Just a moment..." page instead. For code that keeps working, call a CS2 API with requests: results, HLTV-style ratings, the ranking and live scores are one GET each, with a free key.

  • requests, httpx, pandas
  • No scraping
  • 500 free requests / month
GET /cs2/matches/results?limit=2200 OK
$ curl "https://api.citoapi.com/api/v1/cs2/matches/results?limit=2" \ -H "x-api-key: $CITO_API_KEY"
{  "success": true,  "data": [    {      "id": "cs2-match-2399131",      "eventName": "Stake Pulse Beat III",      "bestOf": 3,      "team1Name": "Ninjas in Pyjamas",      "team2Name": "Betclic",      "score": {        "team1": 2,        "team2": 1      }    },    {      "id": "cs2-match-2399130",      "eventName": "Stake Pulse Beat III",      "bestOf": 3,      "team1Name": "Inner Circle",      "team2Name": "Sangal",      "score": {        "team1": 2,        "team2": 0      }    },    "__more__"  ]}

Seamless Integration with our MCP Server

Give Claude, Cursor, and ChatGPT the CS2 data. One command writes the MCP config; agents call live scoreboard, team map stat, opening duel, and transfer tools instead of inventing match IDs, and your key stays on your machine.

MCPInstall the Cito MCP server
Claude
Cursor
OpenAI
Python
Cito API
Next.js
Discord
Slack
GitHub

Why do Python HLTV libraries stop working?

They are scrapers: they request hltv.org pages and parse the HTML. When we sent a plain Python request to hltv.org on 7 October 2026 it got 403 Forbidden with cf-mitigated: challenge, a Cloudflare check that needs a real browser. A library cannot parse a page it never receives.

The full error, and how to detect it in your own code: HLTV scraper alternative and the 403 fix.

Release dates read on PyPI and GitHub on 7 October 2026. HLTV's terms (clause 2.2) prohibit scraping its website.
Python packageLatest releaseHow it gets data
hltv-async-api (PyPI)0.8.3, 3 June 2024Downloads hltv.org pages; its README shows 403 retries and proxy options
hltv-data (PyPI)0.4.0, 9 March 2024Downloads hltv.org pages with requests
SocksPls/hltv-api (GitHub)No PyPI releaseDownloads hltv.org pages; its issues report "Just a moment..." pages

Step 1: How do I set up Python?

Install requests, create a free key at citoapi.com, and keep it in an environment variable. Every call sends it in the x-api-key header; nothing else is needed, no browser and no cookies.

Shell
pip install requests
export CITO_API_KEY="cito_..."   # Windows PowerShell: $env:CITO_API_KEY = "cito_..."
Python: a tiny client
import os, requests

API = "https://api.citoapi.com/api/v1/cs2"
session = requests.Session()
session.headers["x-api-key"] = os.environ["CITO_API_KEY"]

def get(path: str, **params):
    r = session.get(f"{API}{path}", params=params, timeout=10)
    r.raise_for_status()
    return r.json()

Step 2: How do I get recent results?

GET /cs2/matches/results returns finished matches newest first with the event, the format and the series score. Filter one team with /cs2/teams/{slug}/results.

Python
for m in get("/matches/results", limit=10)["data"]:
    print(f"{m['eventName']}: {m['team1Name']} {m['team1Score']}-{m['team2Score']} {m['team2Name']} (Bo{m['bestOf']})")

vitality = get("/teams/vitality/results", limit=5)["data"]

Step 3: How do I get a player's HLTV-style stats?

Players take the slug you already know. /cs2/players/{slug} has the career rating; /cs2/players/{slug}/matches has one row per map with rating, ADR, KAST, kills and deaths.

Python
p = get("/players/zywoo")["data"]
print(p["nickname"], p["realName"], "career rating", p["rating"], "over", p["mapsPlayed"], "maps")

for row in get("/players/zywoo/matches", limit=5)["data"]:
    print(row["map"]["mapName"], f"{row['kills']}-{row['deaths']}", "ADR", row["adr"], "rating", row["rating"])

Step 4: How do I get the team ranking?

GET /cs2/rankings/world returns the world ranking with rank, points and weekly change; /cs2/rankings/vrs returns Valve's Regional Standings in the same shape.

Python
ranking = get("/rankings/world", limit=10)
print("Week of", ranking["meta"]["rankingDate"])
for t in ranking["data"]:
    print(t["rank"], t["teamName"], t["points"], "pts")

Step 5: How do I follow live scores?

Poll GET /cs2/matches/live every 15 to 30 seconds. Each match carries the series score, the map in play, the round and the CT and T score on that map.

Python
import time

while True:
    for m in get("/matches/live")["data"]:
        print(f"{m['team1Name']} {m['team1Score']}-{m['team2Score']} {m['team2Name']} | "
              f"{m['currentMap']} round {m['currentRound']} (CT {m['currentScoreCt']} : T {m['currentScoreT']})")
    time.sleep(30)

Step 6: How do I load stats into pandas?

Every list endpoint returns data as an array of flat-ish objects, so pandas.json_normalize turns a response into a DataFrame in one line. The 90-day leaderboard is a good start for a model or a chart.

Python
import pandas as pd

rows = get("/leaderboards/rating", limit=50)["data"]
df = pd.json_normalize(rows)[["playerName", "teamName", "maps", "rating", "adr", "kast", "kd"]]
print(df.sort_values("adr", ascending=False).head(10).to_string(index=False))

Can I use httpx or asyncio instead?

Yes. The API is plain HTTPS and JSON, so any client works. With httpx you can fetch several players at once; stay under your plan's per-minute limit, which every response reports.

Python: httpx + asyncio
import asyncio, os, httpx

API = "https://api.citoapi.com/api/v1/cs2"

async def main():
    async with httpx.AsyncClient(headers={"x-api-key": os.environ["CITO_API_KEY"]}, timeout=10) as c:
        slugs = ["zywoo", "donk", "m0nesy"]
        res = await asyncio.gather(*(c.get(f"{API}/players/{s}") for s in slugs))
        for r in res:
            p = r.raise_for_status().json()["data"]
            print(p["nickname"], p["rating"])

asyncio.run(main())

Endpoints you can ship with

Every endpoint the Python examples call.

Results

Finished matches with the series score and winner, every map and its score, and the player lines behind them.

View docs
  • GET/api/v1/cs2/matches/recent

    Finished matches with final series score and winner, newest first.

  • GET/api/v1/cs2/matches/{matchId}

    One match: event, teams, series score, and maps.

  • GET/api/v1/cs2/matches/{matchId}/maps

    Each map: name, score, winner, and the team that picked it.

  • GET/api/v1/cs2/matches/{matchId}/player-stats

    Per-player stats for each map: kills, deaths, ADR, KAST and rating.

  • GET/api/v1/cs2/teams/{teamIdOrSlug}/results

    One team's finished matches, newest first.

  • GET/api/v1/cs2/events/{eventIdOrSlug}/results

    Final placements and prize money of a tournament.

FAQs

HLTV and CS2 data in Python

Can't find what you're looking for? Contact our customer support team

Read the CS2 docs

Build in Python: stat bots

Create a free key and run the examples above.