CS2 data reference

Map results

Per-map scores, the half-by-half split, and why overtime is null rather than zero.

GET /v1/{game}/matches/{id}/maps returns one row per map played, ordered by map_number.

A bo3 has up to 3 rows and a bo1 exactly 1 — but a series that ended early has fewer rows than its format allows, so never assume a count from format.

Scores

score_a and score_b are final rounds won by team A and team B (the parent match's team_a_id / team_b_id), including overtime.

map_name is always the Valve identifier — de_ancient, de_mirage — never a display name.

The half split

first_half_a/first_half_b and second_half_a/second_half_b break the map into halves, and are null together when the split isn't available for that map. The final score is authoritative regardless.

Overtime is null, not zero

overtime_a/overtime_b are null when the map didn't go to overtime — deliberately, so you can distinguish "no overtime" from "overtime happened and this team won no rounds in it". Treating null as 0 collapses that distinction.

maps = get(f"/v1/cs2/matches/{match_id}/maps")["data"]

for m in maps:
    ot = "" if m["overtime_a"] is None else f" (OT {m['overtime_a']}-{m['overtime_b']})"
    print(f"Map {m['map_number']}: {m['map_name']} {m['score_a']}-{m['score_b']}{ot}")

Reconciling with the series score

The match's score_a/score_b count maps won, not rounds. So a 2–1 series with map scores 13–8, 10–13, 13–11 gives score_a: 2, score_b: 1. Mixing the two is a common source of confusing totals.

Which side started where

Not exposed. The half-by-half columns tell you the shape of the map without telling you which side each team opened on — that's held internally and isn't part of the customer contract today.

On this page