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.
- package/README.md +22 -6
- package/bin/serve.js +2 -2
- package/data/docs.db +0 -0
- package/docs/fotmob/identity-surfaces.md +62 -0
- package/docs/impect/identity-surfaces.md +61 -0
- package/docs/opta/identity-surfaces.md +71 -0
- package/docs/skillcorner/identity-surfaces.md +60 -0
- package/docs/soccerdonna/identity-surfaces.md +66 -0
- package/docs/sportmonks/identity-surfaces.md +65 -0
- package/docs/statsbomb/api-access.md +41 -14
- package/docs/statsbomb/api-endpoints.md +120 -0
- package/docs/statsbomb/data-model.md +54 -11
- package/docs/statsbomb/event-types.md +42 -1
- package/docs/statsbomb/identity-surfaces.md +81 -0
- package/docs/statsbomb/iq-metrics-glossary.md +223 -0
- package/docs/statsbomb/player-mapping.md +148 -0
- package/docs/statsbomb/player-match-stats.md +245 -0
- package/docs/statsbomb/player-season-stats.md +269 -0
- package/docs/statsbomb/team-match-stats.md +217 -0
- package/docs/statsbomb/team-season-stats.md +213 -0
- package/docs/statsbomb/xg-model.md +33 -3
- package/docs/transfermarkt/identity-surfaces.md +69 -0
- package/docs/wyscout/identity-surfaces.md +64 -0
- package/package.json +17 -6
- package/providers.json +45 -0
|
@@ -98,9 +98,49 @@ File: `matches/{competition_id}/{season_id}.json`
|
|
|
98
98
|
|
|
99
99
|
### Data Quality Flags
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
|
323
|
-
|
|
324
|
-
| `
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
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 |
|
|
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.
|