Build a live sports scoreboard with the Lumify API

Discover in-progress games, stream score updates over SSE, and ship a working scoreboard — with a cloneable open-source demo you can run in about a minute.

For agents: the machine-readable twin of this page is /use-cases/live-scoreboard.md.

API key Sign in, or get an instant trial key below — no signup required.

What you'll build

A live scoreboard that lists every game currently inprogress, shows team names, scores, period, and clock, and updates in real time — without putting your API key in the browser.

Finished live sports scoreboard demo powered by the Lumify API

How it works

Three Lumify endpoints cover the whole flow:

  1. DiscoverGET /v1/events?status=inprogress&include_scores=true returns live games with scores already inlined.
  2. Update — per game, either push with GET /v1/events/{id}/stream (SSE) or poll GET /v1/events/{id}/score.
  3. Render — map scores[], period_label, and clock into cards; close the stream when the game finishes.

Keep keys server-side. Lumify has no CORS for browser keys — and you shouldn't put a real lmfy-… key in frontend JS. The open-source demo uses a tiny Express proxy. See best practices.

1. List live games

Filter the events list with status=inprogress. Add include_scores=true so each event already carries participants and scores — enough to paint the first frame without N+1 detail calls. sort=status puts live games first.

curl
curl "https://lumify.ai/v1/events?status=inprogress&include_scores=true&sort=status" \
  -H "Authorization: Bearer YOUR_API_KEY"
Python
from lumify import Lumify

client = Lumify(api_key="YOUR_API_KEY")
live = client.events.list(
    status="inprogress",
    include_scores=True,
    sort="status",
)
for event in live["events"]:
    print(event["id"], event["name"], event["status"])
JavaScript
import { Lumify } from "@lumifyai/sdk";

const client = new Lumify({ apiKey: "YOUR_API_KEY" });
const { events } = await client.events.list({
  status: "inprogress",
  includeScores: true,
  sort: "status",
});
events.forEach(e => console.log(e.id, e.name, e.status));

Optional: add sport=nba (or mlb, nhl, soccer, …) to scope the board to one sport.

2. Render a scoreboard card

Each event with include_scores=true includes participants[] (home/away or player_1/player_2), plus period / period_label / clock when available. For subsequent ticks, prefer the lighter /score payload:

json — GET /v1/events/{id}/score
{
  "event_id":     4812,
  "status":       "inprogress",
  "period":       "3",
  "period_label": "Q3",
  "clock":        "8:42",
  "scores": [
    { "role": "home", "name": "Boston Celtics", "abbreviation": "BOS", "score": "101" },
    { "role": "away", "name": "New York Knicks", "abbreviation": "NYK", "score": "98" }
  ],
  "updated_at":   "2026-05-10T01:18:44Z"
}

period_label is sport-aware (Q3, Inn 7, 1st, 67'). Live score responses are cached ~15s while a game is in progress — a natural poll cadence.

3. Keep it live — poll vs SSE

Two ways to refresh scores:

SSE connections are capped at 5 minutes; Lumify sends event: reconnect before closing so you can reopen. Each key may hold a limited number of concurrent streams (5). The official SDKs reconnect automatically across the 5-minute cap.

curl
curl -N "https://lumify.ai/v1/events/4812/stream" \
  -H "Authorization: Bearer YOUR_API_KEY"
Python
from lumify import Lumify

client = Lumify(api_key="YOUR_API_KEY")
for evt in client.events.stream(4812):
    if evt.event == "score":
        print(evt.data["period_label"], evt.data["clock"], evt.data["scores"])
    elif evt.event == "done":
        break
JavaScript
import { Lumify } from "@lumifyai/sdk";

const client = new Lumify({ apiKey: "YOUR_API_KEY" });
for await (const evt of client.events.stream(4812)) {
  if (evt.event === "score") renderScore(evt.data);
  if (evt.event === "done") break;
}

4. Handle game end

When a game finishes:

  • The SSE stream emits event: done and closes.
  • /score returns status: "final" (or walkover) with finished: true and is_winner set on participants.
  • The game drops out of ?status=inprogress on the next discovery poll — remove or mark the card Final.

Also handle 429 responses: read Retry-After and back off. Details on rate limits.

Get the code

A complete Node + Express + vanilla JS scoreboard — proxy, SSE re-emit, poll fallback, and UI — is open source:

github.com/lumifyai/lumify · examples/scoreboard MIT · Node 18+ · plug in a Lumify API key and run
bash
git clone https://github.com/lumifyai/lumify.git
cd lumify/examples/scoreboard
npm install
cp .env.example .env   # set LUMIFY_API_KEY=lmfy-…
npm start              # → http://localhost:3000

Grab a free key from the banner above (instant trial, no signup) or create a persistent one at /api-keys.

Next steps