Tony Wang7 min readHow to Scrape MLB Data in 2026 (API & Python)
Get MLB data in 2026 — MLB's own undocumented Stats API, no-code tools, or a structured API — with real JSON examples and the legal basics.
MLB already has a free way to get baseball data: a widely used, keyless JSON API at statsapi.mlb.com that powers MLB.com itself and backs the community's popular MLB-StatsAPI and pybaseball Python libraries. The catch is that MLB has never officially published it — there's no developer portal, no changelog, and no guarantee a field won't move or disappear on the next deploy. This guide covers that undocumented endpoint, no-code tools, and a structured, documented MLB API, plus what MLB's own Terms of Use actually say about reproducing and redistributing its data.
Why scrape MLB data?
MLB's schedule, standings, roster, and stats data feeds a recognizable set of products:
- Fantasy baseball tools — rosters, player stats, and matchup schedules for lineup decisions.
- Sports-betting and odds context — game schedules, scores, and standings alongside odds data from elsewhere.
- Historical and analytics research — league and player stat splits by season for performance analysis.
- Fan and media apps — live scoreboards, standings widgets, and transaction trackers.
- Cross-league sports coverage — pair MLB's baseball-specific depth with ESPN's multi-sport scoreboards or SofaScore's live-event coverage for a broader sports data pipeline.
Is it legal to scrape MLB data?
Option 1: MLB's own undocumented Stats API (and why it's risky to rely on)
statsapi.mlb.com requires no authentication at all — no API key, no bearer token, just a GET request:
curl "https://statsapi.mlb.com/api/v1/schedule?sportId=1&date=2026-04-15"
# team lookups work the same way:
curl "https://statsapi.mlb.com/api/v1/teams?sportId=1"
This is real, it's free, and it's exactly what the community-maintained MLB-StatsAPI and pybaseball Python packages call under the hood — they're widely used for hobbyist and analytics projects and both make clear they're unofficial, unaffiliated wrappers around this same endpoint. So the honest framing isn't "MLB has no API" — it does, and it's been keyless and open for years. The problem is what "undocumented" actually costs you in production:
- No official documentation, ever. Every endpoint, parameter, and field name in circulation (
sportId,hydrate, nestedteams.home/teams.awayshapes) was reverse-engineered by third parties, not published by MLB. - No changelog, no stability guarantee. Because it's not a sanctioned developer product, MLB can rename, restructure, or drop fields between deploys with zero notice to anyone depending on it.
- No published rate limits. There's nothing to design a retry/backoff strategy around beyond community trial and error.
- Schema depth varies by call. Nested resources like boxscores or play-by-play need
hydrateparameters community docs had to figure out by inspection, not a spec. - You're one MLB.com redesign away from a broken pipeline, with no support channel to ask what changed.
Option 2: No-code tools
Generic no-code scrapers and marketplace actors can pull a single day's scoreboard or a standings table for a one-off export. They mostly wrap the same undocumented statsapi.mlb.com endpoints underneath — so they inherit the same schema-drift risk as Option 1 — and they don't solve normalizing MLB alongside other sports platforms in one schema.
Option 3: A structured MLB API (via Crawlora)
A structured MLB API gives you a documented, normalized schema instead of trusting an endpoint MLB could reshape without warning — one auth header, consistent JSON, alongside other sports platforms like ESPN and SofaScore. Pull a team's schedule:
curl -G "https://api.crawlora.net/api/v1/mlb/schedule" \
-H "x-api-key: $CRAWLORA_API_KEY" \
--data-urlencode "team_id=147" \
--data-urlencode "start_date=2026-04-01" \
--data-urlencode "end_date=2026-04-07"
{
"code": 200,
"data": {
"start_date": "2026-04-01",
"end_date": "2026-04-07",
"team_id": 147,
"total_games": 6,
"games": [],
"fetched_at": "2026-08-09T12:00:00Z",
"source_url": "https://statsapi.mlb.com/api/v1/schedule"
}
}
Then pull player or team stats by id in Python (real fields — check the docs for the full splits[] shape):
import requests
h = {"x-api-key": "YOUR_API_KEY"}
base = "https://api.crawlora.net/api/v1/mlb"
teams = requests.get(f"{base}/teams", headers=h, params={"season": 2026}).json()["data"]["teams"]
stats = requests.get(
f"{base}/player-stats", headers=h,
params={"id": 660271, "season": 2026, "group": "hitting"},
).json()["data"]
print(stats["player_id"], stats["season"], stats["group"], stats["total"])
Team-level stats follow the same shape (a real, empty-in-preseason response from the live endpoint):
{
"code": 200,
"data": { "team_id": 147, "season": 2026, "group": "hitting", "splits": [] }
}
Roster, standings, transactions, and game-detail endpoints follow the same id-in, JSON-out pattern: /mlb/team-roster (team_id, season, roster_type), /mlb/standings (season, type), /mlb/transactions (start_date, end_date, team_id, player_id), and /mlb/game / /mlb/game-boxscore / /mlb/game-play-by-play (id — a game_id from a schedule or transactions response). Store one row per game or per player-season and re-run on a schedule.
What you can collect
Public MLB Stats API data, normalized: schedule (by date, date range, or team, with total_games and a games array); standings (grouped by season and type); teams (full season roster of franchises); team roster (by team and season, with roster_type); player detail and player stats (by id, season, and stat group — hitting, pitching, fielding); team stats (same group/season split at the team level); league-wide stat leaders (league-stats, by season and group); game detail, box score, and play-by-play (by game_id, with plays[], linescore, and decisions); and transactions (trades, signings, and roster moves by date range, team, or player).
Limitations and common challenges
- Two different legal surfaces.
mlb.com's Terms of Use govern the website and its content;statsapi.mlb.comhas no published terms of its own — scope commercial or large-scale use carefully against MLB's actual ToU rather than assuming keyless access means unrestricted use. - The undocumented endpoint can change without notice. If you build directly on
statsapi.mlb.com, budget for silent field renames and no changelog to check. - Per-id fan-out. A full game record (boxscore, play-by-play, decisions) is one call per
game_id; a season's worth of player stats means iterating ids from a roster or search response. - Preseason and off-season data is thin. Stat-split and schedule responses can legitimately return empty arrays outside the season, as shown above — that's not a broken call.
- Public data only. This collects what MLB already serves through its own live endpoints — never a way to bypass MLB's licensing for commercial redistribution of its content.
Where this gets used
- Fantasy baseball tools — lineup and waiver decisions from rosters and stat splits.
- Analytics and research — historical player and team performance by season.
- Sports-media dashboards — live scoreboards, standings, and transaction feeds.
- Cross-league sports products — MLB's baseball depth alongside ESPN's multi-sport scoreboards or SofaScore's live-event coverage.
Sources
Start collecting
Try it first, free: run any public URL through the Free Web Scraper, or check whether a site blocks bots with the Anti-Bot Checker — no signup.
Test the schedule, standings, and player-stats endpoints in the Playground, check the schema in the API docs, and review pricing. ESPN is the better fit for cross-league scoreboards and news across multiple sports; MLB is the deeper baseball-specific source once you need season-long stat splits, rosters, or play-by-play. SofaScore rounds out live-event coverage for the sports outside MLB's own scope. On the gaming side of the same hub cluster, how to scrape PlayStation Store covers console-catalog pricing and deals. Once you have the schedule, how to scrape Ticketmaster covers the ticket-market side of those same games. See also how to choose a web scraping API and is web scraping legal.
Part of our how-to-scrape guide series — every platform we cover, in one index.
Frequently asked questions
Does MLB have an official public API?
Not a self-serve, documented one. MLB runs a free, keyless JSON API at statsapi.mlb.com that powers MLB.com itself and community libraries like MLB-StatsAPI and pybaseball, but MLB has never published official documentation, a changelog, or a developer portal for it — it's reverse-engineered by the community, not a sanctioned product.
Is it legal to use statsapi.mlb.com?
It's a different question from mlb.com's Terms of Use, which restrict reproducing or redistributing MLB Digital Properties without written permission. statsapi.mlb.com itself has no published terms a third party can point to. Non-commercial, personal use of data MLB already serves keyless is low-risk in practice; get your own legal read before anything commercial or large-scale. This isn't legal advice.
Can I rely on statsapi.mlb.com for a production app?
You can, but budget for risk: no changelog, no SLA, and fields can be renamed or restructured without notice since MLB never committed to a stable schema for third-party use.
What data can I get from the MLB Stats API?
Schedule, standings, teams, team rosters, player and team stats by season and group (hitting/pitching/fielding), league-wide stat leaders, game detail with box scores and play-by-play, and transactions (trades, signings, roster moves).
How do I look up a specific player's stats?
Resolve the player's MLB id from a team roster response, then call player-stats with that id, a season, and a stat group (e.g. hitting or pitching).
Does the API cover live, in-progress games?
Game and play-by-play endpoints return the current state of a game by game_id, including linescore and decisions, so they reflect live or completed games depending on when you call them.
How is MLB different from ESPN or SofaScore in this series?
ESPN and SofaScore cover scoreboards and standings across many sports and leagues at once. MLB's structured API goes deeper into a single sport — full season stat splits, rosters, and play-by-play — for products that need baseball-specific depth rather than cross-league breadth.