football-docs 0.3.1 → 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.
package/data/docs.db CHANGED
Binary file
@@ -172,32 +172,59 @@ The nested JSON objects (pass, shot, carry, etc.) are flattened with underscores
172
172
  ## 3. Commercial REST API
173
173
 
174
174
  **Access**: Requires a paid license from StatsBomb (contact sales@statsbomb.com)
175
- **Base URL**: `https://data.statsbomb.com/api/v2/`
176
175
 
177
176
  ### Authentication
178
177
 
179
- HTTP Basic Auth with username (email) and password provided by StatsBomb.
178
+ HTTP Basic Auth with username (email) and password provided by StatsBomb. The
179
+ same credentials work across every endpoint.
180
180
 
181
181
  ### Endpoints
182
182
 
183
- | Endpoint | Description |
184
- |----------|-------------|
185
- | `GET /competitions` | List all licensed competitions |
186
- | `GET /competitions/{comp_id}/seasons/{season_id}/matches` | Matches for a competition/season |
187
- | `GET /matches/{match_id}/events` | Events for a match |
188
- | `GET /matches/{match_id}/lineups` | Lineups for a match |
189
- | `GET /matches/{match_id}/360-frames` | 360 freeze frames for a match |
183
+ There is **no single base URL or global API version**. Each resource is
184
+ independently versioned and the API spans **two hostnames**
185
+ (`data.statsbombservices.com` and `data.statsbomb.com`). The full host/version
186
+ matrix, query parameters, and caveats (including a host typo in StatsBomb's own
187
+ Team Stats spec) are documented in **`api-endpoints.md`**. Summary:
188
+
189
+ | Resource | Path (see api-endpoints.md for host + version) |
190
+ |----------|-----------------------------------------------|
191
+ | Competitions | `/api/v4/competitions` |
192
+ | Matches | `/api/v6/competitions/{cid}/seasons/{sid}/matches` |
193
+ | Lineups | `/api/v4/lineups/{mid}` |
194
+ | Events | `/api/v8/events/{mid}` |
195
+ | 360 Frames | `/api/v2/360-frames/{mid}` |
196
+ | Player Mapping | `/api/v1/player-mapping?<params>` |
197
+ | Player Match / Season Stats | `/api/v5/matches/{mid}/player-stats`, `/api/v4/competitions/{cid}/seasons/{sid}/player-stats` |
198
+ | Team Match / Season Stats | `/api/v1/matches/{mid}/team-stats`, `/api/v2/competitions/{cid}/seasons/{sid}/team-stats` |
190
199
 
191
200
  ### Response Format
192
201
 
193
- The commercial API returns the same JSON structure as the open data files. The only differences are:
194
- - More competitions and seasons available
195
- - Data may be more current (open data can lag behind)
196
- - Some fields may be available earlier in the commercial feed
202
+ For competitions, matches, lineups, events, and 360 frames the commercial API
203
+ returns the same JSON structure as the open data files (more competitions,
204
+ fresher data). The **stats endpoints and player-mapping have no open-data
205
+ equivalent** see the parity table below and the dedicated docs
206
+ (`player-match-stats.md`, `player-season-stats.md`, `team-match-stats.md`,
207
+ `team-season-stats.md`, `player-mapping.md`, `iq-metrics-glossary.md`).
208
+
209
+ ### Open Data vs Commercial parity
210
+
211
+ | Capability | Open Data | Commercial API |
212
+ |---|---|---|
213
+ | Competitions / Matches / Lineups / Events / 360 | Yes (selective comps) | Yes (licensed scope) |
214
+ | Player & Team Match/Season Stats (IQ metrics) | **No** | Yes |
215
+ | Player Mapping (live/offline IDs) | **No** | Yes |
216
+ | Freshness | Irregular GitHub updates | Near-live for licensed comps |
217
+
218
+ Code written against open data cannot read OBV, xGChain, PPDA, PSxG, the IQ
219
+ metric catalogues, or live/offline IDs — these exist only in the commercial
220
+ feed.
197
221
 
198
222
  ### Rate Limits
199
223
 
