Per-match tournament box scores — goals, shots, key passes, tackles, duels — for every player at the 2026 World Cup, aggregated across the games they’ve played. The table fills in as matches are played; filter by position or nation, and toggle totals, per-game and per-90 rates.
Show code
statsEsc =window.statsEscstatsTable =window.statsTablebase =window.DATA_BASE_URL// Tournament window — the WC shard runs on league == "WC", which also covers// qualifier internationals. This page is tournament-only: keep rows from the// finals window (Jun 11 – Jul 19, 2026) onward.WC_START ="2026-06-01"// Three-state load:// null → fetch/parse failure (render shows "failed to load")// [] → shard not published yet (404) — friendly "tournament just started" state// rows → per-player per-match WC box scores// fetchParquet returns null on ANY failure, which would make "shard not// published yet" indistinguishable from a real outage — so probe the URL// first and translate a clean 404 into the empty state._wcStatsRaw = {const url = base +"football/match-stats-WC.parquet"try {const probe =awaitfetch(window.cacheBust(url))if (probe.body) probe.body.cancel() // headers are enough — don't buffer the fileif (probe.status===404) return [] } catch (e) {console.error("[wc-player-stats] match-stats-WC probe failed:", e)returnnull }returnawaitwindow.fetchParquet(url)}// Pre-filtered tournament rows (same shape as the club match-stats shards:// match_id, team_name, position, minsPlayed, goals, shots, passes, ...).matchStats = {if (_wcStatsRaw ==null) returnnullreturn _wcStatsRaw.filter(d => (d.league==null|| d.league==="WC") &&String(d.match_date||"").replace("Z","").slice(0,10) >= WC_START)}// Canonical position per player — first non-Substitute occurrence, newest// match first, so a cameo sub appearance doesn't become a starter's listed// position (same pattern as football/player-stats.qmd)._playerCurrentMeta = {if (!matchStats) returnnewMap()const sorted = [...matchStats].sort((a, b) =>String(b.match_date||"").localeCompare(String(a.match_date||"")))const m =newMap()for (const g of sorted) {const pid = g.player_idif (!pid) continuelet rec = m.get(pid)if (!rec) { rec = { team: g.team_name||null,position:null }; m.set(pid, rec) }if (!rec.position&& g.position&& g.position!=="Substitute"&& g.position!=="Sub") { rec.position= g.position } }// Backfill Substitute as the last resort for players who never started.for (const g of sorted) {const rec = g.player_id&& m.get(g.player_id)if (rec &&!rec.position&& g.position) rec.position= g.position }return m}