Live scoreboards and game pages for news and media sites
Publishers, local news, team blogs and media sites that cover games.
Cache the league scoreboard on your server or edge for 30-60 seconds and render it in your own templates. Your readers hit your cache, not the API, so ten readers and ten thousand cost the same number of calls. For pages that should tick without a refresh, keep one WebSocket on your server and fan updates out to readers.
Updated 2026-11-04. Data is aggregated from public sources and is typically 20-30 seconds behind live play (about 1 second after our source). There is no SLA.
Start with the free widget
If you just need scores on a page today, the free scoreboard widget embeds one league with no key and refreshes every 60 seconds. When you want your own layout, game pages or more leagues, move to the API below.
Cache once, serve every reader
GET /events returns the league's current scoreboard: teams, logos, colours, scores, status.state (pre, in, post) and the clock. Cache it on the server and every page view reads the cache. Responses carry X-RateLimit-* headers so you can watch your usage.
Next.js route handler with a 60-second cache
// app/api/scores/[league]/route.ts
const SPORT = { nfl: 'football', 'college-football': 'football', nba: 'basketball', mlb: 'baseball', nhl: 'hockey', 'eng.1': 'soccer' };
export const revalidate = 60; // one upstream call per league per minute, whatever your traffic
export async function GET(_req: Request, { params }: { params: { league: string } }) {
const sport = SPORT[params.league as keyof typeof SPORT];
if (!sport) return Response.json({ error: 'unknown league' }, { status: 404 });
const res = await fetch(`https://www.realtimesportsapi.com/api/v1/sports/${sport}/leagues/${params.league}/events`, {
headers: { Authorization: `Bearer ${process.env.RSA_API_KEY}` },
next: { revalidate: 60 }
});
const { data } = await res.json();
return Response.json(data.map((e: any) => ({
id: e.id, name: e.shortName, state: e.status.state, detail: e.status.detail,
home: { abbr: e.homeTeam.abbreviation, score: e.homeTeam.score, logo: e.homeTeam.logo },
away: { abbr: e.awayTeam.abbreviation, score: e.awayTeam.score, logo: e.awayTeam.logo }
})));
}Game pages that update without a refresh
For a live blog or game page, keep one WebSocket connection on your server, subscribe to event_score_change and event_status_change for the league, and push changes to readers over your own Server-Sent Events or socket layer. Use frequency: "30s" on status updates to conflate clock ticks; score changes, live and final are always sent immediately.
Server: subscribe once for the league
// Server-side only: your API key never ships to browsers or apps.
const res = await fetch('https://www.realtimesportsapi.com/api/websocket/auth', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.RSA_API_KEY}` }
});
const { data } = await res.json(); // data.url, data.token (valid 1 hour)
const ws = new WebSocket(`${data.url}?token=${data.token}`);
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'subscribe', event: 'event_score_change', filters: { sport: 'football', league: 'nfl' } }));
ws.send(JSON.stringify({ type: 'subscribe', event: 'event_status_change', filters: { sport: 'football', league: 'nfl' }, frequency: '30s' }));
};
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.type.startsWith('event_')) broadcastToReaders(msg.data.eventId, msg); // your SSE / socket fan-out
};Beyond the scoreboard
Game pages can add play-by-play, box scores (NFL, college football, NBA, MLB), team schedules, rosters, injuries (NFL, NBA, MLB, NHL) and league news headlines. See what each endpoint returns by league before you design a page around one.
Endpoints used
GET /sports/{sport}/leagues/{league}/eventsGET /sports/{sport}/leagues/{league}/events/{eventId}GET /sports/{sport}/leagues/{league}/events/{eventId}/playsGET /sports/{sport}/leagues/{league}/seasons/{season}/schedulePOST /websocket/auth
Full reference: docs · OpenAPI · what each endpoint returns, by league
Plans
| Plan | Price | Calls | Rate | WebSocket | Webhooks |
|---|---|---|---|---|---|
| Free | $0 | 125/mo (1,000 first 30 days) | 1/s | 500 msgs/mo | No |
| Starter | $29/mo ($290/yr) | 10,000/mo | 5/s | Shares monthly pool | Shares monthly pool |
| Growth | $49/mo ($490/yr) | 25,000/mo | 10/s | Shares monthly pool | Shares monthly pool |
| Pro | $99/mo ($990/yr) | 50,000/mo | 20/s | 100,000 msgs/mo | 25,000/mo |
| Business | $179/mo ($1,790/yr) | 150,000/mo | 40/s | 300,000 msgs/mo | 75,000/mo |
| Scale | $299/mo ($2,990/yr) | 500,000/mo | 100/s | 500,000 msgs/mo | 100,000/mo |
Every successful REST call counts as one call. Over the limit you get HTTP 429 with a Retry-After header. No SLA. Full pricing.
FAQ
- Can I display the data on a commercial site?
- Yes, within the terms; see the usage rights section of the FAQ. Team names and logos may be trademarks of their owners.
- Does a traffic spike increase my bill?
- Not if you cache. Usage counts API calls and WebSocket messages, not your page views. A 60-second server cache is one call per league per minute.
- How fresh are the scores?
- Typically 20-30 seconds behind live play. There is no SLA.
- Which leagues are covered?
- NFL, college football, NBA, men's college basketball, MLB, NHL and 23 soccer competitions including MLS and the Premier League.