College football rankings API in Python
One small script with three commands: print a poll with records, points and first-place votes; compare it with the previous week (movers, new entries, teams that dropped out); and list this week's games that involve a ranked team.
- Stack
- Python, requests
- Plan
- Free (one call per command; movers makes two)
- Code
- python-college-football/ (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-college-football/ 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-college-football3. 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
poll() reads one poll from /rankings (poll=ap, coaches or cfp; add week= for a past week). show prints each ranked team with record, points and first-place votes, then the others receiving votes. movers reads the previous week too and compares by team id, so it lists the biggest moves, the new entries and the teams that dropped out. matchups reads this week's scoreboard, where every ranked team carries a rank, and prints games like #2 UGA @ #10 MISS.
python-college-football/rankings.py
#!/usr/bin/env python3
"""College football rankings in Python with the Realtime Sports API: the AP Top 25, coaches poll or
College Football Playoff rankings, the week's biggest movers, and this week's ranked matchups.
Usage:
python rankings.py # AP Top 25, latest release
python rankings.py --poll cfp # CFP rankings (or: coaches)
python rankings.py movers # who moved most since the previous week (AP)
python rankings.py matchups # this week's games with a ranked team, "#2 UGA @ #10 MISS"
Needs REALTIME_SPORTS_API_KEY (env or .env). `movers` makes two calls, the others one each.
"""
from __future__ import annotations
import argparse
import os
import sys
from pathlib import Path
from typing import Any, Dict, List
import requests
API_BASE = os.environ.get("RSA_API_BASE", "https://www.realtimesportsapi.com/api/v1")
CFB = "/sports/football/leagues/college-football"
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 poll(name: str, week: int | None = None) -> Dict[str, Any]:
params: Dict[str, Any] = {"poll": name}
if week:
params["week"] = week
polls: List[Dict[str, Any]] = api_get(f"{CFB}/rankings", **params)["data"]
if not polls:
sys.exit(f"No {name} poll for that week")
return polls[0]
def cmd_show(args: argparse.Namespace) -> None:
p = poll(args.poll)
print(f"{p['name']} - {p['week'].get('label') or ''} ({(p.get('date') or '')[:10]})")
for r in p["ranks"]:
t = r["team"]
votes = f", {r['firstPlaceVotes']} first-place" if r.get("firstPlaceVotes") else ""
pts = f", {r['points']:g} pts" if r.get("points") else ""
print(f" {r['rank']:>2}. {t.get('displayName')} ({r.get('record') or '-'}){pts}{votes}")
if p.get("othersReceivingVotes"):
print(" Others receiving votes: " + ", ".join(f"{o['team'].get('abbreviation')} {o.get('points') or 0:g}" for o in p["othersReceivingVotes"]))
def cmd_movers(args: argparse.Namespace) -> None:
now = poll(args.poll)
week = now["week"].get("number")
if not week or week < 2:
sys.exit("No previous week to compare with yet")
before = {r["team"]["id"]: r["rank"] for r in poll(args.poll, week - 1)["ranks"]}
moved = [(before[r["team"]["id"]] - r["rank"], r) for r in now["ranks"] if r["team"]["id"] in before]
print(f"{now['name']}: Week {week - 1} -> Week {week}")
for delta, r in sorted(moved, key=lambda m: -abs(m[0]))[:6]:
if delta:
print(f" #{r['rank']:>2} {r['team'].get('displayName')}: {'+' if delta > 0 else ''}{delta} (was #{before[r['team']['id']]})")
for r in now["ranks"]:
if r["team"]["id"] not in before:
print(f" new at #{r['rank']}: {r['team'].get('displayName')}")
for d in now.get("droppedOut") or []:
print(f" dropped out: {d['team'].get('displayName')} (was #{d.get('previousRank')})")
def cmd_matchups(args: argparse.Namespace) -> None:
games = api_get(f"{CFB}/events", limit=200)["data"]
tag = lambda t: f"#{t['rank']} {t.get('abbreviation')}" if t.get("rank") else t.get("abbreviation")
ranked = [g for g in games if g["homeTeam"].get("rank") or g["awayTeam"].get("rank")]
for g in sorted(ranked, key=lambda g: g.get("date") or ""):
st = g.get("status") or {}
score = "" if st.get("state") == "pre" else f" {g['awayTeam'].get('score')}-{g['homeTeam'].get('score')}"
print(f"[{g['id']}] {tag(g['awayTeam'])} @ {tag(g['homeTeam'])}{score} {st.get('detail') or ''}")
print(f"\n{len(ranked)} of {len(games)} games involve a ranked team (rank = the ranking the scoreboard shows for each team)")
def main() -> None:
load_dotenv(Path(__file__).with_name(".env"))
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("--poll", default="ap", choices=["ap", "coaches", "cfp"])
ap.add_argument("cmd", nargs="?", default="show", choices=["show", "movers", "matchups"])
args = ap.parse_args()
{"show": cmd_show, "movers": cmd_movers, "matchups": cmd_matchups}[args.cmd](args)
if __name__ == "__main__":
main()
5. Run it
On 5 November 2026, python rankings.py printed the Week 10 AP Top 25 headed by 1. Miami Hurricanes (8-0), 1740 pts, 62 first-place. movers showed Ohio State falling from #2 to #11 and Florida from #17 to #25, USC, Iowa, New Mexico and South Carolina entering, and SMU, Northwestern, Oklahoma State and Wisconsin dropping out. --poll cfp printed the committee's Week 10 rankings, and matchups found 16 of the week's 63 games with a ranked team, including #9 BYU @ #3 UTAH.
Terminal
python rankings.py # AP Top 25
python rankings.py --poll cfp # College Football Playoff rankings
python rankings.py movers # since last week
python rankings.py matchups # ranked games this week6. Going further
The same endpoint serves men's college basketball (/sports/basketball/leagues/mens-college-basketball/rankings, AP and coaches). For scores, box scores and play-by-play, see the college football API in Python guide; for every field, the rankings endpoint page. Data typically runs 20-30 seconds behind live play.
Endpoints used
GET /sports/football/leagues/college-football/rankings?poll=ap|coaches|cfpGET /sports/football/leagues/college-football/rankings?poll=ap&week=NGET /sports/football/leagues/college-football/events
Full reference: docs · OpenAPI · what each endpoint returns, by league
FAQ
- Is there a free college football rankings API?
- Yes. A free key (no card) gives 1,000 calls in the first 30 days, then 125 a month, and includes the rankings endpoint for the AP Top 25, coaches poll and CFP rankings.
- Can I get a past week's AP poll?
- Yes. Add week=N (and season= for an earlier season) to /rankings; without it you get the latest release.
- Why does a team's rank on a game differ from the AP poll?
- The rank on a scoreboard game is the one shown for that team going into the game, which can follow the CFP rankings once they are released. Use /rankings with poll= for a specific poll.