Get match stats
Get the team stats of a played match: possession, xG, shots, passes, duels, defending and goalkeeping. Every stat comes for the full match and for each half, split into home and away, so you can build a full stats panel or compare the two halves.
https://api.soccer-data.co/v1/matches/{match_id}/stats
- Returns 409 MATCH_IS_LIVE while the match is in play. Use the live stats endpoint until full-time.
- Returns 404 STATS_NOT_AVAILABLE when detailed stats were never collected for the match, and 404 NOT_FOUND when the match is unknown or its stats aren't in yet.
- A period with no recorded value is null, never 0. A real zero looks like {"home": 0, "away": 0}.
- expected_goals and np_expected_goals are null when the match has no xG. Check xg_available on the match first.
- Stat depth varies by competition. See the coverage docs before you rely on a stat.
The match's id, like match_…. Find one with the ID guide.
The match's id.
The headline numbers. Stats: ball_possession, expected_goals, big_chances, total_shots, shots_on_target, goalkeeper_saves, corner_kicks, fouls, yellow_cards, red_cards, passes, accurate_passes, tackles, free_kicks.
Shooting detail. Stats: total_shots, shots_on_target, shots_off_target, blocked_shots, shots_inside_box, shots_outside_box, hit_woodwork.
Attacking play. Stats: big_chances_missed, touches_in_penalty_area, fouled_in_final_third, offsides.
Passing. Stats: accurate_passes, throw_ins, accurate_crosses, accurate_long_balls, final_third_entries.
Duels and dribbling. Stats: duels_won_percentage, dispossessed, dribbles_percentage, ground_duels_percentage, aerial_duels_percentage.
Defending. Stats: tackles, tackles_won_percentage, interceptions, clearances, ball_recoveries.
Goalkeeping. Stats: saves, goal_kicks, goals_prevented, high_claims.
The value for the whole match. Null when it wasn't recorded.
The value for the first half. Null when it wasn't recorded.
The value for the second half. Null when it wasn't recorded.
Home team's value. ball_possession and the stats ending in _percentage are percentages.
Away team's value.
Non-penalty xG, with the same all, first_half and second_half blocks as the other stats. Null when the match has no non-penalty xG, not 0.
curl "https://api.soccer-data.co/v1/matches/match_9pd0ck6g2m9i/stats" \ -H "X-Api-Key: $SOCCER_DATA_KEY"
const res = await fetch("https://api.soccer-data.co/v1/matches/match_9pd0ck6g2m9i/stats", {
headers: { "X-Api-Key": process.env.SOCCER_DATA_KEY },
});
const { data } = await res.json();
import os, requests
res = requests.get(
"https://api.soccer-data.co/v1/matches/match_9pd0ck6g2m9i/stats",
headers={"X-Api-Key": os.environ["SOCCER_DATA_KEY"]},
)
data = res.json()["data"]
$data = Http::withHeaders(['X-Api-Key' => env('SOCCER_DATA_KEY')])
->get('https://api.soccer-data.co/v1/matches/match_9pd0ck6g2m9i/stats')
->json('data');
{
"data": {
"match_id": "match_9pd0ck6g2m9i",
"overview": {
"ball_possession": {
"all": {
"home": 44,
"away": 56
},
"first_half": {
"home": 46,
"away": 54
},
"second_half": {
"home": 42,
"away": 58
}
},
"expected_goals": {
"all": {
"home": 2.397,
"away": 1.572
},
"first_half": {
"home": 0.91,
"away": 0.48
},
"second_half": {
"home": 1.487,
"away": 1.092
}
},
"total_shots": {
"all": {
"home": 15,
"away": 13
},
"first_half": {
"home": 7,
"away": 5
},
"second_half": {
"home": 8,
"away": 8
}
}
},
"shots": {
"shots_on_target": {
"all": {
"home": 8,
"away": 5
},
"first_half": {
"home": 3,
"away": 1
},
"second_half": {
"home": 5,
"away": 4
}
}
},
"attack": {
"big_chances_missed": {
"all": {
"home": 2,
"away": 1
},
"first_half": {
"home": 1,
"away": 0
},
"second_half": {
"home": 1,
"away": 1
}
}
},
"passes": {
"accurate_passes": {
"all": {
"home": 352,
"away": 468
},
"first_half": {
"home": 181,
"away": 230
},
"second_half": {
"home": 171,
"away": 238
}
}
},
"duels": {
"duels_won_percentage": {
"all": {
"home": 52,
"away": 48
},
"first_half": {
"home": 54,
"away": 46
},
"second_half": {
"home": 50,
"away": 50
}
}
},
"defending": {
"tackles": {
"all": {
"home": 17,
"away": 14
},
"first_half": {
"home": 9,
"away": 6
},
"second_half": {
"home": 8,
"away": 8
}
}
},
"goalkeeping": {
"saves": {
"all": {
"home": 3,
"away": 4
},
"first_half": {
"home": 1,
"away": 2
},
"second_half": {
"home": 2,
"away": 2
}
}
},
"np_expected_goals": {
"all": {
"home": 2.397,
"away": 1.572
},
"first_half": {
"home": 0.91,
"away": 0.48
},
"second_half": {
"home": 1.487,
"away": 1.092
}
}
}
}
### GET /matches/{match_id}/stats
Get match stats
Get the team stats of a played match: possession, xG, shots, passes, duels, defending and goalkeeping. Every stat comes for the full match and for each half, split into home and away, so you can build a full stats panel or compare the two halves.
- Returns 409 MATCH_IS_LIVE while the match is in play. Use the live stats endpoint until full-time.
- Returns 404 STATS_NOT_AVAILABLE when detailed stats were never collected for the match, and 404 NOT_FOUND when the match is unknown or its stats aren't in yet.
- A period with no recorded value is null, never 0. A real zero looks like {"home": 0, "away": 0}.
- expected_goals and np_expected_goals are null when the match has no xG. Check xg_available on the match first.
- Stat depth varies by competition. See the coverage docs before you rely on a stat.
Response fields:
- `data.match_id` (string): The match's id.
- `data.overview.{stat}` (object): The headline numbers. Stats: ball_possession, expected_goals, big_chances, total_shots, shots_on_target, goalkeeper_saves, corner_kicks, fouls, yellow_cards, red_cards, passes, accurate_passes, tackles, free_kicks.
- `data.shots.{stat}` (object): Shooting detail. Stats: total_shots, shots_on_target, shots_off_target, blocked_shots, shots_inside_box, shots_outside_box, hit_woodwork.
- `data.attack.{stat}` (object): Attacking play. Stats: big_chances_missed, touches_in_penalty_area, fouled_in_final_third, offsides.
- `data.passes.{stat}` (object): Passing. Stats: accurate_passes, throw_ins, accurate_crosses, accurate_long_balls, final_third_entries.
- `data.duels.{stat}` (object): Duels and dribbling. Stats: duels_won_percentage, dispossessed, dribbles_percentage, ground_duels_percentage, aerial_duels_percentage.
- `data.defending.{stat}` (object): Defending. Stats: tackles, tackles_won_percentage, interceptions, clearances, ball_recoveries.
- `data.goalkeeping.{stat}` (object): Goalkeeping. Stats: saves, goal_kicks, goals_prevented, high_claims.
- `data.{group}.{stat}.all` (object|null): The value for the whole match. Null when it wasn't recorded.
- `data.{group}.{stat}.first_half` (object|null): The value for the first half. Null when it wasn't recorded.
- `data.{group}.{stat}.second_half` (object|null): The value for the second half. Null when it wasn't recorded.
- `data.{group}.{stat}.{period}.home` (number): Home team's value. ball_possession and the stats ending in _percentage are percentages.
- `data.{group}.{stat}.{period}.away` (number): Away team's value.
- `data.np_expected_goals` (object|null): Non-penalty xG, with the same all, first_half and second_half blocks as the other stats. Null when the match has no non-penalty xG, not 0.
Example: curl "https://api.soccer-data.co/v1/matches/match_9pd0ck6g2m9i/stats" -H "X-Api-Key: $SOCCER_DATA_KEY"