football-docs 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -98,9 +98,49 @@ File: `matches/{competition_id}/{season_id}.json`
98
98
 
99
99
  ### Data Quality Flags
100
100
 
101
- - `data_version` -- spec version (current: `"1.1.0"`)
102
- - `shot_fidelity_version` -- `"1"` (basic) or `"2"` (enhanced, includes freeze frames on shots)
103
- - `xy_fidelity_version` -- `"1"` (less precise locations) or `"2"` (high-precision x/y coordinates)
101
+ `metadata` (object on each match; child attributes are optional and the object
102
+ is empty for matches not yet `available`):
103
+
104
+ - `data_version` -- the event-data collection version applied to this match (e.g. `1.0.0`, `1.0.1`, `1.0.2`, `1.0.3`, `1.1.0`). Which optional event fields are populated depends on this value; `1.1.0` is the fullest.
105
+ - `shot_fidelity_version` -- `"1"` (basic) or `"2"` (high-fidelity x/y on shots, freeze frames and shot-paired events)
106
+ - `xy_fidelity_version` -- `"1"` (standard location granularity) or `"2"` (high-precision x/y coordinates)
107
+
108
+ ### Match & collection status (Matches API v6)
109
+
110
+ The Matches response carries several status fields. Events/360 are only
111
+ fetchable once the relevant status reaches `available`:
112
+
113
+ | Field | Values |
114
+ |---|---|
115
+ | `match_status` | `available` (event data obtainable), `scheduled`, `deleted` |
116
+ | `match_status_360` | `available`, `scheduled` (awaiting 360), `unscheduled` (comp gets no 360) |
117
+ | `play_status` | `Normal`, `Postponed`, `Cancelled`, `Abandoned`, `Forfeited` |
118
+ | `collection_status` | collection pipeline state (16 values, below) |
119
+
120
+ `collection_status` values: `Unassigned` (not started), `InProgress`,
121
+ `WithoutLocation` (events not yet located on pitch), `WithoutFreezeFrame` (shot
122
+ freeze-frame phase), `PendingValidation`, `Validating`, `Invalid`,
123
+ `WithoutDirection`, `Complete`, `Postponed`, `NoVidError` (footage not sourced),
124
+ `IncVidError` (incomplete footage), `PoorVidError`, `ErrorAbandoned`,
125
+ `ErrorCancelled`, `ErrorForfeit`.
126
+
127
+ Use `last_updated` / `last_updated_360` per match (and the Competitions
128
+ `match_updated*` / `match_available*` timestamps) to drive incremental sync —
129
+ see `api-endpoints.md`.
130
+
131
+ ### Competition stages
132
+
133
+ `competition_stage` is an `{id, name}` pair. Stage IDs (from Matches/Events
134
+ specs): 1 Regular Season, 2 Play-In Round, 6 Europa League Play-offs –
135
+ Semi-finals, 8 MLS Cup – Conference Semi-finals, 9 3rd Qualifying Round,
136
+ 10 Group Stage, 11 Quarter-finals, 12 Europa League Play-offs – Finals,
137
+ 13 16th Finals, 14 Promotion Play-offs – Final, 15 Semi-finals, 18 Promotion
138
+ Play-offs – Semi-finals, 19 Preliminary Round, 20 2nd Round, 21 Europa League
139
+ Play-offs – Quarter-finals, 22 2nd Qualifying Round, 23 MLS Cup – Conference
140
+ Finals, 24 Promotion Play-offs – 1st Round, 25 3rd Place Final, 26 Final,
141
+ 27 Promotion Play-offs – 2nd Round, 28 Play-offs, 29 1st Qualifying Round,
142
+ 31 Preliminary Round – Semi-finals, 33 8th Finals, 34 1st Phase, 35 Preliminary
143
+ Round – Final.
104
144
 
105
145
  ---
106
146
 
