Integration GuidesDocs
Coverage MatrixDocumentationChange LogLog InContact Us
Integration Guides

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

FeedPurpose
Daily SummariesThe day's slate ahead of play: IDs, start times, teams
Live SummariesEvery game currently in the live window, with score and inning state
Live TimelinesThe full play-by-play stream for live games in one call
Live Timelines DeltaOnly the most recent seconds of timeline activity
Sport Event TimelineThe play-by-play stream for a single game
Sport Event SummaryOne game's status and box score; confirms the final state


High-Level Workflow

Live Tracking WorkflowPreview the slate, poll the window, add depth, wind down
Before playDaily SummariesIDs, start times, teams for today and tomorrow (UTC)
Live windowLive Summariesscores and inning state for every live game
Pitch detailLive Timelines→Live Timelines Deltaplay-by-play where coverage applies
Wind downSport Event Summaryclosed = terminal
Dashed pills are optional; the solid pill is the terminal state. Cadences come from the Best Practices section at the end of this page.


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_status names the current inning, or pause during the break between innings (keep polling; the game is still live); period_scores grows 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 with status: closed.
  • When no game is in the window the feed returns an empty summaries list.

3. Add play-by-play depth

For competitions whose coverage includes basic_play_by_play (see Fundamentals), pitch-level events are available two ways:

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:

Final: Minnesota Twins at Cleveland GuardiansA line score built from period_scores and the statistics totals
Team123456789RHE
MINMinnesota Twins0200001104100
CLECleveland Guardians33111130013190
Innings come from period_scores, R from the status scores, H and E from the team statistics; crest slots use neutral badges, filled by your own or licensed assets.


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 closed as the terminal state and schedule one final Sport Event Summary pull a few minutes after it

Did this page help you?