Changelog
Notable changes to API v1, newest first.
[1.26.0] - 2026-10
Faster running and top speed read closer to the truth.
Changed
- Speeds come from positions that keep more of each acceleration, so top speed reads about 5% low instead of 10%, and distance at 21 km/h and above is no longer about a quarter low.
- Every estimate (
distance_m_est, thedistance_bandsestimates,sprints_est,sprint_distance_m_est, the Summarytotal_distance_m_est, the team report total) projects the untracked minutes at each speed band's own pace instead of the tracked pace, because a player is tracked most while play is near him. Broadcast jogging no longer reads about a quarter high. - Sprint estimate factors re-fitted and set per footage:
params.sprint_m_per_high_speed_m0.52 to 0.39 (broadcast) / 0.34 (non-broadcast),params.sprints_per_high_speed_m0.026 to 0.019 / 0.017. Analyses without a footage class use the broadcast values. ball_out_of_play_sec(Summary, Team Report) counts only dead-ball time inside the halves; half-time and pre-match footage no longer count. Typical error 6% to 4% on broadcast, 27% to 19% on non-broadcast.- Analyses pick up the new speeds when re-aggregated; the new estimates apply to every analysis on its next report build.
[1.25.0] - 2026-10
Covered minutes stop at the final whistle.
Changed
minutes_covered, and every estimate projected over it (distance_m_est, thedistance_bandsestimates,sprints_est,sprint_distance_m_est), counts only time inside the two halves. On non-broadcast footage it read about a fifth high from pre-match, half-time and post-match footage; now about 5%. Estimated distance there: typical error 11% to 8%.- Match possession
pct(Summary, Team Report) is calibrated toward 50/50: the raw split ran about 2 points wide on the side ahead. Typical error on ground truth 2.6 to 1.4 points on broadcast, 3.2 to 1.8 on non-broadcast.secondsandper_minuteare unchanged. - Team Report
territorycounts in-play time only and is calibrated per third: it read the defensive third about 10 points high and the attacking third 10 low. Typical error on broadcast ground truth 10 to about 1 point per third. - Sprint estimate factors re-fitted on the new window:
params.sprint_m_per_high_speed_m0.47 to 0.52,params.sprints_per_high_speed_m0.023 to 0.026.
Added
- Player Report
coverage.seconds_in_halves: detected plus projected seconds inside the halves. Null when the analysis has no detected halves;minutes_coveredthen keeps its old meaning.
[1.24.0] - 2026-10
Sprints and covered minutes on the Summary, so a squad compares from one call.
Added
- Summary
players[].statsgainsminutes_covered,sprint_count,sprint_distance_m,sprints_estandsprint_distance_m_est. Each is the same number as the Player Report field of the same name.
Unchanged
distance_by_speed_bucket.sprinting_mis still the distance at 21 km/h and above, not sprint distance.
[1.23.0] - 2026-10
Sprint estimates on the same footing as the distance estimate, and published accuracy per footage type.
Added
- Player Report
physical.sprints_estandphysical.sprint_distance_m_est: sprints over the player's covered minutes, estimated from the high-speed distance. Measured sprints count about a fifth of the real ones; the estimates are right on average on broadcast footage (about 30% per player). Factors inparams. - An accuracy table for every physical number, broadcast and non-broadcast.
[1.22.0] - 2026-10
Sprint distance that matches the sprint count.
Added
- Player Report
physical.sprint_distance_mandsprints[].distance_m: the metres covered inside counted sprints.0.0when a player has no sprints. params.sprint_exit_kmh(19.8): a sprint now ends when the speed drops below it, not at the first stride under 25.2 km/h.
Changed
- A sprint whose speed dips briefly under 25.2 km/h stays one sprint, so players get more sprints and fewer sub-second pieces that never counted.
[1.21.3] - 2026-10
Player pixel coordinates stay on the event's player.
Changed
pixel_coordsfollow the player only while the tracking around the event is continuous. They stop where the player leaves the view or the tracking jumps to another person, sot0can be later than the intervalstart.- An event whose player is unknown, or not tracked at the event, returns
pixel_coordsthat hold the player's position at the event for 1 s. It returned null.
[1.21.2] - 2026-10
Interval fixes on Query Intervals and a team id fix on the oldest analyses.
Fixed
ball_actionandevent_propertyrows on analyses from the first engine releases carryteam_idasteam_0orteam_1. They returnedteam_0.0andteam_1.0.- A row that starts after the video end returns a zero-length interval at the video end. It returned an
endbefore itsstart. - Rows with the same
startandendcome back in a fixed order: bytype,label,player_id, thenteam_id. The order varied between calls.
[1.21.1] - 2026-10
Numbers in the event property in constraint.
Changed
inon anevent_propertyconstraint accepts numbers and booleans, e.g.{"field": "team_label", "in": [0, 1]}. A list that mixes types returns422.
[1.21.0] - 2026-10
The JSON tracking download is gone.
Removed
format=jsonon Download Tracking returns410. Useformat=cleanto draw the match andformat=parquetto analyse it.
[1.20.0] - 2026-10
Event properties on the event list.
Added
include=propertieson Events: every row gainsproperties, the values of each property Schema lists for its type, andevent_status.
Unchanged
GET /analyses/{id}/eventswithoutincludereturns the same rows and fields as before.
[1.19.0] - 2026-10
Three filters for possession changes, zone entries and progressive passes.
Added
possession_change: the moments a team won or lost the ball, by open play or restart and by third of the pitch.zone_entry: passes and carries into the final third or the opponent penalty box.progressive_pass: passes that moved the ball toward goal, by the progressive carry rule.
[1.18.1] - 2026-10
Docs correction. The API is unchanged; these pages now describe what it returns.
Fixed
- Times in Events, Query Intervals, the reports and Download Tracking count from video start, not match start.
- Rate limits are per account on
POST /videos(5 per minute, 200 per day) andPOST /videos/{id}/analysis(10 per 5 minutes, 300 per week). Other endpoints are not rate limited. - Errors raised by the hub carry
message, including 401, 403, 404 and the 504 proxy timeout. Errors raised by insight carrydetail. A result requested before the analysis is done returns503, not400. match_timelineemitsfirst_half,second_halfandmatchwhen the engine locates the halves, not onlyfull_game.passandcarryare spans withendafterstart, not point events.team_labelongoalandshotis the scoring and shooting team, andteam_idfollows it.- Report examples show
schema_version5andparams.est_seconds_floor. - The tracking parquet has a
teamcolumn, andx/ycan be null.format=jsoncan time out with504. analysis_idin webhooks is an integer. Goalkeepers are always{team}-GK.- Videos carry no
analyseslist and analyses nocreated_at.DELETE /videos/{id}returns409while an analysis on the video runs.
[1.18.0] - 2026-10
Every team-level row carries team_id, so a client never has to match a team by its display name. Schema marks experimental event types and properties an analysis never fills.
Added
team_idon every Events row: the actor's team on player events, the credited team onteam_possessionandgoal, null otherwise.labelis unchanged.team_possessionandplayer_possessionrows from Query Intervals carryplayer_id,team_idandteam_name, the same shape as theball_actionrows.statusper event type on Schema:experimentalwhen the analysis's quality record for that type is flagged unreliable, elsestable.availableper property on Schema:falsewhen the analysis never fills it (null orunknownon every event of the type). The event pages markpass_resultonpassandbody_partonshotas not currently populated.
Changed
- Distance ignores tracking jumps above 10 m/s, the rule top speed already used. Clean matches move by under 1 %.
- A player's full-game distance estimate, per-minute rate and average speed are null when they are physically implausible (above 150 m/min, or more than 30 % sprinting), and a keeper's estimate is null because keepers are mostly seen near play.
physical_withheldgives the reason; measured distance and top speed stay. See Speed & distance. - Report
schema_versionis now5.
[1.17.0] - 2026-09
Possession is a share of in-play time, and the two teams sum to 100. Goals and team possessions from the Event Property filter carry their team.
Changed
possessionon the Summary and the Team Report splits only in-play time credited to a team. On one match 35 / 39 / 26 unknown becomes 47 / 53.- The
unknownbucket, theunknown_pctper-minute field and the Team Reportteam: nullrow are removed.ball_out_of_play_secandunattributed_in_play_secreport the time left out. See Possession. - Report
schema_versionis now4. Refresh caches keyed on it. - The
team_possessionevents are unchanged. teamson the Event Property filter now matches events without a player (goal,team_possession) byteam_label. It returned nothing for them. Goals with an unknown team are excluded whenteamsis set.- Those rows now carry
team_idandteam_name, withplayer_idnull. A goal whose team the engine could not tell has both null.
[1.16.0] - 2026-09
A drive event marks the carries of at least 3 m, with progressive and take-on flags. drive no longer means carry.
Added
- The
driveevent: acarryof at least 3 m, with the carry's span, actor and properties plusprogressiveandtake_on. Returned by Events, Query Intervals and the Summary event histograms, and queryable with the Event Property filter. Available on analyses from engine version0.5.45. on_ball.driveson the Player Report, andparams.drive_min_length_mandparams.take_on_max_opp_dist_mon both reports.
Changed
driveas aball_actionfilter action now returns drive rows labelleddrive, not every carry.ball_actionwithoutactionsdoes not include drives.ball_actions.driveson the Summary now counts drives, not carries.- Report
schema_versionis now3. Refresh caches keyed on it. - The
progressive_carryfilter uses 10 m and 5 m toward goal, as documented. It used 9.14 m and 4.57 m. - The
carryrows and counts are unchanged.
[1.15.0] - 2026-09
A distance estimate and a per-minute rate are offered alongside the detected-only totals, top speed is measured over a sustained second, and the report schema version moves to 2.
Added
physical.distance_per_min,distance_per90_m,distance_m_est,minutes_measuredandminutes_coveredon the Player Report: distance as metres per measured minute, projected over the minutes the player is accounted for. Within about 7-14% of true distance. Null belowparams.est_seconds_floormeasured seconds.physical.distance_bandson the Player Report: the five speed zones merged to four bands (high_intensityandsprintingcombined intohigh_speed), each with its distance, per-minute rate and estimate.teams[].physicalon the Team Report: the per-player estimate summed over each team, withn_players_est.total_distance_m_eston the Summary player stats: the same estimate at the team-list level. Null below300 sof measured time.params.est_seconds_flooron the reports.
Changed
physical.top_speed_kmh(and Summarymax_speed_kmh) is now the highest 1-second rolling-mean speed over contiguous measured windows, not the 99th percentile of samples. Samples aboveparams.top_speed_ceiling_kmh(36 km/h) are dropped first as tracking artifacts, so top speed no longer reports physically impossible values from identity swaps.- Report
schema_versionis now2. The detected-only distances and speed zones are unchanged. Refresh caches keyed on it.
[1.14.0] - 2026-09
Match periods come from the analysis itself, quality numbers are served per analysis, and the tracking data has a small format.
Removed
- Team sheets. The
PUT /videos/{id}/teamsheetendpoint is gone, andGET /videos/{id}/metano longer returns roster or player data. Team identity now comes from the confirm-sides widget and yourleft_start_teamassertion.
Added
event_types[].qualityandeval_sourceson Schema: how well each event type was detected for this analysis's engine version, per evaluation slice.format=cleanon Download Tracking: the smoothed tracklets and kit colours behind minimap and overlay views, around 1-2 MB against 20-50 MB for the parquet. Available on analyses from version0.5.38.timeline_confidenceon Eventsmatch_timelinerows: 0-1,1.0onfull_game, lower on a detected half split. Null on every other event type and on analyses before engine version0.5.45.
Changed
- The half boundary behind
first_half/second_half(on Events, thematch_timelinefilter of Query Intervals, and the attacking-direction rotation of both reports) is now the one the analysis carries, on analyses from engine version0.5.45. It was re-derived from tracking, which could place half-time a few minutes away from where the possession labels were corrected. Older analyses keep the derived boundary.
Deprecated
format=jsonon Download Tracking: still served, to be removed. Useformat=cleanto draw the match andformat=parquetto analyse it.
[1.13.0] - 2026-09
Two Query Intervals filters classify carries, and the carry event exposes the engine's 0.5.45 movement metadata.
Added
progressive_carryfilter: carries that progressed the ball toward the opponent goal. See Derived Carry.take_on_candidatefilter: carries that engaged a defender, with a tunablemax_opp_dist_m. See Derived Carry. Requires engine0.5.45.carrymetadata fieldsdirection_deg,path_length_cmandmin_opp_dist_m, queryable through the Event Property filter and described on Schema. Present on analyses written by engine0.5.45or later.
[1.12.0] - 2026-09
The drive event is renamed carry. The old name keeps working as a deprecated alias.
Changed
- The ball action event
driveis nowcarryeverywhere it is returned: theevent_typeandlabelon Events and Query Intervals, and the Summary event histograms. Analyses written before engine version0.5.45useddrive; they are served ascarry, so one name covers every analysis.
Added
ball_actions.carrieson the Summary player stats.
Deprecated
driveas aball_actionfilter action value: accepted as an alias ofcarry, to be removed. Requests naming it return rows labelledcarry.ball_actions.driveson the Summary: kept equal tocarries, to be removed.
[1.11.0] - 2026-08
One point shape across both reports, and every threshold the numbers turn on is now in params.
Added
params.sequence_gap_msandparams.sequence_shot_slack_mson both reports: the maximum gap between two possessions in oneon_ball.best_sequence, and the maximum time a possession may close after a shot and still count as preceding it.
Changed
- Player Report
position.avg_position[]is now{ period, position: { x, y }, n_frames }, previously flatx/y. - Team Report
teams[].average_positions[].avg_positionis renamedposition, giving both reports one point shape under one field name. on_ball.shots[].distance_to_goal_mis now null whenevercoordinate_frameis not"attacking"; it was previously measured in"attacking_first_half"too, where second-half shots are mirrored and the distance was to the goal the player was defending.- Team names fall back to the neutral
"Team 0"/"Team 1", never to the wire label"team_0". territory[].zoneis documented as a pass-through of the engine'sball_pitchzonevocabulary, so do not switch on it exhaustively.
Unchanged
- Every other field name, unit and null rule on both reports, and every legacy endpoint.
[1.10.0] - 2026-08
Where two endpoints report the same quantity, they now compute it the same way. See Speed & Distance and Pitch Coordinates.
Added
qualityonGET /analyses/{id}/meta-data, the same typed subset (score,grade,reasons) the Team Report ships, andnullon analyses without the quality artifact.coordinate_framerequest parameter onPOST /analyses/{id}/query-intervals, either"camera"(default, unchanged) or"attacking", which rotatesinclude_pitch_coordsoutput with the same team sides the reports use and tags each row with the frame applied. See Query Intervals.physical.sourceon the Player Report,engineortracking_fallback, naming which smoother produced the speed series.orientation_sourceon both reports, recording where the attacking direction behindcoordinate_framecame from:hub(your confirmed side, or the derivedleft_start_team),game_meta(the analysis's own record),tracking(inferred from which end each team occupied), ornullwhen neither could tell, in which casecoordinate_frameiscamera.
Changed
- Analyses without per-frame speed data now get a full
physicalsection on the Player Report, computed by insight's fallback smoother over tracking positions: distance, speed zones, top speed, fatigue curve and sprints, where they previously returned zeros. Treattracking_fallbacknumbers as indicative. - Player physics on Summary now come from the same speed series as the Player Report, so a player's distance, top speed and speed buckets match across the two; values shift slightly with the shared estimator, and
max_speed_kmhis the 99th percentile of the per-sample speed. tracking_duration_secon Summary now measures detected time only (detected samples times 40 ms), so it drops on non-broadcast footage where it previously included off-camera gaps.- Player Report speed-zone edges are now
7 / 14 / 21 / 25.2 km/h, a refinement of the Summary buckets (7.2 / 14.4 / 19.8 / 25.2), so a Summary bucket is an exact union of report zones.
Unchanged
- Every live wire shape is untouched: Summary bucket keys and
_secsuffixes,team_idstrings, filter vocabulary, and the defaultcameraquery-intervals output are byte-identical.
[1.9.0] - 2026-08
Added
- Match reports, per-player and per-team JSON, one call per page.
GET /analyses/{id}/player-report/{player_id}returns coverage, physical output (distance, speed zones, top speed, fatigue curve, sprints), positioning (heatmaps, average position, zone hull, third timeline), on-ball actions (passes, shots, carries, tackles, blocks, pass network, touches, involvement, best sequence) and interactions (pressure received and applied, direct opponent, link-up). See Player Report.GET /analyses/{id}/team-reportreturns average positions per team, possession split, territory, kits and analysis quality. See Team Report.- Coordinates are metres in named
x/yfields, rotated so each team attacks from left to right, andcoordinate_framereports how far that rotation could be resolved (attacking,attacking_first_half,camera). - Every heatmap is the same self-describing grid (
bins,extent,counts), andparamsechoes back every threshold the numbers were computed with. - Every on-ball action row carries
event_idandt_ms, the join keys to Events and Query Intervals. schema_version(1at this release) versions the response shape and the thresholds, so key your cache on it.
Changed
GET /analyses/{id}/eventsrows now also carryevent_id, the join key the report's on-ball rows use; it is null on older analyses, and existing fields are unchanged.
Unchanged
- Existing endpoints, filter vocabulary, player keys (
0-7,0-GK) and units are untouched. - The report's possession figures are the ones Summary returns, and its
qualityobject is the shape returned by Get Analysis.
Older analyses
- Report sections degrade independently rather than failing.
- Analyses without per-frame speed data returned zeroed
physicalat this release, replaced in 1.10.0 by a fallback smoother. - Analyses without nearest-player data return null
interactions.pressure_receivedandpressure_applied, withdirect_opponentandlink_upas[]; theinteractionsobject itself is always present. - Analyses whose attacking direction could not be measured return
coordinate_frame: "camera". - Per-player event counts are lower bounds, so read
coveragealongside them.
[1.8.0] - 2026-08
Added
- Team identity resolution. See Teams and sides.
GET /analyses/{id}/team-mappingresolvesteam_0/team_1to home/away, with names, sides, squads andidentity_source.team_zeroon video responses (home,awayornull) says whoteam_0is.GET /videos/{id}/preview-teamsreturns pre-analysis kit detection (colours and player crops), ready seconds after video creation.POST /videos/{id}/embed-tokenand the embeddable confirm-sides widget let your user confirm which kit is the home team.PUT /videos/{id}/teamsheetreplaces the roster endpoint, andGET /videos/{id}/metareads the resolved meta. See Game meta.PUT /videos/{id}/teamsheetwas removed in 1.14.0.- New analysis status
waiting_for_meta, withwaiting_forin the response, is a short automatic fail-open hold while the hub finishes its own kit pass.
- Analysis quality: a
qualityobject onGET /analyses/{id}with ascore(0-100), agrade(good,fair,degradedorunreliable) andreasonsexplaining any degradation. See Get Analysis. - An analysis workflow guide covering the end-to-end flow.
Changed
team_0/team_1are shirt-cluster labels, fixed before sides are measured, and no longer guaranteed to mean left- or right-starting.- Map those labels via
team-mappingorteam_zero, and render neutral "Team 0" / "Team 1" labels while identity isnull. left_start_teamon the video is now a derived value, so stop using it to infer home/away; your own assertion still wins when you send it.- Identity corrections apply at read time: a team sheet or confirmation arriving after an analysis is visible in all responses immediately, with no re-processing.
Unchanged
- Filter vocabulary (
team_possessionwithteams: ["team_0"|"team_1"]), player keys (0-7,0-GK), and query-intervals request and response shapes.
Older analyses
- Analyses aggregated before this release have no identity measurement recorded, so
team_zeroand therolefields readnulland labels fall back to "Team 0" / "Team 1". Re-aggregating the analysis resolves it.
[1.7.0] - 2026-07
Added
- Row status and confidence columns on the tracking download, from analysis version
0.5.36.- New columns
status,overlap_partner_id,position_confandidentity_conf. - Full-squad coverage: off-camera players are now included as 5 Hz
projectedrows, with pitch coordinates only and no pixel coordinates. - For the previous on-camera-only behaviour, filter with
df[df['status'].str.startswith('detected')]. - See Download Tracking.
- New columns
Changed
- Duplicate event blocks at segment boundaries are removed, roughly 20 fewer duplicates per game.
- Match timeline durations are corrected by about 2s per segment.
- Better camera calibration improved position quality, and the roughly 3% of frames that could not be calibrated are now omitted instead of returned with degraded accuracy.
Unchanged
- Summary player statistics are still computed from detection-backed rows only, so values stay comparable with earlier versions.
- Events schema, filter types and all units are unchanged.
[1.6.0] - 2026-03
Added
- Ball action filter (
ball_action).- Filters passes, drives (dribbles) and shots.
- Filters by specific players or teams.
- Requires analysis version
0.5.10or later. - Responses include
player_id,team_idandteam_name.
[1.5.0] - 2026-02
Added
- Video management endpoint documentation.
GET /videoslists all videos.POST /videosuploads a new video.GET /videos/{id}gets video details.PUT /videos/{id}updates video metadata.
- Create analysis endpoint documentation:
POST /videos/{id}/analysiscreates an analysis for a video. - Complete workflow examples for video upload and analysis creation.
[1.4.0] - 2026-02
Added
- Player names in the Summary endpoint.
- Each entry in the Summary
playersarray includes anamedisplay label such as"Team A #10", alongsideplayer_id,team_idand stats. - For a plain player-id to display-name map, use
GET /analyses/{id}/meta-data, which returns anidentitiesobject.
- Each entry in the Summary
[1.3.0] - 2026-02
Added
- Summary endpoint (
GET /analyses/{id}/summary).- Comprehensive game overview.
- Per-minute possession breakdown.
- Player distance and speed statistics.
- Analysable duration metrics.
Changed
- Player stats now include speed buckets (walking, jogging, running, sprinting).
[1.2.0] - 2026-01
Added
- Tracking download (
GET /analyses/{id}/tracking/download).- Downloads raw tracking data as Parquet or JSON.
- Includes all player positions at 25 FPS.
[1.1.0] - 2024-12
Added
player_possessionfilter type.team_side_perspectiveoption for the ball location filter.
Fixed
- Padding is now correctly applied in query-intervals.
[1.0.0] - 2024-10
Initial Release
- Events endpoint.
- Meta-data endpoint.
- Query intervals with the
team_possession,ball_location,player_ball_proximity,match_timelineandscenefilters.