@@ -316,11 +356,14 @@ Every event is tagged with how the current possession started (counter-attack, s
316
356
 
317
357
  ## Data Versions
318
358
 
319
- | Version | Field | Notes |
320
- |---------|-------|-------|
321
- | `data_version` | `1.0.0` | Original spec |
322
- | `data_version` | `1.1.0` | Current spec with carries, enhanced events |
323
- | `shot_fidelity_version` | `"1"` | Basic shot data |
324
- | `shot_fidelity_version` | `"2"` | Enhanced shots with freeze frames |
325
- | `xy_fidelity_version` | `"1"` | Standard coordinate precision |
326
- | `xy_fidelity_version` | `"2"` | High-precision coordinates |
359
+ Each match's `metadata` reports the collection versions applied to it. The
360
+ values you may see, side by side:
361
+
362
+ | Field | Value | What this match contains |
363
+ |-------|-------|--------------------------|
364
+ | `data_version` | `1.0.0` | Core event set, no carry events |
365
+ | `data_version` | `1.1.0` | Full event set including carries and the additional event attributes described on this page and in `event-types.md` |
366
+ | `shot_fidelity_version` | `"1"` | Shots at standard location granularity |
367
+ | `shot_fidelity_version` | `"2"` | Shots, their freeze frames, and shot-paired events at high-precision x/y |
368
+ | `xy_fidelity_version` | `"1"` | Standard x/y location granularity |
369
+ | `xy_fidelity_version` | `"2"` | High-precision x/y coordinates |
@@ -9,6 +9,7 @@ StatsBomb uses named event types with numeric IDs. Every event in a match has a
9
9
  | 2 | Ball Recovery | Player regains possession from a loose ball |
10
10
  | 3 | Dispossessed | Player loses the ball through opponent action (not a failed dribble) |
11
11
  | 4 | Duel | Contested situation between two players (aerial or ground) |
12
+ | 5 | Camera On* | Signals the camera resuming gameplay capture after a replay/cut (deprecated; superseded by `off_camera`) |
12
13
  | 6 | Block | Player blocks a shot, pass, or cross |
13
14
  | 8 | Offside | Player caught in an offside position |
14
15
  | 9 | Clearance | Defensive action to remove the ball from a dangerous area |
@@ -18,10 +19,12 @@ StatsBomb uses named event types with numeric IDs. Every event in a match has a
18
19
  | 17 | Pressure | Player applies pressure on an opponent in possession |
19
20
  | 18 | Half Start | Marks the start of each half/period |
20
21
  | 19 | Substitution | Player substitution |
22
+ | 20 | Own Goal Against | An own goal scored against the team |
21
23
  | 21 | Foul Won | Player wins a foul from an opponent |
22
24
  | 22 | Foul Committed | Player commits a foul |
23
25
  | 23 | Goal Keeper | Goalkeeper-specific actions (saves, punches, claims, etc.) |
24
26
  | 24 | Bad Behaviour | Disciplinary action not linked to a foul (e.g. dissent) |
27
+ | 25 | Own Goal For | An own goal scored for the team |
25
28
  | 26 | Player On | Player enters the pitch (substitution on) |
26
29
  | 27 | Player Off | Player leaves the pitch (substitution off) |
27
30
  | 28 | Shield | Player shields the ball from an opponent |
@@ -30,12 +33,20 @@ StatsBomb uses named event types with numeric IDs. Every event in a match has a
30
33
  | 34 | Half End | Marks the end of each half/period |
31
34
  | 35 | Starting XI | Starting lineup announcement (one per team per match) |
32
35
  | 36 | Tactical Shift | Formation or positional change during play |
36
+ | 37 | Error | Player makes an on-the-ball mistake that leads to a shot on goal |
33
37
  | 38 | Miscontrol | Player fails to control the ball cleanly |
34
38
  | 39 | Dribbled Past | Player is beaten by an opponent's dribble |
35
39
  | 40 | Injury Stoppage | Play stopped due to injury |
40
+ | 41 | Referee Ball-Drop | Referee drops the ball to resume play after an injury stoppage |
36
41
  | 42 | Ball Receipt* | Player receives a pass (the asterisk is part of the name) |
37
42
  | 43 | Carry | Player moves with the ball at their feet between events |
38
43
 
44
+ > The event-type vocabulary and field set below describe the **Events API
45
+ > v8.0.0** feed (`GET /api/v8/events/{match_id}`). Each match also carries a
46
+ > `metadata.data_version` string (see `data-model.md`) — the exact set of
47
+ > fields present on a given match depends on the data version it was collected
48
+ > under.
49
+
39
50
  ---
40
51
 
41
52
  ## Common Event Fields
@@ -76,6 +87,25 @@ Every event shares these base fields:
76
87
  - `duration` -- event duration in seconds (0.0 for instantaneous events)
77
88
  - `related_events` -- UUIDs of causally linked events (e.g. pass -> receipt)
78
89
  - `under_pressure` -- boolean, present and true when a defender is applying pressure
90
+ - `off_camera` -- boolean, present and true only when the event occurred while the camera was off (data then logically inferred)
91
+ - `out` -- boolean, present and true when the event's outcome is the ball going out of bounds
92
+ - `counterpress` -- boolean, on various defensive events (pressure, dribbled past, 50-50, duel, block, interception, non-offensive foul committed): a pressing action within 5 seconds of an open-play turnover
93
+
94
+ ### On-Ball Value fields
95
+
96
+ OBV-eligible events carry net/before/after value fields measuring the change in
97
+ scoring/conceding likelihood caused by the event:
98
+
99
+ - `obv_for_after`, `obv_for_before`, `obv_for_net` -- scoring likelihood within the possession chain after/before/net
100
+ - `obv_against_after`, `obv_against_before`, `obv_against_net` -- conceding likelihood in the next possession chain
101
+ - `obv_total_net` -- net expected goal-difference change over the next two possession chains
102
+
103
+ OBV is populated only where play is not interrupted by off-ball events.
104
+ Eligible types: Carry, Ground/High/Low Pass, Dribble, Shot, Goalkeeper
105
+ Collection, Block, Tackle, Interception, Clearance, Goalkeeper Sweep,
106
+ Goalkeeper Save, Foul Committed, Goalkeeper Concede. See
107
+ `iq-metrics-glossary.md` for the OBV concept and its aggregated forms in the
108
+ stats endpoints.
79
109
 
80
110
  ---
81
111
 
@@ -103,7 +133,12 @@ The `shot` object is nested within shot events.
103
133
 
104
134
  | Field | Type | Description |
105
135
  |-------|------|-------------|
106
- | `statsbomb_xg` | float | StatsBomb expected goals value (0.0 to 1.0) |
136
+ | `statsbomb_xg` | float | xG "chance quality" -- likelihood of scoring from the shot situation (location, GK and blocker positions), **not** considering shot execution |
137
+ | `gk_save_difficulty_xg` | float | Likelihood of the keeper conceding, given shot placement/velocity and keeper position (on-target, unblocked shots only). Some feeds label this field `statsbomb_xg2` |
138
+ | `shot_execution_xg` | float | Likelihood of scoring after execution -- incorporates placement & velocity on top of the `statsbomb_xg` features |
139
+ | `shot_execution_xg_uplift` | float | `shot_execution_xg − statsbomb_xg`; how much execution improved (or, if negative, worsened) the chance |
140
+ | `gk_positioning_xg_suppression` | float | Goal-scoring threat suppressed by the keeper's positioning vs an average keeper |
141
+ | `gk_shot_stopping_xg_suppression` | float | Goals prevented above expectation by the keeper's shot-stopping |
107
142
  | `end_location` | [x, y] or [x, y, z] | Where the shot ended up. Z is height in yards (present for shots that leave the ground) |
108
143
  | `key_pass_id` | string | UUID of the pass that assisted this shot |
109
144
  | `technique` | object | How the shot was struck |
@@ -207,6 +242,12 @@ The `pass` object is nested within pass events.
207
242
  | `no_touch` | boolean | Player intended the ball to run through |
208
243
  | `miscommunication` | boolean | Pass and recipient miscommunicated |
209
244
  | `backheel` | boolean | Whether the pass was a backheel |
245
+ | `deflected` | boolean | Pass was deflected (can occur on complete or incomplete passes) |
246
+ | `aerial_won` | boolean | The pass event was also an aerial duel won |
247
+ | `pass_cluster_id` | integer | Which of 60 distinct pass clusters this pass is most associated with |
248
+ | `pass_cluster_label` | string | Text description of that cluster, combining its starting third, side of the pitch, length (long/short), primary direction, and modal pass height |
249
+ | `pass_cluster_probability` | float | Probability the pass belongs to `pass_cluster_id`/`label` |
250
+ | `pass_success_probability` | float | Estimated likelihood of the attempted pass being completed, given pitch location, context and target |
210
251
 
211
252
  ### Pass Types
212
253
 
@@ -0,0 +1,81 @@
1
+ ---
2
+ source_type: curated
3
+ source_url: https://github.com/statsbomb/open-data
4
+ upstream_version: null
5
+ crawled_at: null
6
+ ---
7
+
8
+ # StatsBomb Identity Surfaces
9
+
10
+ StatsBomb provides strong match, lineup, event, and tactical context for covered
11
+ competitions. Open Data is excellent for public examples and corroboration, but
12
+ its coverage is selective and should not be treated as a full canonical register
13
+ source unless the exact scope has been audited.
14
+
15
+ ## Access Surface
16
+
17
+ StatsBomb identity examples can come from the public Open Data repository, the
18
+ `statsbombpy` wrapper, or licensed commercial APIs. Public docs should prefer
19
+ Open Data IDs and explicitly say when guidance is inferred from Open Data rather
20
+ than a commercial entitlement.
21
+
22
+ ## Stable Identity Surfaces
23
+
24
+ | Entity | Common surface | Notes |
25
+ |---|---|---|
26
+ | Competition | `competition_id` | Stable inside StatsBomb. Pair with `competition_name` and country/region for human review. |
27
+ | Season | `season_id` under a competition | Stable inside StatsBomb. Not globally unique without competition context in some workflows. |
28
+ | Match | `match_id` | Strong match bridge for covered matches. |
29
+ | Team | `team_id` | Strong team bridge inside StatsBomb data. Check whether a single ID is being used across provider-side historical segmentation. |
30
+ | Player | `player_id` | Strong player bridge inside lineups/events. Corroborate with names, DOB from another authority, and relationship evidence. |
31
+ | Coach or manager | lineup or match metadata surfaces where present | Treat as role evidence. Coverage is less central than player/event data. |
32
+
33
+ ## ID Scheme Notes
34
+
35
+ StatsBomb Open Data exposes numeric `competition_id`, `season_id`, `match_id`,
36
+ `team_id`, and `player_id` fields, plus event UUIDs. The numeric IDs are stable
37
+ inside the provider dataset but should stay provider-scoped. Do not infer global
38
+ identity from a bare number without provider and dataset context.
39
+
40
+ ### Two internal ID systems: live vs offline
41
+
42
+ StatsBomb does **not** have a single ID space. Internally there is a *live*
43
+ system and an *offline* system, each with its own ids for players, teams,
44
+ country-of-birth, and matches (`live_player_id` vs `offline_player_id`,
45
+ `live_team_id` vs `offline_team_id`, `live_match_id` vs `offline_match_id`,
46
+ etc.). The same person/team has different integers in each. Which system's ids
47
+ appear in a given feed depends on the system that produced it.
48
+
49
+ Treat a StatsBomb id as a **(system, id)** pair, not a bare integer. Reconciling
50
+ the two requires the commercial **Player Mapping** endpoint
51
+ (`/api/v1/player-mapping`), which returns paired `live_*`/`offline_*` ids — see
52
+ `player-mapping.md`. Open Data does not expose this duality or the mapping
53
+ endpoint, so Open-Data-only workflows generally see one system's ids and should
54
+ record which.
55
+
56
+ ## Useful Matching Fields
57
+
58
+ - Competitions and seasons: IDs, names, country, gender, and season label.
59
+ - Matches: match ID, date, home and away team IDs, score, competition, season,
60
+ match status, and lineup availability.
61
+ - Teams: team IDs and names from matches, lineups, and events.
62
+ - Players: player IDs, names, team membership in lineups/events, shirt number,
63
+ position, and event participation.
64
+
65
+ ## Known Quirks
66
+
67
+ - Open Data coverage is selective. Absence from open data is not evidence that
68
+ an entity or match does not exist.
69
+ - StatsBomb lineups are strong match-grain relationship evidence but not the
70
+ same as club or national-team contract membership.
71
+ - Public Open Data may include rich international matches but not full
72
+ tournament squad or call-up semantics.
73
+ - Names can be display names. Use another attribute authority for DOB where a
74
+ person bridge requires it.
75
+
76
+ ## Reep Next Usage
77
+
78
+ Use this page as the public provider-fact reference for StatsBomb identity
79
+ surfaces. Reep Next can cite Open Data ID families and matching cautions, while
80
+ commercial entitlement assumptions, register acceptance policy, private review
81
+ evidence, and derived bridge decisions belong outside football-docs.
@@ -0,0 +1,223 @@
1
+ ---
2
+ source_type: curated
3
+ source_url: https://github.com/statsbomb/open-data
4
+ upstream_version: null
5
+ crawled_at: null
6
+ ---
7
+
8
+ # StatsBomb IQ Metrics Glossary
9
+
10
+ Definitions of the derived metrics that recur across the StatsBomb commercial
11
+ stats endpoints (`player-match-stats`, `player-season-stats`,
12
+ `team-match-stats`, `team-season-stats`) and, for OBV/xG, the Events feed.
13
+ These concepts are referenced by many column names — read this alongside the
14
+ per-endpoint catalogues.
15
+
16
+ These metrics are commercial-only unless noted. OBV and the xG-decomposition
17
+ fields also appear on individual events; everything else is delivered
18
+ pre-aggregated by the stats endpoints.
19
+
20
+ ## On-Ball Value (OBV)
21
+
22
+ OBV models the change in the likelihood of scoring/conceding caused by an event,
23
+ expressed in expected-goal-difference units.
24
+
25
+ On an **event** (Events v8) it appears decomposed as:
26
+ - `obv_for_after` / `obv_for_before` — probability of scoring within the
27
+ possession chain after / before the event.
28
+ - `obv_for_net` — net change in scoring likelihood from the event.
29
+ - `obv_against_after` / `obv_against_before` / `obv_against_net` — same for the
30
+ likelihood of conceding in the next possession chain.
31
+ - `obv_total_net` — net change in expected goal difference (scoring change minus
32
+ conceding change) over the next two possession chains.
33
+
34
+ OBV is only populated where the sequence of play is not interrupted by off-ball
35
+ events. Event types eligible for OBV: Carry, Ground/High/Low Pass, Dribble,
36
+ Shot, Goalkeeper Collection, Block, Tackle, Interception, Clearance, Goalkeeper
37
+ Sweep, Goalkeeper Save, Foul Committed, Goalkeeper Concede.
38
+
39
+ In the **stats** endpoints OBV is aggregated and split by action family:
40
+ `*_obv` (total), `*_obv_pass`, `*_obv_shot`, `*_obv_defensive_action`,
41
+ `*_obv_dribble_carry`, `*_obv_gk`. Team stats add `*_obv_*_conceded` (opponent
42
+ OBV). Season uses `_90` / `_pg` suffixes.
43
+
44
+ ## xGChain and xGBuildup
45
+
46
+ Both attribute the xG of a possession's final shot to **every player involved in
47
+ that possession**, not just the shooter/assister.
48
+
49
+ - **xGChain** — credits all players who touched the ball during a possession
50
+ that ended in a shot, with the shot's xG.
51
+ - **xGBuildup** — the same, but **excludes** the shooter and the assisting
52
+ (key) pass, isolating contribution to build-up play prior to the chance.
53
+
54
+ Variants across the stats endpoints: `xgchain` / `xgbuildup`, `op_*` (open play
55
+ only), `*_per_possession`, and `_90` / `_pg` season forms.
56
+
57
+ ## xG, npxG, xA and combined measures
58
+
59
+ - `np_xg` — non-penalty expected goals (xG excluding penalty shots).
60
+ - `np_xg_per_shot` — shot-quality proxy: average npxG per shot taken.
61
+ - `xa` / `op_xa` / `sp_xa` — expected assists: the xG of the shot a player's
62
+ pass set up (all / open play / set piece).
63
+ - `npxgxa` (season) — non-penalty xG + xA combined goal contribution.
64
+ - `over_under_performance` (season) — actual goal contribution minus expected
65
+ (xG+xA): finishing/creation over- or under-performance.
66
+ - `conversion_ratio` / `penalty_conversion_ratio` — % of (non-penalty / penalty)
67
+ shots converted to goals.
68
+
69
+ ## Post-Shot xG (PSxG) and goalkeeping value
70
+
71
+ PSxG models goal probability **after** the shot is struck, using placement and
72
+ velocity — only defined for on-target, unblocked shots. Used to value
73
+ goalkeeping.
74
+
75
+ - `np_psxg` — non-penalty PSxG earned from a player's on-target shots.
76
+ - `npot_psxg_faced` / `np_psxg_faced_90` — non-penalty on-target PSxG faced by a
77
+ goalkeeper.
78
+ - `gsaa` (Goals Saved Above Average) — goals the keeper saved/conceded versus
79
+ expectation (PSxG faced minus goals conceded). `gsaa_ratio` expresses it as a
80
+ share of shots faced. `xs_ratio` (season) — expected save % given PSxG faced.
81
+ - `save_ratio` — % of on-target shots saved.
82
+ - `gk_positioning_error` / `np_optimal_gk_dlength` — average distance of the
83
+ keeper from the modelled optimal position for facing a shot.
84
+ - `da_aggressive_distance` — average distance from goal at which the keeper
85
+ performs defensive actions (sweeping tendency).
86
+ - `ccaa` / `clcaa` — Claimable Collection Attempts over Average: how often the
87
+ keeper attempts to claim a claimable pass vs the average keeper.
88
+ - `claim_success` — % of claim attempts that succeed.
89
+ - `goals_conceded` (player-match) — goals conceded by the keeper, excluding
90
+ penalties and own goals.
91
+
92
+ The Events v8 shot object decomposes shot xG into: `statsbomb_xg` (chance
93
+ quality — pre-strike situation including GK/defender positions),
94
+ `shot_execution_xg` (incorporates placement & velocity),
95
+ `shot_execution_xg_uplift` (`shot_execution_xg − statsbomb_xg`; can be
96
+ negative), `gk_save_difficulty_xg` (renamed from `statsbomb_xg2`; difficulty for
97
+ the keeper given placement/velocity/position), `gk_positioning_xg_suppression`
98
+ and `gk_shot_stopping_xg_suppression` (threat suppressed by keeper positioning /
99
+ shot-stopping). See `xg-model.md`.
100
+
101
+ ## PPDA — Passes Per Defensive Action
102
+
103
+ `ppda` (team stats) — how many passes a team allows the opponent before making a
104
+ defensive action (tackle, interception, foul). Lower = more intense pressing.
105
+ StatsBomb defines it in attacking areas: from 40% of pitch length away from the
106
+ pressing team's own goal and forward. `defensive_distance_ppda` is the average
107
+ distance from a team's own goal at which it makes those defensive actions.
108
+
109
+ ## Pressing and counterpressing
110
+
111
+ - `pressures` — times a player/team pressures an opponent in possession.
112
+ - `counterpressures` — pressures within 5 seconds of the team losing the ball
113
+ (an open-play turnover).
114
+ - `pressure_regains` / `counterpressure_regains` /
115
+ `defensive_action_regains` — ball won back within 5 seconds of a pressure /
116
+ counterpressure / any defensive action.
117
+ - `pressured_action_fails` / `counterpressured_action_fails` — opponent actions
118
+ forced to fail under (counter)pressure.
119
+ - `aggressive_actions` — tackles, pressures and fouls within 2 seconds of an
120
+ opposition ball receipt. `aggression` — the proportion of an opponent's pass
121
+ receipts so contested.
122
+ - `fhalf_*` — restricted to the opposition (final) half of the pitch;
123
+ `fhalf_*_ratio` expresses it as a share of the player's/team's total.
124
+ - `defensive_distance` — average distance from a team's own goal at which it
125
+ makes defensive actions (higher = higher defensive line / more proactive).
126
+
127
+ ## Possession-adjusted defensive metrics (padj_*)
128
+
129
+ `padj_clearances`, `padj_interceptions`, `padj_pressures`, `padj_tackles`,
130
+ `padj_tackles_and_interceptions` (season, per-90) — raw counts adjusted
131
+ proportionally to the team's possession volume, so low-possession teams' high
132
+ raw defensive counts are normalised for fair cross-team comparison.
133
+
134
+ ## Progression and territory
135
+
136
+ - `deep_progressions` — passes, dribbles and carries into the opposition final
137
+ third.
138
+ - `deep_completions` — successful passes within ~20 m of the opposition goal.
139
+ - `passes_into_box` / `op_passes_into_box` — successful passes into the box from
140
+ outside it (all / open play).
141
+ - `passes_inside_box` — passes completed both starting and ending in the box.
142
+ - `directness` (team) — distance gained towards goal during a shot-ending
143
+ possession divided by total distance travelled in the build-up (1.0 = perfectly
144
+ direct).
145
+ - `pace_towards_goal` (team) — average build-up speed (m/s) from start of
146
+ possession to shot, for shot-ending possessions.
147
+ - `pass_length` family — `s_pass_length` (avg completed), `p_pass_length` /
148
+ `ps_pass_length` (under pressure), `pass_length_ratio` (completed length ÷
149
+ attempted length), `pressured_change_in_pass_length`.
150
+ - Pass-direction proportions (season) — `forward_pass_proportion`,
151
+ `backward_pass_proportion`, `sideways_pass_proportion` (and `op_f3_*`
152
+ variants). Direction is defined by radian arcs of the pass-angle circle:
153
+ forwards = 11π/6→π/6, backwards = 5π/6→7π/6, sideways = the two remaining
154
+ arcs, where angle 0 = no change in y (towards the opponent goal line).
155
+
156
+ ## Line-Breaking Passes (LBP) — requires 360 data
157
+
158
+ A pass is line-breaking when it crosses a defensive line (a row of sufficiently
159
+ close defenders) and makes enough progression toward the centre of the goal.
160
+ 360 data also carries this as a per-event `line_breaking_pass` boolean. The
161
+ stats endpoints expose a large LBP suite:
162
+
163
+ - `lbp` / `lbp_completed` / `lbp_ratio` — attempted / completed / success %.
164
+ - `fhalf_*` and `f3_*` — restricted to opposition half / final third.
165
+ - `obv_lbp` — pass-OBV from line-breaking passes.
166
+ - `lbp_received` — line-breaking passes received.
167
+ - `lbp_to_space_{2,5,10}` — completed LBPs whose recipient had >2/5/10 m of
168
+ space; `*_received` variants; `average_lbp_to_space_distance` /
169
+ `*_received_distance` — average space of the recipient.
170
+
171
+ These (and the `ball_receipts_in_space_{2,5,10}`,
172
+ `average_space_received_in`, `*_passes_360`, `*_ball_receipts_360`,
173
+ `360_minutes`) metrics are derived from 360 data and only populated for matches
174
+ that have it. **Per-90 conversion for 360-derived season metrics uses
175
+ `player_season_360_minutes` / `team_season` 360 minutes, not the standard
176
+ minutes field** — see `player-season-stats.md`.
177
+
178
+ ## Ball receipts in space (360)
179
+
180
+ - `average_space_received_in` — average value of space for all ball receipts
181
+ (`fhalf_` / `f3_` variants for opposition half / final third).
182
+ - `ball_receipts_in_space_{2,5,10}` — share of ball receipts made with more than
183
+ 2/5/10 m of space. The 5 m set is a subset of the 2 m set; the 10 m set is a
184
+ subset of both.
185
+
186
+ ## Outcome / involvement scores
187
+
188
+ - `positive_outcome_score` — how frequently the player is involved, while on the
189
+ pitch, in sequences that resolve with a positive outcome (a shot, a free kick
190
+ in the attacking half, or a corner).
191
+ - `positive_outcome` (season count) — possessions that connected through the
192
+ player and ended in such an outcome.
193
+ - `defensive_actions` — tackles, pressure events and fouls recorded
194
+ (`_90` per-90 in season).
195
+ - `shot_touch_ratio` — shots taken as a proportion of touches.
196
+ - `challenge_ratio` — % of duels entered where the player makes a tackle rather
197
+ than being dribbled past. `dribble_faced_ratio` — % of faced dribbles that
198
+ were stopped.
199
+ - `change_in_passing_ratio` (season) — pressured pass % minus overall pass %.
200
+
201
+ ## Set-piece breakdown (team stats)
202
+
203
+ Team stats split attacking and conceding output by set-piece type: `corner`,
204
+ `free_kick` (indirect), `direct_free_kick`, `throw_in`, and aggregate `sp`.
205
+ For each: counts, `*_xg`, `xg_per_*`, `shots_from_*`, `goals_from_*`, and
206
+ `*_shot_ratio` / `*_goal_ratio`, each with a `_conceded` mirror. Also
207
+ `counter_attacking_shots` (shots within 15 s of a possession from own half),
208
+ `high_press_shots` (shots from possessions won within 5 s of a defensive action
209
+ in the opposition half), `shots_in_clear` (only the keeper between shooter and
210
+ goal) — all with `_conceded` mirrors.
211
+
212
+ ## Suffix conventions
213
+
214
+ - `op_` — open play only (excludes set pieces).
215
+ - `np_` — non-penalty (excludes penalty shots/goals).
216
+ - `sp_` — set piece only.
217
+ - `fhalf_` — opposition (final) half of the pitch.
218
+ - `f3_` — final third.
219
+ - `padj_` — possession-adjusted.
220
+ - `_90` — per 90 minutes (player-season; uses `360_minutes` for 360 metrics).
221
+ - `_pg` — per game (team-season).
222
+ - `_conceded` — the value allowed to/by the opponent (team stats).
223
+ - `*_ratio` — a percentage or proportion.
@@ -0,0 +1,148 @@
1
+ ---
2
+ source_type: curated
3
+ source_url: https://github.com/statsbomb/open-data
4
+ upstream_version: "1.0.0"
5
+ crawled_at: null
6
+ ---
7
+
8
+ # StatsBomb Player Mapping API
9
+
10
+ The Player Mapping endpoint bridges StatsBomb's **two internal ID systems** —
11
+ the *live* system and the *offline* system — for players, teams, and countries.
12
+ **Commercial API only**; there is no Open Data equivalent.
13
+
14
+ - Endpoint: `GET https://data.statsbomb.com/api/v1/player-mapping?<params>` (v1)
15
+ - Auth: HTTP Basic (StatsBomb credentials)
16
+
17
+ ## Why this matters: live vs offline IDs
18
+
19
+ StatsBomb does not have a single player/team/country ID space. The same player
20
+ has a **`live_player_id`** (StatsBomb Live system) and a separate
21
+ **`offline_player_id`** (standard StatsBomb offline system); likewise
22
+ `live_team_id`/`offline_team_id` and `live_country_of_birth_id`/
23
+ `offline_country_of_birth_id`, and `live_match_id`/`offline_match_id`. Which ID
24
+ appears in a given feed depends on the system that produced it. This endpoint is
25
+ the authoritative crosswalk between the two.
26
+
27
+ Treat StatsBomb IDs as **(system, id)** pairs, not bare integers. A
28
+ `player_id` seen elsewhere is only unambiguous once you know whether it is a
29
+ live or offline id. See `identity-surfaces.md`.
30
+
31
+ ## Request parameters
32
+
33
+ No query parameters → no data returned. Filters narrow the licensed set:
34
+
35
+ | Parameter | Type | Description |
36
+ |---|---|---|
37
+ | `competition-id` | integer | Desired competition id |
38
+ | `season-id` | integer | Desired season id |
39
+ | `live-player-id` | integer | Player id from the StatsBomb Live system |
40
+ | `offline-player-id` | integer | Player id from the offline system |
41
+ | `match-date-from` | yyyy-mm-dd | Only competition-season-team blocks with matches on/after this date |
42
+ | `match-date-to` | yyyy-mm-dd | Only blocks with matches on/before this date (combine with `-from` for a window) |
43
+
44
+ Size/shape controls:
45
+
46
+ | Parameter | Type | Description |
47
+ |---|---|---|
48
+ | `all-account-data` | boolean | Must be `true` to return all player data on the account (otherwise trimmed, to protect trialling users) |
49
+ | `add-matches-played` | boolean | Must be `true` to include the `matches_played` array per block |
50
+
51
+ Constraints:
52
+ - `live-player-id` and `offline-player-id` are **mutually exclusive** — supply
53
+ at most one.
54
+ - If the query would return **more than 5000 records, the response is streamed
55
+ to a file** as JSON instead of being returned as the inline payload. Plan for
56
+ both delivery modes.
57
+ - Even when `match-date-from`/`-to` are set, `matches_played` (when requested)
58
+ still returns **all** matches in the competition-season-team block, not just
59
+ those in the date window.
60
+
61
+ Example — Jill Scott, 2020/21 FA WSL, with matches:
62
+
63
+ ```
64
+ https://data.statsbomb.com/api/v1/player-mapping?season-id=90&competition-id=37&offline-player-id=10172&add-matches-played=true
65
+ ```
66
+
67
+ ## Response
68
+
69
+ JSON array of player-mapping blocks. One block per
70
+ **{competition, season, team}** the player appeared for — so a mid-season
71
+ transfer yields multiple blocks for the same player.
72
+
73
+ | Field | Type | Description |
74
+ |---|---|---|
75
+ | `competition_id` | integer | Competition id (some StatsBomb documentation misspells the key as `competiton_id`; the JSON payload uses `competition_id`) |
76
+ | `competition_name` | string | Competition name |
77
+ | `season_id` / `season_name` | integer / string | Season |
78
+ | `offline_team_id` | integer | Team id (offline system) |
79
+ | `live_team_id` | integer | Team id (Live system) |
80
+ | `team_name` | string | Team name |
81
+ | `team_gender` | string | Gender of competitions played by the team |
82
+ | `earliest_match_date` | yyyy-mm-dd | Earliest match the player appeared in for this block |
83
+ | `most_recent_match_date` | yyyy-mm-dd | Most recent match in this block |
84
+ | `offline_country_of_birth_id` | integer | Country-of-birth id (offline system) |
85
+ | `live_country_of_birth_id` | integer | Country-of-birth id (Live system) |
86
+ | `country_of_birth_name` | string | Country of birth name |
87
+ | `offline_player_id` | integer | Player id (offline system) |
88
+ | `live_player_id` | integer | Player id (Live system) |
89
+ | `player_name` | string | Player name |
90
+ | `player_nickname` | string | Player nickname (nullable) |
91
+ | `player_height` | number | Height (cm) |
92
+ | `player_weight` | number | Weight (kg) |
93
+ | `player_birth_date` | yyyy-mm-dd | Date of birth |
94
+ | `player_preferred_foot` | string | Recognised preferred foot (some StatsBomb documentation misspells the key as `player_perferred_foot`; the JSON payload uses `player_preferred_foot`) |
95
+ | `matches_played` | array | Matches in this block (only if `add-matches-played=true`) |
96
+
97
+ `matches_played[]` entries:
98
+
99
+ | Field | Type | Description |
100
+ |---|---|---|
101
+ | `offline_match_id` | integer | Match id (offline system) |
102
+ | `live_match_id` | integer | Match id (Live system) |
103
+ | `match_date` | yyyy-mm-dd | Date the match was played |
104
+
105
+ ### Example response (abridged)
106
+
107
+ ```json
108
+ [ {
109
+ "competition_id": 37,
110
+ "competition_name": "FA Women's Super League",
111
+ "season_id": 90,
112
+ "season_name": "2020/2021",
113
+ "offline_team_id": 746,
114
+ "live_team_id": 389,
115
+ "team_name": "Manchester City WFC",
116
+ "team_gender": "female",
117
+ "earliest_match_date": "2020-09-05",
118
+ "most_recent_match_date": "2021-01-17",
119
+ "offline_country_of_birth_id": 68,
120
+ "live_country_of_birth_id": 2,
121
+ "country_of_birth_name": "England",
122
+ "offline_player_id": 10172,
123
+ "live_player_id": 32564,
124
+ "player_name": "Jill Scott",
125
+ "player_nickname": null,
126
+ "player_height": 181.0,
127
+ "player_weight": 68.0,
128
+ "player_birth_date": "1987-02-02",
129
+ "player_preferred_foot": "Right",
130
+ "matches_played": [
131
+ { "match_date": "2020-09-05", "live_match_id": 90335, "offline_match_id": 3764234 }
132
+ ]
133
+ } ]
134
+ ```
135
+
136
+ Note in the example how the **offline and live ids differ** for player
137
+ (10172 vs 32564), team (746 vs 389), country of birth (68 vs 2), and every
138
+ match — exactly the crosswalk this endpoint exists to provide.
139
+
140
+ ## Relevance to reep
141
+
142
+ reep is the entity register that answers "who is this player?" and holds
143
+ provider cross-references. This endpoint is the canonical StatsBomb-internal
144
+ crosswalk: a `custom_id` bridge to StatsBomb must record **which system** an id
145
+ belongs to (live vs offline) and can use this endpoint to reconcile the two.
146
+ Mapping only a bare StatsBomb player id without its system risks colliding live
147
+ and offline spaces. The block-per-{competition,season,team} shape also captures
148
+ transfer history within a season, useful as relationship evidence.