Every Captains-Mode draft from TI 2025, TI 2026 and both Esports World Cups — 538 games, 12,912 draft actions, verified complete against official records. Free, CC BY 4.0.
Parquet + CSV, one download, no key, no signup. License CC BY 4.0 — use it for anything, credit batru.gg.
| tournament | event | games |
|---|---|---|
| ti-2025 | The International 2025 (Hamburg) | 144 |
| ewc-2025 | Esports World Cup 2025 (Riyadh) | 89 |
| ewc-2026 | Esports World Cup 2026 (Paris) | 157 |
| ti-2026 | The International 2026 (Shanghai) — won by Team Spirit | 148 |
A few of the stories in there: Treant Protector was picked or banned in all 148 games of TI 2026; first pick won exactly 50.0% of them; the popularity-trap hero won just 41% of the most-picked slot. Full breakdowns on the TI pick/ban page.
86 TI 2026 games carry model_pre_series_p_team1 — the win probability our calibrated pro model gave before each series was played, archived live on a 30-minute cron during the event. Because the reads pre-date the results, you can score them fairly, with no hindsight. Retro-compiled tournaments deliberately carry null: computing a “prediction” after the result is known would be a fabricated track record.
The model’s full public evaluation ledger lives on the benchmark page. Think you can beat a draft-only baseline? The dataset is the arena.
Per-event game counts were verified against both OpenDota league records and Liquipedia’s official totals. Two drafts were missing from every public API and were recovered from primary sources: one from Valve’s own record of a crashed-and-resumed game, one reconstructed from Liquipedia and the broadcast VOD — each cross-validated against games with known sequences before inclusion. The only official result excluded is a 1v1 tiebreaker (not a Captains-Mode game), noted in the dataset card.
Match facts derive from official data via the OpenDota API. Analysis only — no betting content.
import pandas as pd
games = pd.read_parquet("hf://datasets/batrugg/dota-2-pro-tournament-drafts/games.parquet")
steps = pd.read_parquet("hf://datasets/batrugg/dota-2-pro-tournament-drafts/draft_steps.parquet")
# Most contested heroes at TI 2026
print(steps[steps.tournament == "ti-2026"].groupby("hero").size().nlargest(10))
# First-pick win rate per tournament
g = games.assign(fp_won=(games.first_pick_side == "radiant") == games.radiant_win)
print(g.groupby("tournament").fp_won.mean().round(3))A ready-made starter notebook (“TI 2026 in 5 charts”) ships with the dataset.