Open-source project
pseudo-r/Public-ESPN-API avatar
pseudo-r/Public-ESPN-API

Public-ESPN-API: A Documentation Map for ESPN's Undocumented Endpoints, Plus a Django Service

The Public ESPN API documentation provides a complete list of undocumented API endpoints, URL parameters, and JSON response formats across 20+ sports (NFL, NBA, MLB, NHL). Includes live curl examples, routing guides, and a Django REST API service for live scores, standings, and news. Optimized for search, developers, AI, and LLMs.

719 stars86 forksPythonLicense varies

At a glance

What is it?
This repository catalogs ESPN's unofficial JSON endpoints across 17 sports and also ships a Django REST service for scores, standings and news. It is useful as a reference, but it is documentation of someone else's moving target, not a stable SDK.
Who is it for?
Adopt this repository if you need a starting map of ESPN's endpoint families or a Django scaffold for scores and standings, and you accept that ESPN can change or block anything without notice. Do not adopt it as a long-term stability guarantee, and do not treat the Django service as production-hardened without reading its settings and cache configuration yourself.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 73 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What the Repository Actually Contains

ESPN runs public-facing JSON services that power its website and apps, and those services are not officially documented. This repository is an attempt to fill that gap. According to the README, it covers 17 sports and 139 leagues, with 370 v2 endpoints and 79 v3 endpoints mapped from ESPN's WADL files at sports.core.api.espn.com/v2/application.wadl and sports.core.api.espn.com/v3/application.wadl. The material also documents additional domains: site.api.espn.com (v2 and v3), site.web.api.espn.com, cdn.espn.com, now.core.api.espn.com and fantasy.espn.com.

The second half of the project is not documentation at all. The README describes an ESPN Service, a Django REST implementation for live scores, standings and news. So the repository serves two audiences with one codebase: someone reading endpoint tables, and someone running a Python service that proxies those endpoints. The README's disclaimer is explicit that the author is not affiliated with ESPN and that users should follow ESPN's terms of service. That framing matters more than it might appear, because the entire value of the project depends on endpoints that ESPN has never agreed to support.

The Endpoint Families and How They Differ

The documentation splits ESPN's surface into distinct API families rather than presenting one flat list. The Site API at site.api.espn.com (v2 and v3) covers scores, news, teams and standings. The Core API at sports.core.api.espn.com (v2 and v3) covers athletes, statistics, odds, play-by-play and what the README calls richer or enriched schemas. Search and athlete profiles live at site.web.api.espn.com. Live data has a CDN-optimized path at cdn.espn.com, and real-time news feeds sit at now.core.api.espn.com. Fantasy leagues use fantasy.espn.com with v3.

The version distinction is not cosmetic. The README points to v2 for detailed data such as play-by-play and odds, and to v3 for athletes and leaders with a richer schema. That means a single feature can require two different hosts and two different response shapes. If you are building a player stats page, you may pull the roster from one family and the statistics from another, then reconcile the identifiers yourself. The documentation does not claim a unified schema across families, and nothing in the material suggests one exists.

Getting a Response: The Curl Examples and Their Traps

The Quick Start section gives four concrete commands. For an NFL scoreboard: curl "https://site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard". For NBA teams: curl "https://site.api.espn.com/apis/site/v2/sports/basketball/nba/teams". For MLB scores on a specific date: curl "https://site.api.espn.com/apis/site/v2/sports/baseball/mlb/scoreboard?dates=20241215". And for NHL standings, the README adds a warning in capitals: use /apis/v2/ rather than /apis/site/v2/, because the latter returns a stub. That single note is the most practically valuable line in the Quick Start, since a stub response can look like an empty season rather than a wrong URL.

The URL pattern is consistent enough to generalize: host, then /apis/ or /apis/site/, then the version, then sports/{sport}/{league}/{resource}. The dates parameter takes a YYYYMMDD string. The README states that most endpoints require no authentication, and that no official rate limits are published, with the caveat that excessive requests may be blocked. That is not a specification. It is a warning that the throttling behavior is unknown, which is a real constraint if you plan to poll a scoreboard on a schedule.

Two Documented Failure Modes Worth Knowing Before You Build

