Skip to content

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}%`);