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 confidenceplayer_id_conf: Higher = more certain identificationnullplayer_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