The README calls out two problems that will bite anyone integrating this data. First, some Core API responses contain $ref URLs pointing at sports.core.api.espn.pvt, which is ESPN's internal domain and is not publicly accessible. The documented workaround is string replacement: change .pvt to .com so that sports.core.api.espn.pvt/v2/... becomes sports.core.api.espn.com/v2/.... The README links issue #20 for context. This means a naive JSON walker that follows $ref values will fail on some responses, and the fix is a text substitution you have to apply yourself.

Second, season dates may not match event availability. The dates returned by the seasons/calendar endpoint, such as the start and end of a soccer season, may not align with when scoreboard data actually exists. The README's guidance is to try a date range closer to when matches begin if the scoreboard returns empty for the reported start date, and it links issue #17. For a soccer app, this turns a simple "fetch the season window, then iterate days" loop into a guess-and-check problem. Neither issue has a library-level fix in the material I have; both are integration work the adopter performs.

The Django Service and What the README Does Not Say

The repository includes a Django REST API service for live scores, standings and news, listed in the table of contents as ESPN Service (Django Implementation). The README does not, in the portion I have, show the settings module, the cache backend, the view classes or the URL configuration for that service. It also does not state a polling interval, a retry policy or a timeout. Those are exactly the details that determine whether a proxy service survives an upstream hiccup.

What the README does say is that caching and error handling are best practice, and that rate limits are unpublished. Read together, that puts the burden on you: the project gives you a Django structure and a set of endpoint definitions, and expects you to decide how aggressively to hit ESPN. I would treat the Django component as a scaffold rather than a finished service. The project's own live examples are mobile apps published on Google Play under the Sportly name for basketball, soccer, hockey, American football and baseball, which shows the endpoint documentation has been used in shipped products. It does not tell you anything about the Django service's operational behavior.

Licence Status, Maintenance and the Cost of an Unofficial Dependency

The repository metadata I have does not name a licence. The README carries a disclaimer about non-affiliation with ESPN and a request to follow ESPN's terms of service, but no licence identifier appears in the material supplied. If you intend to reuse the code, particularly the Django service, resolving that is your first step, since the absence of a licence file is not the same as permissive terms. I cannot give legal advice here, and I am not; the factual point is that the licence is unknown from what I can see.

Maintenance cost has two layers. The first is the repository itself: the README solicits support through Buy Me a Coffee, GitHub Sponsors and PayPal, with the stated purpose of keeping the project updated as ESPN changes its API. That is an honest signal that updates are ongoing work rather than a one-time mapping. The second layer is your integration: any endpoint you depend on can change shape or disappear, and the README says so directly. There are no releases retrieved in the metadata I have, so there is no versioned artifact to pin against. Your upgrade path is reading the CHANGELOG and re-checking the endpoint tables, not bumping a dependency version.

Where a Typed Client Wins Instead

The obvious alternative is a language-specific ESPN client library, such as the Python espn-api package, which wraps a subset of ESPN's endpoints behind typed objects and methods. The difference in approach is fundamental. This repository documents raw HTTP surfaces and leaves parsing, pagination and schema drift to you. A client library picks a subset it supports, models the responses as classes, and absorbs some upstream changes in its own releases. You trade coverage for stability.

That trade is not automatically favorable in either direction. A client library cannot document 370 v2 endpoints across 17 sports, and it will not help you when you need an obscure Core API v3 leaders feed. This repository will not give you a Scoreboard object with a .games attribute. If your application needs breadth across many sports and you are willing to own the parsing, the documentation approach fits. If you need a small, stable set of endpoints for one sport and you want the library maintainer to worry about response changes, a client library is the better fit. The README's own framing, optimized for search, developers, AI and LLMs, tells you the project sees itself as a reference layer, not an abstraction layer.

Editorial conclusion

Adopt this repository if you need a starting map of ESPN's endpoint families or a Django scaffold for scores and standings, and you accept that ESPN can change or block anything without notice. Do not adopt it as a long-term stability guarantee, and do not treat the Django service as production-hardened without reading its settings and cache configuration yourself. Before committing, verify three things: whether the licence file exists in the repository (the metadata I have does not name a licence), whether the endpoints you need still respond with the documented JSON shape, and whether the .pvt $ref rewriting applies to your target responses.

Official sources

  1. Issues
  2. Project website
  3. pseudo-r/Public-ESPN-API on GitHub
  4. README
Community notes

Community notes