Skip to content

Download Tracking

Download raw player and ball tracking data.

Performance Note

This endpoint streams large files and may take several seconds to respond. Results are deterministic for a given analysis — we recommend caching the downloaded file on your end to avoid repeated transfers.

Request

GET /analyses/{id}/tracking/download?format=parquet

Query Parameters

Parameter Type Default Options Description
format string parquet parquet, json Output format

Response

Returns a file download:

  • Parquet: Binary file, ~20-50 MB (recommended)
  • JSON: Text file, ~200-500 MB

Data Schema

Column Type Description
timestamp int32 Time in milliseconds
role string player, goal_keeper, ball, referee
player_id string Player identifier (e.g., "0-10") or null
player_id_conf float16 Confidence of player identification (0-1)
x int16 X position in centimeters
y int16 Y position in centimeters
bbox_x int16 Pixel X location of player in the video. Center of the player bounding box
bbox_y int16 Pixel Y location of player in the video. Bottom of the player bounding box

Sample Data

timestamp  role        player_id  x      y
3309680    player      0-4        6606   3256
3309680    player      0-10       4520   4100
3309680    ball        null       5200   3400
3309720    player      0-4        6610   3259

Understanding the Data

Coordinate System

  • Origin (0,0) is bottom-left corner of pitch
  • X: 0 to 10500 (centimeters) = 0 to 105 meters, left to right
  • Y: 0 to 6800 (centimeters) = 0 to 68 meters, bottom to top

See Pitch Coordinates for details.

Frame Rate

Data is recorded at 25 FPS (frames per second):

  • Timestamps increment by 40ms between frames
  • 1 second = 25 data points per tracked entity

Player Identification

  • player_id: Assigned when jersey is detected with confidence
  • player_id_conf: Higher = more certain identification
  • null player_id: Player detected but jersey not readable

Working with the Data

Python (Parquet)

import pandas as pd

# Load tracking data
df = pd.read_parquet('tracking.parquet')

# Filter to specific player
player_10 = df[df['player_id'] == '0-10']

# Convert to meters
player_10['x_m'] = player_10['x'] / 100
player_10['y_m'] = player_10['y'] / 100

# Calculate distance traveled
player_10 = player_10.sort_values('timestamp')
player_10['dx'] = player_10['x_m'].diff()
player_10['dy'] = player_10['y_m'].diff()
player_10['dist'] = (player_10['dx']**2 + player_10['dy']**2)**0.5

total_distance = player_10['dist'].sum()
print(f"Player 0-10 traveled {total_distance:.0f} meters")

JavaScript (JSON)

// Note: JSON files are large, consider streaming
const response = await fetch(
  `/api/v1/analyses/${id}/tracking/download?format=json`,
  { headers }
);
const tracking = await response.json();

// Group by timestamp for frame-by-frame analysis
const frames = {};
tracking.forEach(row => {
  if (!frames[row.timestamp]) frames[row.timestamp] = [];
  frames[row.timestamp].push(row);
});

Format Comparison

Aspect Parquet JSON
File size 20-50 MB 200-500 MB
Load time Fast Slow
Streaming No Yes
Language support Python, R, Spark Universal
Recommended for Analysis Web apps

Example

curl -X GET "https://aiontheball.nl/api/v1/analyses/1246/tracking/download?format=parquet" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -o tracking.parquet
curl -X GET "https://aiontheball.nl/api/v1/analyses/1246/tracking/download?format=json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -o tracking.json
import requests
import pandas as pd
from io import BytesIO

response = requests.get(
    'https://aiontheball.nl/api/v1/analyses/1246/tracking/download',
    headers={'Authorization': f'Bearer {token}'},
    params={'format': 'parquet'}
)

df = pd.read_parquet(BytesIO(response.content))
print(f"Loaded {len(df)} tracking points")

Large Files

Tracking files can be large. For web applications, consider:

  • Using the Summary endpoint for aggregated stats
  • Streaming JSON responses
  • Server-side processing with Parquet