Summary
Get a comprehensive game summary with statistics, possession breakdown, and player metrics.
Performance Note
This endpoint performs real-time aggregation and may take several seconds to respond. Results are deterministic for a given analysis — we recommend caching the response on your end to avoid repeated computation.
Request
GET /analyses/{id}/summary
Response
{
"metadata": {
"game_id": "2025-01-15_hub-1246",
"game_date": "2025-01-15",
"version": "0.4.98",
"generated_at": "2025-01-20T14:30:00.000Z",
"video_length_sec": 5425.5
},
"teams": {
"team_0_name": "Team A",
"team_1_name": "Team B"
},
"match_stats": {
"event_counts": {
"team_possession": 245,
"player_possession": 1830,
"scene": 12,
"match_timeline": 1
},
"total_durations_sec": {
"team_possession": 5280.5,
"player_possession": 4920.3,
"scene": 5400.0,
"match_timeline": 5400.0
},
"analysable_duration_sec": 5320.0,
"non_analysable_duration_sec": 80.0
},
"possession": {
"summary": {
"team_0": { "seconds": 2750.5, "pct": 52.1 },
"team_1": { "seconds": 2120.0, "pct": 40.2 },
"unknown": { "seconds": 410.0, "pct": 7.7 }
},
"per_minute": [
{ "minute": 0, "team_0_pct": 58.67, "team_1_pct": 33.5, "unknown_pct": 7.83 },
{ "minute": 1, "team_0_pct": 47.5, "team_1_pct": 52.0, "unknown_pct": 0.5 },
{ "minute": 2, "team_0_pct": 61.2, "team_1_pct": 38.8, "unknown_pct": 0.0 }
]
},
"players": [
{
"player_id": "0-10",
"team_id": "team_0",
"jersey_number": 10,
"name": "Team A #10",
"stats": {
"total_distance_m": 10542.5,
"distance_by_speed_bucket": {
"walking_m": 3200.0,
"jogging_m": 4500.0,
"running_m": 2200.0,
"sprinting_m": 642.5
},
"avg_speed_kmh": 7.2,
"max_speed_kmh": 32.1,
"tracking_duration_sec": 5280.0,
"ball_actions": {
"passes": 12,
"drives": 8,
"shots": 2
}
}
},
{
"player_id": "1-9",
"team_id": "team_1",
"jersey_number": 9,
"name": "Team B #9",
"stats": {
"total_distance_m": 9876.32,
"distance_by_speed_bucket": {
"walking_m": 2800.0,
"jogging_m": 4200.0,
"running_m": 2100.0,
"sprinting_m": 776.32
},
"avg_speed_kmh": 6.9,
"max_speed_kmh": 30.5,
"tracking_duration_sec": 5100.0,
"ball_actions": {
"passes": 12,
"drives": 8,
"shots": 2
}
}
}
]
}
Response Structure
The response is organized into logical groups:
| Section | Description |
|---|---|
metadata |
Game identification and processing info |
teams |
Team names and identifiers |
match_stats |
Event counts, durations, analysable time |
possession |
Overall and per-minute possession breakdown |
players |
Complete player list with embedded stats |
Metadata
| Field | Type | Description |
|---|---|---|
game_id |
string | Internal game identifier (format: YYYY-MM-DD_hub-XXX) |
game_date |
string | ISO date extracted from game_id (e.g., "2025-01-15") |
version |
string | Processing pipeline version |
generated_at |
string | ISO timestamp when this response was generated |
video_length_sec |
float | Total video duration in seconds |
Teams
| Field | Type | Description |
|---|---|---|
team_0_name |
string | Name of team that started on the left side |
team_1_name |
string | Name of team that started on the right side |
Match Stats
| Field | Type | Description |
|---|---|---|
event_counts |
object | Number of detected events by type |
total_durations_sec |
object | Total seconds covered per event type |
analysable_duration_sec |
float | Duration of actual gameplay (seconds) |
non_analysable_duration_sec |
float | Duration of replays, graphics, etc. (seconds) |
All numeric values are rounded to 2 decimal places.
Possession
Summary
Overall possession breakdown for the entire game:
| Field | Type | Description |
|---|---|---|
team_0 |
object | { seconds, pct } for team 0 |
team_1 |
object | { seconds, pct } for team 1 |
unknown |
object | { seconds, pct } for unknown possession |
Per-Minute Breakdown
Array of possession percentages for each minute:
| Field | Type | Description |
|---|---|---|
minute |
int | Game minute (0, 1, 2, ...) |
team_0_pct |
float | Possession percentage for team 0 |
team_1_pct |
float | Possession percentage for team 1 |
unknown_pct |
float | Unknown possession percentage |
About unknown Possession
The unknown category represents periods where possession cannot be confidently determined. This includes:
- Ball in air - During high crosses, long balls, or aerial duels
- Contested situations - When multiple players are challenging for the ball
- Transition moments - Brief moments between possession changes
- Tracking gaps - When ball tracking confidence is below threshold
A typical match has 5-15% unknown possession. Higher values may indicate challenging camera angles or fast-paced play.
See Possession Concepts for more details.
Players
Array of player objects, each containing complete player info with embedded stats:
Player Object
| Field | Type | Description |
|---|---|---|
player_id |
string | Unique identifier (e.g., "0-10") |
team_id |
string | Team identifier: "team_0" or "team_1" |
jersey_number |
int | Player's jersey number |
name |
string | Display name (e.g., "Team A #10") |
stats |
object | Player statistics (see below) |
Stats Object
| Field | Type | Unit | Description |
|---|---|---|---|
total_distance_m |
float | meters | Total distance traveled |
distance_by_speed_bucket |
object | meters | Distance per speed category |
avg_speed_kmh |
float | km/h | Average speed |
max_speed_kmh |
float | km/h | Maximum recorded speed |
tracking_duration_sec |
float | seconds | Duration player was tracked |
ball_actions |
object | — | Ball action counts (see below) |
Ball Action Counts
| Field | Type | Description |
|---|---|---|
passes |
integer | Number of passes |
drives |
integer | Number of drives (dribbles) |
shots |
integer | Number of shots |
Distance by Speed Bucket
| Field | Type | Speed Range | Description |
|---|---|---|---|
walking_m |
float | 0-7 km/h | Distance at walking pace |
jogging_m |
float | 7-14 km/h | Distance at jogging pace |
running_m |
float | 14-21 km/h | Distance at running pace |
sprinting_m |
float | 21+ km/h | Distance at sprinting pace |
All distance values are in meters. All numeric values are rounded to 2 decimal places.
See Speed & Distance for speed bucket definitions.
Use Cases
Display Possession Chart
const { possession } = await fetchSummary(analysisId);
// For a stacked bar chart (already sorted by minute)
const chartData = possession.per_minute.map(pm => ({
minute: pm.minute,
team0: pm.team_0_pct,
team1: pm.team_1_pct
}));
Player Distance Leaderboard
summary = requests.get(f'/api/v1/analyses/{id}/summary', headers=headers).json()
# Sort players by distance
top_runners = sorted(
summary['players'],
key=lambda p: p['stats']['total_distance_m'],
reverse=True
)[:5]
for player in top_runners:
km = player['stats']['total_distance_m'] / 1000
print(f"{player['name']}: {km:.1f} km")
Sprint Analysis
# Find players with most sprinting distance
sprinters = sorted(
summary['players'],
key=lambda p: p['stats']['distance_by_speed_bucket']['sprinting_m'],
reverse=True
)
for p in sprinters[:3]:
sprint_m = p['stats']['distance_by_speed_bucket']['sprinting_m']
total_m = p['stats']['total_distance_m']
sprint_pct = (sprint_m / total_m * 100) if total_m > 0 else 0
print(f"{p['name']}: {sprint_pct:.1f}% sprinting")
Filter by Team
# Get only team_0 players
team_0_players = [p for p in summary['players'] if p['team_id'] == 'team_0']
# Team totals
total_distance = sum(p['stats']['total_distance_m'] for p in team_0_players)
print(f"Team 0 total distance: {total_distance/1000:.1f} km")
Example
curl -X GET "https://aiontheball.nl/api/v1/analyses/1246/summary" \
-H "Authorization: Bearer YOUR_API_TOKEN"
import requests
response = requests.get(
'https://aiontheball.nl/api/v1/analyses/1246/summary',
headers={'Authorization': f'Bearer {token}'}
)
summary = response.json()
# Access grouped data
print(f"Game: {summary['metadata']['game_id']}")
print(f"Date: {summary['metadata']['game_date']}")
print(f"Teams: {summary['teams']['team_0_name']} vs {summary['teams']['team_1_name']}")
print(f"Possession: {summary['possession']['summary']['team_0']['pct']}% vs {summary['possession']['summary']['team_1']['pct']}%")
print(f"Players: {len(summary['players'])}")
const response = await fetch('https://aiontheball.nl/api/v1/analyses/1246/summary', {
headers: { 'Authorization': `Bearer ${token}` }
});
const summary = await response.json();
// Destructure grouped data
const { metadata, teams, possession, players } = summary;
console.log(`Game: ${metadata.game_id} (${metadata.game_date})`);
console.log(`${teams.team_0_name}: ${possession.summary.team_0.pct}%`);
console.log(`${teams.team_1_name}: ${possession.summary.team_1.pct}%`);