MLB Stats Scraper & Stat Change Monitor - Hitting, Pitching
Pricing
from $3.65 / 1,000 stat line returneds
MLB Stats Scraper & Stat Change Monitor - Hitting, Pitching
For fantasy baseball, betting models and analytics: season hitting, pitching and fielding from the official MLB Stats API - 4,223 stat lines for 2026 (732 hitting, 848 pitching, 2,643 fielding). Innings pitched are handled as thirds, not decimals. Monitoring returns only lines that changed.
Pricing
from $3.65 / 1,000 stat line returneds
Rating
0.0
(0)
Developer
NeverEmpty
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
MLB Stats Scraper & Stat Change Monitor — Hitting, Pitching, Fielding
Built for fantasy baseball, betting models and season-long analytics: every MLB season stat line from the official MLB Stats API as one flat row — the player, team, league, position, the rank the API assigns, and every stat it publishes for that group.
A whole season, not a sample. For 2026 the API held 732 hitting, 848 pitching and 2,643 fielding lines — 4,223 lines in all — and this Actor pages through the entire group, 100 at a time, until the API's own total is reached. The player pool is yours to choose: 2026 hitting holds 732 lines under ALL but the 2025 group holds 145 under QUALIFIED, so leaving a default in place quietly shows you a fraction of the league.
The two things that silently ruin baseball data are fixed here. Innings are thirds, not decimals — 20.1 is 20 innings and one out, so every innings figure comes back three ways ("20.1", 61 outs, 20.3333). And a rate the API could not compute (.---) comes back as null, never 0: on the 2026 pitching fixture 39 of 60 lines had at least one.
Turn monitoring on and every later run returns only the stat lines that have actually changed, so you are never charged for the same line twice. Run it daily through the season and pay only for the players who played. Export as JSON, CSV or Excel.
Unofficial Actor. Not affiliated with or endorsed by MLB. It reads MLB's public Stats API — no key, no login, no HTML parsing.
What it does
- ⚾ Three stat groups. Hitting, pitching and fielding. For the 2026 season the API held 732 hitting, 848 pitching and 2,643 fielding lines.
- 🔁 Change monitoring. The remembered key is the player plus the group plus every number in their line, so a player comes back only when a stat actually moved. Run it daily during the season and pay only for the players who played.
- 👥 The player pool matters, and you choose it. The 2026 hitting group holds 732 lines under
ALL; the 2025 group holds 145 underQUALIFIED— the pool changes the answer by roughly a factor of five. An Actor that leaves the default in place quietly shows you a fraction of the league. - 📄 Full pagination. Reads through the whole group, 100 at a time, and stops when the API's own total is reached.
🔴 Two things this Actor gets right that are easy to get wrong
1. Innings are thirds, not decimals. In baseball 20.1 means 20 innings and one out — 20⅓ — not 20.1. Summing or averaging the raw number is silently wrong. Every innings figure is returned three ways:
| Column | Value for 20.1 |
|---|---|
inningsPitchedRaw | "20.1" (exactly as the API prints it) |
inningsPitchedOuts | 61 |
inningsPitchedDecimal | 20.3333 |
The same applies to fielding innings. If the API ever prints a first decimal above 2, that is not a thirds notation, and the Actor returns null rather than guessing.
2. Unavailable rates are not zero. When a rate cannot be computed, the API prints .--- or -.--. Turning that into 0 invents a fact — a pitcher with no stolen-base attempts against him is not a pitcher with a 0% rate. Those come back as null, with the original text kept in a …Raw column. On the 2026 pitching fixture, 39 of 60 lines had at least one.
What this Actor refuses to guess
The MLB API answers HTTP 200 with an empty stats array for a stat group it does not know — which looks exactly like "this player has no stats". Only the three verified groups are accepted, and an unknown one is refused with an explanation rather than reported as an empty result.
A season that has not been played returns a genuine zero (2030 gives totalSplits: 0), and that is reported as the API's own answer. Empty seasons, unknown groups, filters that matched nothing and unreadable responses each come back as their own row with the reason, and none are charged.
What you get in every row
| Field | What it is |
|---|---|
season, statGroup, playerPool | What was asked for, on every row |
playerId, playerName, firstName, lastName | The player and their MLB id |
teamId, teamName, leagueId, leagueName | Where they played |
position, positionAbbreviation, positionType | Their position |
statRank | The rank the API assigns within the group |
teamsPlayedFor | More than 1 means they were traded mid-season |
| (the stats) | Every stat the API publishes, flattened: homeRuns, avg, ops, era, whip, assists, putOuts … |
…Raw | Kept whenever a value could not be turned into a number |
statKey | Changes when any stat changes — this is what monitoring compares |
Configure the run
{ "statGroups": ["hitting"], "season": 2026, "playerPool": "ALL", "maxPlayers": 200 }
Follow one team through the season, paying only for changes:
{ "statGroups": ["hitting", "pitching"], "teams": ["Dodgers"], "monitoringMode": true }
Qualified hitters only, top 50 by the API's rank:
{ "statGroups": ["hitting"], "playerPool": "QUALIFIED", "maxRank": 50 }
Input reference
Every field is optional; the defaults read 2026 hitting for all players.
| Field | Type | Default | What it does |
|---|---|---|---|
statGroups | array | ["hitting"] | Which stat groups to read. The MLB API answers HTTP 200 with an empty stats array for a group it does not know, which looks exactly like 'this player has no stats',… |
season | integer | 2026 | Which season to read. Seasons that have not been played return zero rows, which is the API's own honest answer and is reported as such rather than as a failure. |
playerPool | string | ALL | Which players are included. This changes the result a lot: for 2026 hitting the API returned 732 players for ALL but only 140 for QUALIFIED (players who reached the… |
maxPlayers | integer | 200 | How many rows to return. One row is one player in one stat group. You are charged for the rows you actually receive. For reference, 2026 held 732 hitting, 848… |
monitoringMode | boolean | false | Off = return every line for the groups you picked. On = remember the exact numbers already returned and, on later runs, return a player's line again only when one of… |
resetMonitoringState | boolean | false | Clear the remembered lines before this run, so everything counts as new again. |
teams | array | [] | Keep a line only if the team name contains one of these (case-insensitive, partial). Example: Yankees, Dodgers. |
players | array | [] | Keep a line only if the player's full name contains one of these (case-insensitive, partial). Example: Ohtani, Judge. |
positions | array | [] | Keep a line only if the position or its abbreviation contains one of these (case-insensitive, partial). Example: Pitcher, P, Catcher, C. |
leagues | array | [] | Keep a line only if the league name contains one of these. Example: American League, National League. |
minGamesPlayed | integer | 0 | Keep a line only if the player appeared in at least this many games. 0 = no limit. Lines with no games-played figure are kept, because unknown is not the same as zero. |
maxRank | integer | 0 | The API assigns each line a rank within the group. 0 = no limit. Lines with no rank are kept. |
keywords | array | [] | Keep a line only if one (Any) or all (All) of these appear in the player, team, position, league or group name. |
keywordMatch | string | any | Any = at least one keyword. All = every keyword. |
excludeKeywords | array | [] | Drop a line if any of these appear in the same fields. |
useProxy | boolean | false | Off by default: the official MLB Stats API answered 200 from a plain Apify datacentre address when this Actor was built (2026-09-06). If it starts answering 403, 429… |
Pricing
Pay per result: you are charged for the stat lines you actually receive. Rows that only explain why there is nothing (no-results, no-such-group, unreadable, no-filter-match, no-stat-change) are never charged.
Every number in this README is checked
The fixtures in test/fixtures/ are the real responses this Actor was built from (2026-09-06). The test suite re-counts every figure quoted above — 60, 732, 848, 2643, 145, 39, 20.1, 61, 20.3333 — so if the API changes, the tests fail rather than the data going quietly wrong.