NFL API in Python: scores, box scores and injuries
A single Python script with three commands: this week's NFL games (or any past week) with scores and team ids, passing/rushing/receiving lines from one game's box score, and the league-wide or per-team injury report.
- Stack
- Python, requests
- Plan
- Free (each command is one call)
- Code
- python-nfl/ (MIT)
Updated 2026-11-05. Tested against the live API on that date. 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.
1. Get a free API key
Sign up (no card) and copy the key from the dashboard. The Free plan gives you 1,000 calls in the first 30 days, then 125 a month, at 1 request per second. Every successful REST call counts as one call.
Check the key works with one call to the live-scores endpoint:
Terminal
export REALTIME_SPORTS_API_KEY=your_key
curl -H "Authorization: Bearer $REALTIME_SPORTS_API_KEY" \
"https://www.realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/live"2. Get the code
Everything below is in the python-nfl/ folder of the examples repo (MIT). Clone it and work from that folder.
Terminal
git clone https://github.com/ElcoDevRepos/realtime-sports-api-examples
cd realtime-sports-api-examples/python-nfl3. Install
Python 3.10+ and requests. Nothing else.
Terminal
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # REALTIME_SPORTS_API_KEY4. The script
api_get sends your key as a Bearer token and stops with the API's own error message if a call fails. scores reads the current scoreboard, or a season week with --week. box walks each team's players and prints the passing, rushing and receiving categories. injuries prints each player's status, body part and expected return date. The league-wide feed is limited to the 25 most recent records per team, so pass --team for a complete team report.
python-nfl/nfl.py
#!/usr/bin/env python3
"""NFL data in Python with the Realtime Sports API: scores, box scores and injury reports.
Usage:
python nfl.py scores # this week's games (current scoreboard)
python nfl.py scores --season 2026 --week 8 # any regular-season week
python nfl.py box <eventId> # passing, rushing and receiving lines for one game
python nfl.py injuries # league-wide injury report (latest 25 per team)
python nfl.py injuries --team 9 # one team's full report (team ids: `scores` prints them)
Each command is one API call. Needs REALTIME_SPORTS_API_KEY (env or .env).
"""
from __future__ import annotations
import argparse
import os
import sys
from pathlib import Path
from typing import Any, Dict
import requests
API_BASE = os.environ.get("RSA_API_BASE", "https://www.realtimesportsapi.com/api/v1")
NFL = "/sports/football/leagues/nfl"
def load_dotenv(path: Path) -> None:
"""Tiny .env loader (KEY=value). Existing environment variables win."""
if not path.exists():
return
for line in path.read_text().splitlines():
line = line.strip()
if line and not line.startswith("#") and "=" in line:
k, v = line.split("=", 1)
os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'"))
def api_get(path: str, **params: Any) -> Dict[str, Any]:
key = os.environ.get("REALTIME_SPORTS_API_KEY")
if not key:
sys.exit("Set REALTIME_SPORTS_API_KEY (get a free key at https://www.realtimesportsapi.com/signup)")
r = requests.get(f"{API_BASE}{path}", params=params, headers={"Authorization": f"Bearer {key}"}, timeout=20)
body = r.json()
if r.status_code != 200 or not body.get("success", False):
err = body.get("error") or {}
sys.exit(f"HTTP {r.status_code}: {err.get('message') or body}")
return body
def team_line(t: Dict[str, Any]) -> str:
score = t.get("score")
return f"{t.get('abbreviation') or t.get('name')} (id {t.get('id')}){'' if score is None else f' {score}'}"
def cmd_scores(args: argparse.Namespace) -> None:
if args.week:
body = api_get(f"{NFL}/seasons/{args.season}/schedule", week=args.week, seasonType=2)
else:
body = api_get(f"{NFL}/events", limit=50)
for g in sorted(body["data"], key=lambda e: e.get("date") or ""):
status = (g.get("status") or {}).get("detail") or (g.get("status") or {}).get("state")
print(f"[{g['id']}] {g.get('date', '')[:16]} {team_line(g['awayTeam'])} @ {team_line(g['homeTeam'])} {status}")
def cmd_box(args: argparse.Namespace) -> None:
box = api_get(f"{NFL}/events/{args.event_id}/boxscore")["data"] or {}
for side in ("away", "home"):
team = box.get(f"{side}Team") or {}
print(f"\n{team.get('name', side)} {team.get('score', '')}")
for p in box.get(f"{side}Players") or []:
c = p.get("categories") or {}
parts = []
if "passing" in c:
ps = c["passing"]
parts.append(f"{ps.get('completions/passingAttempts')} for {ps.get('passingYards')} yds, {ps.get('passingTouchdowns')} TD, {ps.get('interceptions')} INT")
if "rushing" in c:
rs = c["rushing"]
parts.append(f"{rs.get('rushingAttempts')} rush, {rs.get('rushingYards')} yds, {rs.get('rushingTouchdowns')} TD")
if "receiving" in c:
rc = c["receiving"]
parts.append(f"{rc.get('receptions')} rec, {rc.get('receivingYards')} yds, {rc.get('receivingTouchdowns')} TD")
if parts:
print(f" {p.get('name')}: " + "; ".join(parts))
def cmd_injuries(args: argparse.Namespace) -> None:
params = {"team": args.team} if args.team else {}
data = api_get(f"{NFL}/injuries", **params)["data"] or {}
for group in data.get("groups") or []:
rows = group.get("injuries") or []
if not rows:
continue
# The league-wide feed names each team; a ?team= report carries only the team id.
t = rows[0].get("team") or group.get("team") or {}
team = t.get("displayName") or f"Team {t.get('id', '?')}"
print(f"\n{team} ({len(rows)})")
for i in rows:
ath = i.get("athlete") or {}
ret = f", expected back {i['returnDate']}" if i.get("returnDate") else ""
print(f" {ath.get('displayName')} ({ath.get('position')}): {i.get('status')} - {i.get('bodyPart') or i.get('type')}{ret}")
print(f"\n{data.get('count', 0)} records")
def main() -> None:
load_dotenv(Path(__file__).with_name(".env"))
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
sub = ap.add_subparsers(dest="cmd", required=True)
s = sub.add_parser("scores")
s.add_argument("--season", type=int, default=2026)
s.add_argument("--week", type=int)
s.set_defaults(fn=cmd_scores)
b = sub.add_parser("box")
b.add_argument("event_id")
b.set_defaults(fn=cmd_box)
i = sub.add_parser("injuries")
i.add_argument("--team")
i.set_defaults(fn=cmd_injuries)
args = ap.parse_args()
args.fn(args)
if __name__ == "__main__":
main()
5. Run it
On 5 November 2026, scores --season 2026 --week 8 listed [401873023] CAR (id 29) 19 @ GB (id 9) 27 Final. box 401873023 printed lines like Bryce Young: 23/41 for 209 yds, 1 TD, 1 INT and Chuba Hubbard: 22 rush, 81 yds, 1 TD; 7 rec, 38 yds, 0 TD. injuries --team 9 returned 67 Green Bay records, each with a status (Questionable, Out, Injured Reserve) and, where given, an expected return date. The league-wide report had 800 records.
Terminal
python nfl.py scores # this week
python nfl.py scores --season 2026 --week 8 # a past week, with event ids
python nfl.py box 401873023 # one game's stat lines
python nfl.py injuries --team 9 # one team's full report6. Going further
Play-by-play is one more call per game (/events/{eventId}/plays, paginated). The college football version of this script shows it. For a full season in pandas, see the season analysis guide. To react to scores without polling, use webhooks or the WebSocket stream on a paid plan. Data typically runs 20-30 seconds behind live play.
Endpoints used
GET /sports/football/leagues/nfl/eventsGET /sports/football/leagues/nfl/seasons/{season}/schedule?week=NGET /sports/football/leagues/nfl/events/{eventId}/boxscoreGET /sports/football/leagues/nfl/injuries
Full reference: docs · OpenAPI · what each endpoint returns, by league
FAQ
- Is there a free NFL API for Python?
- Yes. Any HTTP client works; this guide uses requests. A free key (no card) gives 1,000 calls in the first 30 days, then 125 a month, and includes every endpoint, including box scores and injuries.
- How do I get NFL injury data in Python?
- Call GET /sports/football/leagues/nfl/injuries with your key. Pass team={teamId} for one team's complete report; the league-wide feed keeps the 25 most recent records per team.
- Where do I find NFL event and team ids?
- `python nfl.py scores` prints both: the event id in brackets and each team's id next to its abbreviation.