Tracking Live Games
This scenario keeps scores and play-by-play flowing while games are in progress: find what is live, poll at the right depth, and wind down cleanly at the final out.
This scenario is commonly used to:
- Drive a live scoreboard across one league or many
- Power a pitch-by-pitch gamecast
- Feed live win-probability and game-state displays
Relevant Feeds
| Feed | Purpose |
|---|---|
| Daily Summaries | The day's slate ahead of play: IDs, start times, teams |
| Live Summaries | Every game currently in the live window, with score and inning state |
| Live Timelines | The full play-by-play stream for live games in one call |
| Live Timelines Delta | Only the most recent seconds of timeline activity |
| Sport Event Timeline | The play-by-play stream for a single game |
| Sport Event Summary | One game's status and box score; confirms the final state |
High-Level Workflow
Integration Steps
1. Know what is coming
Pull Daily Summaries for today and tomorrow (UTC dates) ahead of the slate, so you have every game's ID, start time, and teams before first pitch; see Pulling Schedules and Results.
2. Poll Live Summaries
Live Summaries returns every game currently in progress, in the same three-part shape as every other summary feed. This response was taken as an evening MLB slate began; the full payload held six entries across two leagues, trimmed here to the two MLB games:
GET https://api.sportradar.com/baseball/trial/v2/en/schedules/live/summaries.json
x-api-key: YOUR_API_KEY{
"generated_at": "2026-07-21T22:50:08+00:00",
"summaries": [
{
"sport_event": {
"id": "sr:sport_event:63299165",
"start_time": "2026-07-21T22:40:00+00:00",
"competitors": [
{
"id": "sr:competitor:3650",
"name": "Cleveland Guardians",
"country": "USA",
"country_code": "USA",
"abbreviation": "CLE",
"qualifier": "home",
"gender": "male"
},
{
"id": "sr:competitor:3649",
"name": "Minnesota Twins",
"country": "USA",
"country_code": "USA",
"abbreviation": "MIN",
"qualifier": "away",
"gender": "male"
}
]
},
"sport_event_status": {
"status": "live",
"match_status": "1st_inning",
"home_score": 0,
"away_score": 1,
"period_scores": [
{
"home_score": 0,
"away_score": 1,
"type": "regular_period",
"number": 1
}
]
}
},
{
"sport_event": {
"id": "sr:sport_event:63301331",
"start_time": "2026-07-21T22:40:00+00:00",
"competitors": [
{
"id": "sr:competitor:3635",
"name": "Philadelphia Phillies",
"country": "USA",
"country_code": "USA",
"abbreviation": "PHI",
"qualifier": "home",
"gender": "male"
},
{
"id": "sr:competitor:3638",
"name": "Los Angeles Dodgers",
"country": "USA",
"country_code": "USA",
"abbreviation": "LAD",
"qualifier": "away",
"gender": "male"
}
]
},
"sport_event_status": {
"status": "not_started",
"match_status": "not_started"
}
}
]
}match_statusnames the current inning, orpauseduring the break between innings (keep polling; the game is stilllive);period_scoresgrows as innings complete.- The feed is "the live window", not strictly "in play": games enter 10 minutes before their scheduled start (the second entry is one, listed with
status: not_started) and leave 10 minutes after they end, so a just-finished game can remain listed briefly withstatus: closed. - When no game is in the window the feed returns an empty
summarieslist.
3. Add play-by-play depth
For competitions whose coverage includes basic_play_by_play (see Fundamentals), pitch-level events are available two ways:
- Live Timelines: the full event stream for every live covered game in one call
- Sport Event Timeline: the same stream for a single game
In Live Timelines, each entry carries the sport event ID directly as its id, with the status and event array alongside. Taken during the first inning of an MLB game, trimmed to that game's three most recent events (its stream already held 78):
GET https://api.sportradar.com/baseball/trial/v2/en/schedules/live/timelines.json
x-api-key: YOUR_API_KEY{
"generated_at": "2026-07-21T22:50:11+00:00",
"sport_event_timelines": [
{
"id": "sr:sport_event:63299165",
"start_time": "2026-07-21T22:40:00+00:00",
"sport_event_status": {
"status": "live",
"match_status": "1st_inning",
"home_score": 0,
"away_score": 1,
"period_scores": [
{
"home_score": 0,
"away_score": 1,
"type": "regular_period",
"number": 1
}
]
},
"timeline": [
{
"id": 2416070322,
"type": "ball_in_play",
"time": "2026-07-21T22:49:56+00:00",
"match_time": 10,
"players": [
{
"id": "sr:player:2290857",
"name": "Rojas, Kendry",
"type": "pitcher"
}
],
"inning_half": "bottom"
},
{
"id": 2416070350,
"type": "player_out",
"time": "2026-07-21T22:50:03+00:00",
"match_time": 10,
"out_type": "ground_out",
"out_base": 0,
"count_balls": 3,
"count_strikes": 2,
"outs": 1,
"errors": 0
},
{
"id": 2416070376,
"type": "play_end",
"time": "2026-07-21T22:50:06+00:00",
"match_time": 10,
"player": {
"id": "sr:player:1721884",
"name": "Kwan, Steven"
}
}
]
}
]
}Pitch-level depth follows coverage: games from competitions without basic_play_by_play coverage may appear with only match_started and match_ended markers in their timeline arrays. Key your rendering on the events present rather than expecting every listed game to carry pitches.
The timeline element itself is a chronological event array. This longer sequence is from a completed covered game (trimmed to one scoring play; the full response holds 1,121 events): an at-bat begins, the ball is put in play, and a run scores:
{
"sport_event_status": {
"status": "closed",
"match_status": "ended",
"home_score": 13,
"away_score": 4,
"winner_id": "sr:competitor:3650"
},
"timeline": [
{
"id": 2415291484,
"type": "play_start",
"time": "2026-07-20T22:58:00+00:00",
"players": [
{
"id": "sr:player:2009851",
"name": "Ryan, Joe",
"type": "pitcher"
},
{
"id": "sr:player:1692303",
"name": "Rocchio, Brayan",
"type": "batter"
}
],
"inning_half": "bottom",
"at_bat_number": 8,
"pitch_number": 18,
"count_balls": 1,
"count_strikes": 1,
"outs": 2
},
{
"id": 2415291526,
"type": "ball_in_play",
"time": "2026-07-20T22:58:10+00:00",
"players": [
{
"id": "sr:player:2009851",
"name": "Ryan, Joe",
"type": "pitcher"
},
{
"id": "sr:player:1692303",
"name": "Rocchio, Brayan",
"type": "batter"
}
],
"inning_half": "bottom"
},
{
"id": 2415291554,
"type": "run_scored",
"time": "2026-07-20T22:58:15+00:00",
"players": [
{
"id": "sr:player:2801195",
"name": "Bazzana, Travis",
"type": "runner"
},
{
"id": "sr:player:1692303",
"name": "Rocchio, Brayan",
"type": "batter"
}
],
"inning_half": "bottom",
"scored_run_type": "earned_run",
"starting_base": 2,
"count_balls": 1,
"count_strikes": 1,
"outs": 2
}
]
}Events name their players by role (pitcher, batter, runner) and carry game-state context where it applies: inning_half, at_bat_number, pitch_number, the ball and strike count_* fields, outs, and on scoring plays scored_run_type and starting_base. Event types across one MLB game: match_started, inning_half_start, play_start, pitch_result, ball_in_play, player_out, player_on_base, run_scored, runner_check, substitution, inning_half_end, match_ended; an NPB stream additionally carried out_recorded and at_bat_result. Parse defensively: handle event types you do not recognize by skipping them. Each event carries its own numeric id and timestamp, so you can render incrementally by processing only events newer than the last one you displayed.
4. Cut bandwidth with the delta feed
Live Timelines Delta returns only the most recent seconds of timeline activity, so steady-state polling moves far less data than re-pulling full timelines. Entries nest under sport_event_timeline and carry the current status, plus whatever events fell inside the delta window; this response was taken at the same moment as the timeline above, during a lull between pitches:
{
"generated_at": "2026-07-21T22:50:24+00:00",
"sport_event_timeline_deltas": [
{
"sport_event_timeline": {
"id": "sr:sport_event:69056268",
"start_time": "2026-07-21T22:35:00+00:00",
"sport_event_status": {
"status": "not_started",
"match_status": "not_started"
}
}
},
{
"sport_event_timeline": {
"id": "sr:sport_event:63299165",
"start_time": "2026-07-21T22:40:00+00:00",
"sport_event_status": {
"status": "live",
"match_status": "1st_inning",
"home_score": 0,
"away_score": 1,
"period_scores": [
{
"home_score": 0,
"away_score": 1,
"type": "regular_period",
"number": 1
}
]
}
}
}
]
}An entry with no timeline array had no new events in the window. Use the full feeds to build initial state and to re-synchronize after any gap in polling, and the delta feed in between.
5. Wind down at the final out
When a game leaves Live Summaries, confirm its final state with Sport Event Summary: status: closed with winner_id and completed statistics is the terminal signal. Statistics can settle for a short period after the last pitch, so schedule one final pull a few minutes after the game closes. The closed summary carries everything a final-score module needs; this line score is built from its period_scores and statistics totals:
Common Use Cases
Typical builds on this workflow include:
- A multi-league live scoreboard with inning-by-inning line scores
- A single-game gamecast rendering every pitch and base state
- Notifications on scoring plays, lead changes, and finals
- A live data layer under win-probability displays
Best Practices
- Live Summaries and Live Timelines carry a measured cache TTL of about 1 second during play; poll at the freshness your product needs, typically every 2 to 10 seconds for a gamecast and every 20 to 60 seconds for a scoreboard
- The delta feed covers only the last few seconds of activity; if your polling gap exceeds its window, re-pull the full timeline to re-synchronize
- Off-slate, drop to a slow Daily Summaries loop and re-enter live polling as start times approach
- Treat
closedas the terminal state and schedule one final Sport Event Summary pull a few minutes after it
Updated about 6 hours ago
