The xG pitch lab

Every cell of this half-pitch is a question put to the model: if a typical shot were taken from here, in this situation, how often does it become a goal? Click anywhere — or walk the surface with your arrow keys — then switch context and feel the same blade of grass change value.

Calibrated goal probability across the attacking half

xG per shot (probability, 0–1) · 48 × 32 grid, 1.25 × 2.5 yd cells · click or use arrow keys

  • < 1%
  • 1–3%
  • 3–6%
  • 6–12%
  • 12–25%
  • 25–45%
  • ≥ 45%
Source: StatsBomb Open Data · model fit on n = 21,760 shots · computed by pipeline/model_xg-model.py

The surfaces quantify football instinct. A one-on-one from the penalty spot is worth 0.564 — nearly four times the 0.148 of a regular open-play foot shot from the same grass. Make it a header instead and the chance collapses to 0.064. Strand the keeper 8 yards off his line and a shot from just outside the box climbs from 0.078 to 0.130. Penalties are excluded from the model and priced at their empirical rate: 411 in the data, 71.8% converted.

1 Each surface embeds location-typical defender and keeper context — unspecified features are filled with medians of the 150 nearest matching training shots. That realism has edges: on the one-on-one surface, a few wide-byline cells (~5%) can dip below open play, because true one-on-ones almost never happen there. The first-time surface differs only slightly from open play — the flag itself carries little signal once technique is held fixed.

Twelve shots you remember

Models earn trust on shots that mean something. Here are twelve — every goal from three World Cup and European finals, the miss that nearly rewrote the greatest final ever played, and one strike of pure folklore — each priced by our model and by StatsBomb’s.

Seconds from the end of extra time in the 2022 World Cup final, Randal Kolo Muani is clean through with the World Cup on his boot. Our model prices the chance at 0.235 — roughly 1 in 4 — StatsBomb says 0.278. Emiliano Martínez spreads himself and saves. Minutes earlier, Messi’s extra-time poacher’s finish was the biggest chance of the night: 0.463 by our model, 0.488 by StatsBomb’s. And then there is Jamie Vardy, volleying from thirty yards in 2016 — a 0.030 shot, 1 in 33, that flew in anyway. xG never says a goal can’t happen. It says: don’t build a gameplan on it.

Where the twelve shots were struck

shot location on a 120 × 80 yd pitch · filled dot = goal, open dot = no goal · click a dot for the story

—

Our model
StatsBomb xG
Geometry-only LR
  • Scored
  • Didn’t score
Source: StatsBomb Open Data event freeze frames · n = 12 selected shots · computed by pipeline/model_xg-model.py
The twelve shots, all three models · click a header to sort
Player Match Year Our xG StatsBomb LR baseline Outcome Held-out?

2 “Held-out” marks shots from WC 2022 and Euro 2024 — matches the model never trained on. The 2018/2020/2015-16 shots sit inside the training era and are shown for story, not for scorekeeping.

The honesty scorecard

One held-out exam, no excuses: every model prices the same 2,734 shots from WC 2022 and Euro 2024 — tournaments none of them trained on — and is judged on log-loss, Brier score, discrimination and calibration.

Log-loss gap to StatsBomb
2.7%
0.2534 vs 0.2468 · lower is better
ROC-AUC
0.792
StatsBomb production: 0.804
Worst calibration bin
3.6pp
StatsBomb’s worst: 7.6pp
Test xG vs actual goals
255.1 / 250
+2.0% over 2,734 shots

The headline: a from-scratch model using just four scalar freeze-frame summaries finishes within 2.7% log-loss of a production model that sees every defender’s coordinates. The gradient-boosted model beats the geometry-only logistic baseline by 3.4% log-loss (0.2622 → 0.2534) and +1.8 AUC points — the “real but modest” gap Robberechts & Davis reported, reproduced here on tournament data. Where we quietly win: honesty. Our worst reliability bin sits 3.6pp from the empirical goal rate; StatsBomb’s own worst bin misses by 7.6pp.

Six models, one test set (WC 2022 + Euro 2024, n = 2,734 shots) · click a header to sort
Model Log-loss ↓ Brier ↓ AUC ↑ ECE ↓

Reliability diagram: when the model says 30%, does it happen 30% of the time?

mean predicted xG vs actual goal rate, quantile bins of test shots · dot area ∝ shots in bin · labels mark each model’s worst bin

  • Our model
  • StatsBomb xG
  • Perfect calibration (y = x)
All calibration bins as a table
Quantile bins: mean predicted xG vs empirical goal rate
SeriesBinPredictedActualShots
Source: StatsBomb Open Data · test set n = 2,734 shots (WC 2022 + Euro 2024) · computed by pipeline/model_xg-model.py

3 Totals add up, tournaments diverge: across the test set our model expects 255.1 goals and 250 arrive (+2.0%). But WC 2022 overshot its xG — 152 goals on 139.7 expected (+8.8%) — while Euro 2024 undershot, 98 on 115.4 (−15%). StatsBomb’s model shows the same split. Some summers just finish colder.

What actually matters

Permutation importance asks a blunt question: scramble one feature’s values across the test set and measure how much worse the log-loss gets. Big damage means the model was leaning on it.

Geometry does most of the work, exactly as thirty years of xG literature predicts: shuffling the goal-mouth angle costs 0.0339 of log-loss and distance costs 0.0224. The finding worth the price of admission is third and fourth place: where the nearest defender stands (0.0112) and how many bodies are in the shot cone (0.0102) both outrank body part (0.0076). Knowing a defender’s position is worth more to an xG model than knowing whether the shot was taken with the head or the boot.

Permutation importance, top 8 of 16 features

increase in test log-loss when the feature is shuffled · whiskers = ±1 sd over repeats

Source: StatsBomb Open Data · test set n = 2,734 shots · computed by pipeline/model_xg-model.py

4 A data quirk found en route: StatsBomb’s defenders-in-cone count includes the goalkeeper — 86% of flagged one-on-ones carry def_in_cone = 1. Naively forcing the cone empty for the one-on-one surface inflated a 12-yard 1v1 to an implausible 0.74 xG; the pitch-lab surface is instead built from real one-on-one contexts. The remaining eight features — technique, first-time, under-pressure, pattern of play and friends — each move test log-loss by less than 0.001.

How it’s computed