200
- The commercial API has rate limits that vary by license tier. StatsBomb recommends caching responses locally and using bulk endpoints where possible.
224
+ The commercial API has rate limits that vary by license tier. StatsBomb
225
+ recommends caching responses locally and polling the Competitions/Matches
226
+ `*_updated` / `last_updated` timestamps to refetch only changed data (see
227
+ `api-endpoints.md` → Incremental sync).
201
228
 
202
229
  ---
203
230
 
@@ -0,0 +1,120 @@
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 Commercial REST API Endpoints
9
+
10
+ Reference for the StatsBomb commercial REST API surface. Each resource is
11
+ **independently versioned** and the API spans **two hostnames** — there is no
12
+ single global API version or base path.
13
+
14
+ > This page describes these endpoint versions: Competitions v4.0.0, Matches
15
+ > v6.0.0, Lineups v4.0.1, Events v8.0.0, 360 Frames v2.0.0, Player Mapping
16
+ > v1.0.0, Player Match Stats v5.0.0, Player Season Stats v4.0.0, Team Match
17
+ > Stats v1.0.0, Team Season Stats v2.0.0. StatsBomb increments the version
18
+ > segment per resource when the response shape changes, so the URL itself
19
+ > tells you which version a feed is; a higher version than listed here may
20
+ > carry additional fields not described on this page.
21
+
22
+ ## Authentication
23
+
24
+ All endpoints use **HTTP Basic Auth** with the username (email) and password
25
+ issued by StatsBomb. The same credentials work across every endpoint. Access
26
+ requires a paid licence; licensed scope determines which competitions/seasons
27
+ return data.
28
+
29
+ `statsbombpy` and `StatsBombR` wrap these endpoints. With `statsbombpy`, set
30
+ `SB_USERNAME`/`SB_PASSWORD` env vars or pass `creds={"user":..., "passwd":...}`.
31
+
32
+ ## Endpoint matrix
33
+
34
+ `{cid}` = competition_id, `{sid}` = season_id, `{mid}` = match_id.
35
+
36
+ | Resource | Method + path | Host | Spec version |
37
+ |---|---|---|---|
38
+ | Competitions | `GET /api/v4/competitions` | `data.statsbombservices.com` | v4.0.0 |
39
+ | Matches | `GET /api/v6/competitions/{cid}/seasons/{sid}/matches` | `data.statsbombservices.com` | v6.0.0 |
40
+ | Lineups | `GET /api/v4/lineups/{mid}` | `data.statsbomb.com` | v4.0.1 |
41
+ | Events | `GET /api/v8/events/{mid}` | `data.statsbombservices.com` | v8.0.0 |
42
+ | 360 Frames | `GET /api/v2/360-frames/{mid}` | `data.statsbombservices.com` | v2.0.0 |
43
+ | Player Mapping | `GET /api/v1/player-mapping?<params>` | `data.statsbomb.com` | v1.0.0 |
44
+ | Player Match Stats | `GET /api/v5/matches/{mid}/player-stats` | `data.statsbombservices.com` | v5.0.0 |
45
+ | Player Season Stats | `GET /api/v4/competitions/{cid}/seasons/{sid}/player-stats` | `data.statsbombservices.com` | v4.0.0 |
46
+ | Team Match Stats | `GET /api/v1/matches/{mid}/team-stats` | `data.statsbomb.com` | v1.0.0 |
47
+ | Team Season Stats | `GET /api/v2/competitions/{cid}/seasons/{sid}/team-stats` | `data.statsbombservices.com` | v2.0.0 |
48
+
49
+ Older versions of a resource are generally reachable by lowering the version
50
+ segment (e.g. `/api/v7/events/{mid}`), subject to StatsBomb retaining them.
51
+
52
+ ### Host and typo caveats
53
+
54
+ - **Two active hosts.** Most resources are on `data.statsbombservices.com`;
55
+ Lineups and Player Mapping are documented on `data.statsbomb.com`. The hosts
56
+ are not interchangeable in the specs — use the one documented per resource and
57
+ verify against live behaviour.
58
+ - **Team Match Stats typo.** The Team Match Stats v1.0.0 PDF prints the host as
59
+ `data.statsbom.com` (missing a `b`). This is a documentation typo; the
60
+ intended host is almost certainly `data.statsbomb.com`. Treat with caution and
61
+ confirm against StatsBomb support.
62
+
63
+ ## Response format
64
+
65
+ Every endpoint returns a JSON **array** of objects. The shape mirrors the
66
+ StatsBomb Open Data JSON for the entities that exist in open data
67
+ (competitions, matches, lineups, events, 360-frames). The four stats endpoints
68
+ and player-mapping have no open-data equivalent.
69
+
70
+ | Resource | Array element | Documented in |
71
+ |---|---|---|
72
+ | Competitions | competition-season object | `data-model.md` |
73
+ | Matches | match object (incl. `collection_status`, `metadata`) | `data-model.md` |
74
+ | Lineups | per-team lineup (lineup/formations/events arrays) | `data-model.md` |
75
+ | Events | event object (v8 fields incl. OBV, pass clusters) | `event-types.md` |
76
+ | 360 Frames | freeze-frame object per event_uuid | `data-model.md`, `coordinate-system.md` |
77
+ | Player Mapping | competition-season-team block per player | `player-mapping.md` |
78
+ | Player Match/Season Stats | one row per player | `player-match-stats.md`, `player-season-stats.md` |
79
+ | Team Match/Season Stats | one row per team | `team-match-stats.md`, `team-season-stats.md` |
80
+
81
+ ## Open Data vs commercial parity
82
+
83
+ The free Open Data repository (`github.com/statsbomb/open-data`) mirrors only a
84
+ subset of the commercial API:
85
+
86
+ | Capability | Open Data | Commercial API |
87
+ |---|---|---|
88
+ | Competitions / Matches / Lineups / Events / 360 | Yes (selective competitions) | Yes (licensed scope) |
89
+ | Player Match Stats | **No** | Yes (`/matches/{mid}/player-stats`) |
90
+ | Player Season Stats | **No** | Yes (`/competitions/{cid}/seasons/{sid}/player-stats`) |
91
+ | Team Match Stats | **No** | Yes (`/matches/{mid}/team-stats`) |
92
+ | Team Season Stats | **No** | Yes (`/competitions/{cid}/seasons/{sid}/team-stats`) |
93
+ | Player Mapping (live/offline IDs) | **No** | Yes (`/player-mapping`) |
94
+ | Data freshness | Irregular GitHub updates | Near-live for licensed comps |
95
+
96
+ The pre-computed IQ metric catalogues (OBV, xGChain, PPDA, PSxG, GSAA, etc.)
97
+ and the live/offline ID mapping **only exist in the commercial feed**. Code
98
+ written against open data cannot read these fields — do not assume their
99
+ presence from open-data examples.
100
+
101
+ ## Incremental sync
102
+
103
+ The Competitions response carries `match_updated`, `match_updated_360`,
104
+ `match_available`, and `match_available_360` timestamps per competition-season;
105
+ the Matches response carries `last_updated` / `last_updated_360` per match.
106
+ Poll Competitions, diff the timestamps, then refetch only changed
107
+ competition-seasons/matches rather than re-pulling everything.
108
+
109
+ `match_status` must be `"available"` before Events can be fetched for a match;
110
+ `match_status_360` of `"available"` is required before 360 frames exist. See the
111
+ collection/match status enums in `data-model.md`.
112
+
113
+ ## Player Mapping request rules
114
+
115
+ `/api/v1/player-mapping` requires at least one query parameter (no params = no
116
+ data). `all-account-data=true` is required to return the full licensed set
117
+ (otherwise the response is trimmed for trialling). If a query would return
118
+ **more than 5000 records the response is streamed to a file** as JSON rather
119
+ than returned inline. See `player-mapping.md` for parameters and the
120
+ live/offline ID model.
@@ -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
 
@@ -37,6 +37,22 @@ StatsBomb Open Data exposes numeric `competition_id`, `season_id`, `match_id`,
37
37
  inside the provider dataset but should stay provider-scoped. Do not infer global
38
38
  identity from a bare number without provider and dataset context.
39
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
+
40
56
  ## Useful Matching Fields
41
57
 
42
58
  - Competitions and seasons: IDs, names, country, gender, and season label.
@@ -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.