ESPN Player Stats Scraper - NFL, NBA, MLB, NHL Box Scores
Pricing
from $0.90 / 1,000 saved player rows
ESPN Player Stats Scraper - NFL, NBA, MLB, NHL Box Scores
Scrape ESPN player stats, box scores and game logs for the NFL, NBA, MLB, NHL, WNBA, NCAA and soccer. One row per player per game, with every stat, team, opponent and score. Filter by date, team, player or position.
Pricing
from $0.90 / 1,000 saved player rows
Rating
0.0
(0)
Developer
Harish Garg
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
3
Monthly active users
11 days ago
Last modified
Categories
Share
ESPN Player Stats Scraper — NFL, NBA, MLB, NHL, WNBA, College & Soccer Box Scores
ESPN Player Stats Scraper gets per-player box scores and game logs from ESPN for the NFL, NBA, MLB, NHL, WNBA, NCAA football and basketball, MLS, the Premier League, La Liga and the UEFA Champions League. You get one clean row per player per game, with the player, the position, the team, the opponent, the score, and every stat ESPN publishes for that game.
Pick the leagues and the days, or paste ESPN game links, and download the results as JSON, CSV, Excel, XML or HTML. You can also read them through the Apify API, send them to Google Sheets, Zapier or Make, or let an AI assistant such as Claude or ChatGPT run the scraper for you.
No ESPN account. No API key. No coding needed.
What does ESPN Player Stats Scraper do?
It turns ESPN box scores into a player-level dataset. For each game in your date range, it returns:
- Player — name, ESPN player ID, jersey number, position, headshot, starter flag, and did-not-play reason
- Team and opponent — name, abbreviation, home or away, final score, and winner
- Game — ESPN game ID, date and time, season, week, status, venue, and attendance
- Stats — every stat in the ESPN box score, grouped by category (for example
passing,rushing,batting,pitching,goalies)
A player who appears in more than one stat group, such as a quarterback who also runs, gets one row that holds all of the player's stat groups.
Supported leagues
| Sport | League | Code |
|---|---|---|
| American football | NFL | nfl |
| American football | NCAA Football | ncaaf |
| Basketball | NBA | nba |
| Basketball | WNBA | wnba |
| Basketball | NCAA Men's Basketball | ncaam |
| Basketball | NCAA Women's Basketball | ncaaw |
| Baseball | MLB | mlb |
| Ice hockey | NHL | nhl |
| Soccer | MLS | mls |
| Soccer | English Premier League | epl |
| Soccer | La Liga | laliga |
| Soccer | UEFA Champions League | ucl |
Why scrape ESPN player stats?
- Fantasy sports — Get the full player slate after every game night. Build projections from real game logs, not season averages.
- Sports betting models — Get the player-level history that player-prop models need. Filter to one team, one player, one position, or one stat group.
- Player research and scouting — Compare players across games, opponents and venues over a date range.
- Dashboards, bots and newsletters — Schedule a run after the games end to feed a leaderboard, a Slack or Discord digest, or a weekly recap.
- Sports analytics and machine learning — Build season-long game-log tables for analysis, one month at a time.
How to get ESPN player stats in Apify Console
- Open ESPN Player Stats Scraper in Apify Console and click Try for free.
- In Leagues, select one or more leagues.
- Set Start Date and End Date. Pick a calendar date, or type a relative value such as
7 days. The prefilled range is the last 7 days. - Optional: add a Team, Player Name, Position or Stat Group filter.
- Click Save & Start.
- When the run finishes, open the Output tab. The Player stats view shows each player's stat line, and the Game details view shows the game, the score and the venue. Download the data as JSON, CSV or Excel, or copy the API link.
To get new stats every day, create a Schedule for the run. To send the data to another app, add an Integration or a Webhook.
Input
| Field | Type | Default | Description |
|---|---|---|---|
leagues | array | ["nfl"] | League codes from the table above. Use exactly one league when you set eventIds. |
startDate | string | 7 days | First day. YYYY-MM-DD, or a relative value such as 7 days or 2 weeks. |
endDate | string | today | Last day. YYYY-MM-DD or a relative value. Empty means today, including live games. |
gameStatus | string | all | all (final and live games), post (final games only), or in (live games only). |
teams | array | [] | Team abbreviations (KC, LAL, NYY, LIV) or parts of team names (Chiefs, Man City, Atletico). |
players | array | [] | Player name terms. Partial match. Case and accents do not matter, so mbappe finds Kylian Mbappé. |
positions | array | [] | Position abbreviations (QB, WR, PG, C, SP, G). |
statGroups | array | [] | Stat groups to keep (passing, batting, goalies). |
includeDidNotPlay | boolean | false | Include bench players with no stat line. |
eventIds | array | [] | ESPN game IDs or game page links to get directly. Start and end dates are then ignored. |
maxGames | integer | 100 | The most games one run reads (maximum 500). When more games match, the most recent ones are kept. |
Dates
Relative dates count back from today, in US Eastern time, to match ESPN's game days. Most leagues do not play every day, so a range of a week finds games in any league that is in season.
| You want | startDate | endDate |
|---|---|---|
| Today and the 7 days before it | 7 days | empty |
| Last week's final games | 7 days | 1 day |
| Yesterday | 1 day | 1 day |
| Today, including live games | 0 days | empty |
| One date | 2026-09-27 | 2026-09-27 |
| A fixed range | 2026-09-01 | 2026-09-15 |
One run covers up to 31 days. For a longer range, the run keeps the most recent 31 days. An end date in the future changes to today.
Get a single game
Open the game on espn.com and copy the link from the address bar. Paste the whole link into Game IDs, or only the number after /gameId/. For example, https://www.espn.com/nfl/game/_/gameId/401872953/chargers-bills and 401872953 give the same game.
Input examples
Last week's NFL player stats:
{ "leagues": ["nfl"], "startDate": "7 days", "endDate": "1 day" }
Every quarterback's passing line for today and the 7 days before it:
{ "leagues": ["nfl"], "startDate": "7 days", "positions": ["QB"], "statGroups": ["passing"] }
One NBA player's game log for a month. A player filter searches every game in the range, so set maxGames high enough for all of them:
{ "leagues": ["nba"], "startDate": "2026-03-01", "endDate": "2026-03-31", "players": ["doncic"], "maxGames": 500 }
One MLB team for the last 2 weeks:
{ "leagues": ["mlb"], "startDate": "2 weeks", "teams": ["Yankees"] }
Every goalkeeper in the Premier League and MLS for the last 14 days:
{ "leagues": ["epl", "mls"], "startDate": "14 days", "positions": ["G"] }
A single game from its ESPN link:
{ "leagues": ["nfl"], "eventIds": ["https://www.espn.com/nfl/game/_/gameId/401872953/chargers-bills"] }
Output
Each dataset item is one player in one game. Rows come in game order, oldest game first.
{"gameId": "401872953","league": "nfl","leagueName": "NFL","sport": "football","date": "2026-09-27T17:00Z","dateLocal": "2026-09-27T13:00:00.000-04:00","season": { "year": 2026, "type": 2 },"week": 3,"status": { "state": "post", "description": "Final", "completed": true },"venue": { "name": "Highmark Stadium", "city": "Orchard Park", "state": "NY" },"attendance": 60361,"neutralSite": false,"team": { "id": "2", "name": "Buffalo Bills", "abbreviation": "BUF", "homeAway": "home", "score": 24, "winner": true },"opponent": { "id": "24", "name": "Los Angeles Chargers", "abbreviation": "LAC", "score": 16 },"player": {"id": "3918298","name": "Josh Allen","shortName": null,"jersey": "17","position": "Quarterback","positionAbbreviation": "QB","headshot": "https://a.espncdn.com/i/headshots/nfl/players/full/3918298.png","starter": null,"didNotPlay": false,"dnpReason": null,"ejected": null},"statGroups": ["passing", "rushing", "receiving", "fumbles"],"stats": {"passing": {"completions/passingAttempts": "16/26","passingYards": 204,"yardsPerPassAttempt": 7.8,"passingTouchdowns": 0,"interceptions": 2,"sacks-sackYardsLost": "4-30","adjQBR": 50.8,"QBRating": 54},"rushing": {"rushingAttempts": 8,"rushingYards": 22,"yardsPerRushAttempt": 2.8,"rushingTouchdowns": 2,"longRushing": 8},"receiving": {"receptions": 1,"receivingYards": 1,"yardsPerReception": 1,"receivingTouchdowns": 0,"longReception": 1,"receivingTargets": 1},"fumbles": { "fumbles": 1, "fumblesLost": 1, "fumblesRecovered": 0 }}}
Output fields
| Field | Description |
|---|---|
gameId | ESPN game ID |
league, leagueName, sport | League code, league name, and sport |
date | Game start time in UTC |
dateLocal | Game start time in US Eastern time |
season.year, season.type | Season year, and season type (1 = preseason, 2 = regular season, 3 = postseason) |
week | Week number (football) |
status | state is post (final) or in (live), with ESPN's status text |
venue, attendance, neutralSite | Where the game was played, and the crowd size |
team | The player's team: ID, name, abbreviation, home or away, score, winner |
opponent | The opposing team: ID, name, abbreviation, score |
player | ID, name, jersey, position, headshot, starter, did-not-play flag and reason, ejected |
player.subbedIn, player.subbedOut, player.formationPlace | Soccer only: substitutions and formation slot |
statGroups | The stat groups in this row |
stats | Stats by group, then by ESPN stat name |
Stat groups by sport
| Sport | Stat groups |
|---|---|
| American football | passing, rushing, receiving, fumbles, defensive, interceptions, kickReturns, puntReturns, kicking, punting |
| Baseball | batting, pitching |
| Ice hockey | forwards, defenses, goalies |
| Basketball | stats |
| Soccer | stats |
Stat values
- Plain numbers are numbers (
204,0.252,-2), so you can sum, sort and average them. - Combined values stay text, because they hold two numbers:
"16/26"(completions out of attempts),"4-30"(sacks and yards lost),"24:31"(time on ice). - A stat that ESPN leaves blank is
null, not0. - Baseball innings pitched use the baseball convention:
1.2means one and two-thirds innings. Do not add it as a normal decimal.
Use the ESPN Player Stats Scraper with the Apify API
You can start the scraper and read its results from any language through the Apify API. Get your API token in Apify Console under Settings → API & Integrations, and replace <YOUR_API_TOKEN> below.
HTTP
Run the scraper and get the results in one call:
curl -X POST "https://api.apify.com/v2/acts/hgservices~espn-player-stats-scraper/run-sync-get-dataset-items?format=json" \-H "Authorization: Bearer <YOUR_API_TOKEN>" \-H "Content-Type: application/json" \-d '{ "leagues": ["mlb"], "startDate": "1 day", "endDate": "1 day", "teams": ["NYY"] }'
Change format=json to format=csv or format=xlsx to get a spreadsheet. This endpoint waits up to 300 seconds. For a long date range, start the run, and then read the dataset when the run finishes:
# 1. Start the run. The answer contains data.id (the run ID) and data.defaultDatasetId.curl -X POST "https://api.apify.com/v2/acts/hgservices~espn-player-stats-scraper/runs" \-H "Authorization: Bearer <YOUR_API_TOKEN>" \-H "Content-Type: application/json" \-d '{ "leagues": ["nba", "wnba"], "startDate": "30 days", "maxGames": 500 }'# 2. When the run status is SUCCEEDED, get the rows.curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?format=json" \-H "Authorization: Bearer <YOUR_API_TOKEN>"
JavaScript / Node.js
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });const run = await client.actor('hgservices/espn-player-stats-scraper').call({leagues: ['nba'],startDate: '1 day',endDate: '1 day',});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const row of items) {console.log(row.player.name, row.team.abbreviation, row.stats.stats?.points);}
Python
Use apify-client 3.0 or later.
from apify_client import ApifyClientclient = ApifyClient("<YOUR_API_TOKEN>")run = client.actor("hgservices/espn-player-stats-scraper").call(run_input={"leagues": ["nfl"],"startDate": "7 days","positions": ["QB"],})if run is None:raise RuntimeError("The run was not found.")for row in client.dataset(run.default_dataset_id).iterate_items():print(row["player"]["name"], row["stats"].get("passing"))
Use ESPN player stats in Claude, ChatGPT and other AI assistants
This scraper works as a tool for AI assistants through the Apify MCP server. Your assistant can find the scraper, read its input options, run it, and use the player stats in its answer.
Claude (claude.ai or Claude Desktop) — Go to Settings → Connectors, add a custom connector, and enter https://mcp.apify.com. Sign in to Apify when Claude asks.
Claude Code
$claude mcp add --transport http apify https://mcp.apify.com
ChatGPT — Turn on Developer mode in Settings → Apps & Connectors → Advanced settings. Then create a connector with the MCP server URL https://mcp.apify.com.
Cursor, VS Code and other MCP clients — Add https://mcp.apify.com as a remote MCP server. To give the assistant only this scraper, use https://mcp.apify.com?tools=hgservices/espn-player-stats-scraper.
Then ask in plain language:
Use the ESPN Player Stats Scraper to get last week's NFL quarterback stats, then rank the quarterbacks by passing yards.
Get Luka Doncic's NBA game log for March 2026 and list the points, rebounds and assists for each game.
Which Premier League goalkeepers made the most saves in the last 14 days?
For the best results, tell the assistant the league, the dates, and any team or player you want. This keeps the run fast.
Integrations
Connect the scraper to the tools you already use with Apify integrations: Google Sheets, Slack, Zapier, Make, n8n, Airbyte, Keboola, GitHub and more. You can also use webhooks to call your own endpoint when a run finishes.
Schedule examples
| Use case | Cron | Input |
|---|---|---|
| Nightly game logs | 0 6 * * * | startDate and endDate both 1 day |
| NFL week recap | 0 8 * * 2 | leagues: ["nfl"], startDate: "7 days", endDate: "1 day" |
| Live player tracking | */10 * * * * | startDate: "0 days", gameStatus: "in" |
Run summary
Each run also saves a SUMMARY record in the key-value store, and the Output tab links to it. It shows the number of player rows, the number of games found and read, the dates that the run used, the filters, and notes that explain an empty result. A shortened example:
{"totalPlayerRows": 1041,"gamesFound": 16,"gamesFetched": 16,"gamesSkippedByMaxGames": 0,"gamesWithoutBoxscore": 0,"leagues": ["nfl"],"dateRange": { "startDate": "2026-09-26", "endDate": "2026-10-02" },"filters": { "teams": [], "players": [], "positions": [], "statGroups": [], "gameStatus": "all", "includeDidNotPlay": false },"notes": []}
Tips for fast runs
- Use a team filter. The scraper then reads only the games that the team played.
- Set Maximum Games to limit a large run. If a run finds more games than this limit, it keeps the most recent ones, and the log and the SUMMARY record tell you how many games it skipped.
- Use a short date range for scheduled runs, such as
1 day.
Data notes
- NFL and NCAA Football positions come from the current team roster, because ESPN's football box scores do not list them. A player who has left the team since the game has no position. Football box scores also have no starter flag.
- MLB box scores have no jersey number.
- Soccer substitutes have the position
SUB. - Postponed and cancelled games have no box score, so they give no rows.
- Live games give partial stats that change until the game ends.
- Scheduled games have no player stats, so the scraper never includes them.
FAQ
Do I need an ESPN account or an API key? No. You need only an Apify account.
How far back can I get player stats? ESPN has box scores for many past seasons. For example, NBA games from 2015 work. One run covers up to 31 days, so run the scraper once per month to build a full season.
Why did my run return no rows? Usually the league had no games on those days (an off day, a break or the off-season), or the filters matched nothing. The status message, the run log and the SUMMARY record tell you which one, and what to change.
Can I get stats for a live game?
Yes. Set startDate to 0 days, leave endDate empty, and set gameStatus to in.
Can I search for names with accents?
Yes. Accents do not matter in the player and team filters. Mbappe and Mbappé give the same result, and so do Atletico and Atlético.
Can I combine this data with game scores and schedules?
Yes. The ESPN Sports Scores & Schedules scraper gives one row per game. The league, gameId, team and opponent fields are the same in both datasets, so you can join them.
Is it legal to scrape ESPN? This scraper collects only public sports statistics and never signs in. You are responsible for how you use the data, and for ESPN's terms of use.
Related scrapers
- ESPN Sports Scores & Schedules — game scores, schedules, venues and broadcasts
- ESPN Transactions Scraper — signings, releases, trades and injured list moves
Support
Did you find a bug, or do you need a field or a league that is not here? Open an issue on the Issues tab. Custom solutions are available on request.
This scraper uses public data from ESPN. It is not affiliated with, endorsed by, or sponsored by ESPN.