Frame State Filter
Filter intervals by per-frame player state thresholds. Find moments where players meet specific physical criteria — sprinting, pressing close to opponents, etc.
Requires Data Version 3+
This filter requires analysis data version 3 with frame_state data available. Use the Schema endpoint to check availability.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | Must be "frame_state" |
players |
array | Yes | Player IDs to check (e.g. ["0-5", "1-13"]) |
column |
string | Yes | State column to threshold on |
gte |
number | No | Minimum value (greater than or equal) |
lte |
number | No | Maximum value (less than or equal) |
min_duration_ms |
integer | No | Minimum interval duration in milliseconds (default: 500) |
Available Columns
| Column | Type | Description |
|---|---|---|
timestamp |
int32 |
Milliseconds from match start; join key. Same format as tracking.parquet (= frame / fps * 1000). |
player_id |
str |
Identity-resolved 'team-jersey' id; join key. |
speed_mps |
float32 |
Smoothed speed in m/s — Savitzky-Golay (window=9, order=2) over per-track xy. Pinned in the schema; changing the smoother bumps data_version_external. |
nearest_opp_id |
str |
player_id of the closest opposite-team player at this frame. Null when no opponent is on-frame. |
nearest_opp_dist_m |
float32 |
Distance to nearest_opp_id in metres. |
Basic Examples
Player sprinting (speed >= 7 m/s)
{
"filters": [
{
"type": "frame_state",
"players": ["0-10"],
"column": "speed_mps",
"gte": 7.0,
"min_duration_ms": 1000
}
]
}
Player jogging (moderate speed)
{
"filters": [
{
"type": "frame_state",
"players": ["0-10"],
"column": "speed_mps",
"gte": 2.0,
"lte": 4.0,
"min_duration_ms": 2000
}
]
}
Player pressing (close to opponent)
{
"filters": [
{
"type": "frame_state",
"players": ["0-7", "0-8", "0-10"],
"column": "nearest_opp_dist_m",
"lte": 2.0,
"min_duration_ms": 500
}
]
}
Combining with Other Filters
High-speed runs during possession
{
"operator": "AND",
"filters": [
{
"type": "frame_state",
"players": ["0-10"],
"column": "speed_mps",
"gte": 6.0,
"min_duration_ms": 1000
},
{ "type": "team_possession", "teams": ["team_0"] }
]
}
Sprint into the final third
{
"operator": "AND",
"filters": [
{
"type": "frame_state",
"players": ["0-10"],
"column": "speed_mps",
"gte": 7.0,
"min_duration_ms": 1000
},
{ "type": "ball_location", "x_min": 70, "x_max": 105 }
]
}
How It Works
The filter identifies consecutive frames where the player meets the threshold condition, groups them into intervals, and filters out intervals shorter than min_duration_ms. This ensures you only get meaningful stretches of activity, not single-frame spikes.
Response Structure
{
"start": 340.2,
"end": 343.8,
"label": "speed_mps >=7.0",
"type": "frame_state"
}
Response Fields
| Field | Type | Description |
|---|---|---|
start |
float | Start time in seconds |
end |
float | End time in seconds |
label |
string | Column name and threshold used |
type |
string | Always "frame_state" |