# ESPN Scraper: Scores, Box Scores, Play-by-Play & Odds (`keelwright/espn-scraper`) Actor

Scores, schedules and results for the NFL, NBA, MLB, NHL, WNBA, college football and basketball, MLS and 10 more soccer leagues from ESPN, with optional box scores, play-by-play, injuries, win probability and opening and closing betting lines.

- **URL**: https://apify.com/keelwright/espn-scraper.md
- **Developed by:** [Keelwright](https://apify.com/keelwright) (community)
- **Categories:** Sports, Developer tools
- **Security:** Limited permissions
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## ESPN Scraper: scores, box scores, play-by-play and betting lines

Get every game ESPN lists for the **NFL, NBA, MLB, NHL, WNBA, college football and basketball, MLS and 10 more soccer leagues** as clean JSON, CSV or Excel: **scores by period, status, teams with records and rankings, venue, attendance, TV channels and the current betting line**. Add **box scores, play-by-play, injury reports, win probability and opening and closing lines** when you need them.

- **22 leagues in one Actor.** NFL, college football (FBS and FCS), UFL, NBA, WNBA, G League, men's and women's college basketball (Division I), MLB, NHL, MLS, NWSL, Liga MX, Premier League, EFL Championship, LaLiga, Bundesliga, Serie A, Ligue 1, Champions League and Europa League.
- **Any day, past or upcoming.** Today's scores, last night's results, next week's schedule or a whole season. All 1,401 NBA games of the 2025-26 season, preseason to the Finals, come back in about 35 seconds.
- **Box scores for every sport.** Passing, rushing, receiving and defense in football; batting and pitching with innings pitched in baseball; time on ice and save percentage in hockey; lineups, formations and substitutes in soccer.
- **Play-by-play.** Every play with period, clock, team and running score. Football plays carry the drive, down, distance and field position.
- **Opening and closing lines.** Moneyline, spread and total with their opening and closing prices, kept after the game, plus ESPN's win probability before kick-off.
- **Injury reports.** Both teams' injured players with status, injury and expected return date.
- **Results in date order**, ready for a spreadsheet or a model, and **only changed games** on a schedule for live scores.

### What can I use ESPN data for?

- **Betting models and backtesting**: final scores with opening and closing moneylines, spreads and totals.
- **Fantasy sports and DFS**: player box scores, injury reports, and probable pitchers and goalies.
- **Live score apps, bots and widgets**: scores, periods and clocks every few minutes, saving only the games that changed.
- **Analytics and research**: season results, team statistics and play-by-play for models, dashboards and papers.
- **Content and media**: schedules, results, TV channels and recap headlines for newsletters, social posts and websites.

### How to scrape ESPN scores

1. Click **Try for free**.
2. Pick the **Leagues**.
3. Set the **From date** and **To date**: a date such as `2025-09-04`, or a period such as `7 days`, counted back from today in **From date** and ahead in **To date**. Leave both empty for today's games.
4. Optionally filter by **Teams**, **Game status** or **Part of the season**, and tick **Box score**, **Play-by-play**, **Opening and closing lines** or **Injury report**.
5. Click **Start** and download the results as JSON, CSV, Excel or HTML, or read them through the API.

### Input examples

Today's games in the four major leagues:

```json
{
    "leagues": ["nfl", "nba", "mlb", "nhl"]
}
```

Yesterday's and today's finished NBA games with box scores and closing lines:

```json
{
    "leagues": ["nba"],
    "dateFrom": "1 day",
    "statuses": ["final"],
    "includeBoxScore": true,
    "includeOdds": true
}
```

The next seven days of NFL and college football with lines and injury reports:

```json
{
    "leagues": ["nfl", "college-football"],
    "dateTo": "7 days",
    "includeOdds": true,
    "includeInjuries": true
}
```

One team's season, regular season and playoffs:

```json
{
    "leagues": ["nba"],
    "teams": ["Lakers"],
    "dateFrom": "2025-10-01",
    "dateTo": "2026-06-30",
    "seasonTypes": ["regular", "postseason"]
}
```

Live scores: run this every 5 minutes on a [schedule](https://docs.apify.com/platform/schedules) to get only the games whose score or status changed.

```json
{
    "leagues": ["nfl", "college-football"],
    "statuses": ["live", "final"],
    "onlyChanged": true
}
```

### What data do you get?

One row per game. Every row has:

| Field                                                         | What it holds                                                                                                                                                  |
| ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gameId`, `url`                                               | ESPN's game id and the game's page on espn.com                                                                                                                 |
| `league`, `sport`, `season`, `week`                           | League key and name, the season year and part (`preseason`, `regular`, `postseason`, `other`) and the football week                                            |
| `date`                                                        | Start time in UTC                                                                                                                                              |
| `status`, `statusDetail`                                      | `scheduled`, `live`, `final`, `postponed`, `delayed`, `suspended` or `cancelled`, and ESPN's own text such as `Final/OT` or `Sun, October 25th at 8:20 PM EDT` |
| `period`, `clock`                                             | Current or last period, inning or half, and the game clock while live                                                                                          |
| `home`, `away`                                                | Team id, name, abbreviation, score, score per period, record, college ranking, soccer form, team statistics, leaders and probable pitchers or goalies          |
| `winner`                                                      | `home`, `away` or `draw` once the game is final                                                                                                                |
| `venue`, `neutralSite`, `attendance`, `weather`, `broadcasts` | Stadium and city, crowd, forecast for upcoming outdoor games, TV and streaming channels                                                                        |
| `note`, `series`, `headline`                                  | Playoff round (`ALCS - Game 4`), series score and the recap headline                                                                                           |
| `odds`                                                        | The line ESPN shows (DraftKings): moneyline, spread and total in American odds, and the favorite                                                               |
| `keyEvents`                                                   | Soccer goals, cards and substitutions with the minute                                                                                                          |

With the extra options:

| Option                        | Adds                                                                                                                      |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Box score**                 | `boxScore`: team totals, every player's stat line (including players who did not play, with the reason) and the officials |
| **Play-by-play**              | `playByPlay`: every play in order                                                                                         |
| **Opening and closing lines** | `odds` with opening prices for every game, finished games too, and `winProbability` before the game                       |
| **Injury report**             | `injuries`: player, position, status, injury, expected return and when ESPN updated it                                    |

#### Output example

A finished NFL game with every option on (team statistics, players, plays and injuries cut to one or two entries):

```json
{
    "gameId": "401873008",
    "url": "https://www.espn.com/nfl/game/_/gameId/401873008/commanders-49ers",
    "league": {
        "key": "nfl",
        "name": "NFL",
        "abbreviation": "NFL"
    },
    "sport": "football",
    "season": {
        "year": 2026,
        "type": "regular",
        "label": "regular-season"
    },
    "week": 6,
    "date": "2026-10-20T00:15:00.000Z",
    "status": "final",
    "statusDetail": "Final",
    "period": 4,
    "clock": null,
    "name": "Washington Commanders at San Francisco 49ers",
    "shortName": "WSH @ SF",
    "home": {
        "id": "25",
        "name": "San Francisco 49ers",
        "shortName": "49ers",
        "abbreviation": "SF",
        "location": "San Francisco",
        "score": 23,
        "linescores": [13, 7, 3, 0],
        "winner": true,
        "record": "6-0",
        "rank": null,
        "form": null,
        "statistics": {},
        "leaders": [
            {
                "category": "rushingYards",
                "player": "Christian McCaffrey",
                "playerId": "3117251",
                "value": "16 CAR, 64 YDS, 2 TD"
            },
            {
                "category": "receivingYards",
                "player": "Mike Evans",
                "playerId": "16737",
                "value": "3 REC, 94 YDS"
            }
        ],
        "probables": []
    },
    "away": {
        "id": "28",
        "name": "Washington Commanders",
        "shortName": "Commanders",
        "abbreviation": "WSH",
        "location": "Washington",
        "score": 17,
        "linescores": [3, 0, 7, 7],
        "winner": false,
        "record": "1-4-1",
        "rank": null,
        "form": null,
        "statistics": {},
        "leaders": [
            {
                "category": "passingYards",
                "player": "Jayden Daniels",
                "playerId": "4426348",
                "value": "29/40, 300 YDS, 2 TD"
            }
        ],
        "probables": []
    },
    "winner": "home",
    "venue": {
        "name": "Levi's Stadium",
        "city": "Santa Clara",
        "state": "CA",
        "country": "USA",
        "indoor": false
    },
    "neutralSite": false,
    "attendance": 71561,
    "weather": null,
    "broadcasts": ["ESPN", "ABC"],
    "note": null,
    "series": null,
    "headline": "Brock Purdy and the offense staked San Francisco to a big lead. The defense made sure the 49ers remained undefeated.",
    "odds": {
        "provider": "DraftKings",
        "details": "SF -7.5",
        "favorite": "home",
        "moneyline": {
            "home": -410,
            "away": 320,
            "draw": null,
            "homeOpen": -250,
            "awayOpen": 205,
            "drawOpen": null
        },
        "spread": {
            "home": -7.5,
            "away": 7.5,
            "homeOdds": -102,
            "awayOdds": -118,
            "homeOpen": -5.5,
            "awayOpen": 5.5,
            "homeOpenOdds": -110,
            "awayOpenOdds": -110
        },
        "total": {
            "line": 51.5,
            "overOdds": -110,
            "underOdds": -110,
            "openLine": 50.5,
            "openOverOdds": -110,
            "openUnderOdds": -110
        }
    },
    "winProbability": null,
    "injuries": [
        {
            "side": "home",
            "team": "SF",
            "player": "Upton Stout",
            "playerId": "4565200",
            "position": "CB",
            "status": "Questionable",
            "injury": "Shoulder - AC Joint - Sprain",
            "returnDate": "2026-10-25",
            "updated": "2026-10-20T23:51:00.000Z"
        }
    ],
    "boxScore": {
        "teams": [
            {
                "side": "away",
                "team": "WSH",
                "statistics": {
                    "firstDowns": 19,
                    "firstDownsPassing": 13,
                    "firstDownsRushing": 2,
                    "firstDownsPenalty": 4,
                    "thirdDownEff": "3-12",
                    "fourthDownEff": "1-3"
                }
            },
            {
                "side": "home",
                "team": "SF",
                "statistics": {
                    "firstDowns": 20,
                    "firstDownsPassing": 9,
                    "firstDownsRushing": 11,
                    "firstDownsPenalty": 0,
                    "thirdDownEff": "7-14",
                    "fourthDownEff": "2-2"
                }
            }
        ],
        "players": [
            {
                "side": "away",
                "team": "WSH",
                "playerId": "4426348",
                "name": "Jayden Daniels",
                "jersey": "5",
                "position": null,
                "starter": null,
                "didNotPlay": false,
                "reason": null,
                "stats": {
                    "passing": {
                        "completions": 29,
                        "passingAttempts": 40,
                        "passingYards": 300,
                        "yardsPerPassAttempt": 7.5,
                        "passingTouchdowns": 2,
                        "interceptions": 0,
                        "sacks": 4,
                        "sackYardsLost": 39,
                        "adjQBR": 44.6,
                        "QBRating": 110.4
                    },
                    "rushing": {
                        "rushingAttempts": 4,
                        "rushingYards": 10,
                        "yardsPerRushAttempt": 2.5,
                        "rushingTouchdowns": 0,
                        "longRushing": 4
                    }
                }
            }
        ],
        "officials": ["Trawick Boger (Field Judge)", "Adrian Hill (Referee)"]
    },
    "playByPlay": [
        {
            "period": 1,
            "clock": "14:55",
            "team": "SF",
            "type": "Pass Reception",
            "text": "B.Purdy pass short left to C.McCaffrey to SF 42 for 6 yards (A.Robertson).",
            "homeScore": 0,
            "awayScore": 0,
            "scoringPlay": false,
            "drive": 1,
            "down": 1,
            "distance": 10,
            "yardLine": "SF 36"
        }
    ],
    "scrapedAt": "2026-10-21T16:17:21.518Z"
}
```

The **Games** and **Betting lines** tabs of the dataset show the main columns as tables. Open a row or export JSON for everything.

### How much does it cost?

**Pay-per-event pricing starts on 20 November 2026.** Until then the Actor costs only the Apify platform usage of your runs, which is small.

From 20 November 2026 you pay only for the games you get (pay per event); Apify platform usage is included.

| What              | Price                 |
| ----------------- | --------------------- |
| Game              | $3.00 per 1,000 games |
| Game with details | $6.00 per 1,000 games |
| Run start         | $0.05 per 1,000 runs  |

A game costs the higher price only when it comes with at least one of the extra parts you asked for. An upcoming game that has no box score yet, or a game ESPN has no game page for, costs the lower price.

Examples:

- One evening of NBA and NHL games (about 20 games): about **$0.06**.
- All 1,401 NBA games of the 2025-26 season: about **$4.20**.
- One NFL week with box scores, play-by-play, lines and injury reports (about 15 games): about **$0.09**.

Cap any run with **Max results** or with the maximum cost per run in the run options; the run stops cleanly at the limit. Apify's free plan includes $5 of monthly credit, enough for about 1,600 games.

### Tips

- **Days follow US Eastern time**, as ESPN lists them: a 10:30 pm game in New York belongs to that day, although its `date` (UTC) is already the next day.
- **Box scores and play-by-play** come for games that have started. For upcoming games, use the lines and the injury report.
- **Closing lines stay.** The scoreboard drops the line once a game is over; **Opening and closing lines** keeps it for finished games, with the opening prices.
- **The injury report is the current one.** For a past game it shows today's report, not the one at game time.
- **Season years follow ESPN.** Basketball and hockey seasons carry the year they end (the 2025-26 NBA season is `2026`); football, baseball and soccer seasons carry the year they start. The NBA play-in counts as `postseason`, all-star games as `other`.
- **College sports** cover every FBS and FCS football game and every Division I basketball game, not only ranked teams. A game between an FBS and an FCS team is saved once.
- **Long ranges.** One run reads up to 1,100 league-days, about three seasons of one league. Split longer ranges into several runs.
- **How far back.** Scores go back to at least 2005 for the NFL, MLB, NHL, college football and the Premier League, and to 1999 for the NBA. Box scores and play-by-play can be thinner for older games; a part ESPN doesn't have is `null`.
- **Integrations.** Send results to Google Sheets, Slack, Zapier, Make or your own webhook with Apify [integrations](https://apify.com/integrations), or call the Actor through the [API](https://docs.apify.com/api/v2).

### FAQ

**How fast is it?**
A day of several leagues takes a few seconds. A whole season of one league takes about 35 seconds. With every extra part on, 50 games take about 10 seconds.

**Which bookmaker are the lines from?**
The lines ESPN shows, currently from DraftKings. They are American odds: `-150` means you risk 150 to win 100, `+130` means you win 130 on 100.

**Can I get live scores?**
Yes. Schedule a run every few minutes with **Only new or changed games** on. Each run returns only the games whose status, score, period or start time changed since the last run with the same settings.

**Do I need a proxy?**
No. ESPN answers Apify's servers directly. The proxy option is there in case that changes.

**Is it legal to scrape ESPN?**
This Actor reads publicly available sports data: scores, statistics, published betting lines and the public names of professional and college athletes. It does not log in or collect private information. Check the source's terms and your local laws for your use case, especially for commercial use.

**Something is missing or broken?**
Open an issue in the **Issues** tab with the run link, and it will be looked at.

*ESPN Scraper is an independent tool. It is not affiliated with, endorsed by or connected to ESPN, Inc., or any league or team. Betting lines are shown for information only.*

# Actor input Schema

## `leagues` (type: `array`):

The leagues to read. Each league adds one request per day, so pick only the ones you need. Empty means NFL, NBA, MLB and NHL.

## `dateFrom` (type: `string`):

First day to include, as ESPN dates games (US Eastern time). A date such as 2025-09-04, or a period back from today such as 7 days. Empty means today. One run reads up to 1,100 league-days (about three seasons of one league).

## `dateTo` (type: `string`):

Last day to include. A date, or a period ahead of today such as 7 days for upcoming games. Empty means today, or the From date when that is in the future.

## `teams` (type: `array`):

Only games of these teams: a nickname (Lakers), a full name (Los Angeles Lakers), an abbreviation (LAL) or an ESPN team id. Leave empty for all teams.

## `statuses` (type: `array`):

Only games with these statuses. Leave empty for all.

## `seasonTypes` (type: `array`):

Only games from these parts of the season. Leave empty for all.

## `includeBoxScore` (type: `boolean`):

Team totals and every player's stat line: passing, rushing and receiving in football, batting and pitching in baseball, time on ice for hockey, lineups, formations and substitutes in soccer. Includes players who did not play and the officials. For started and finished games.

## `includePlayByPlay` (type: `boolean`):

Every play with period, clock, team, description and running score. Football plays carry the drive, down, distance and field position; soccer gives goals, cards and substitutions.

## `includeOdds` (type: `boolean`):

Moneyline, spread and total with the opening and closing prices (kept after the game, unlike the scoreboard's), plus ESPN's win probability before the game. Without this option, rows still have the current line while ESPN shows one, mostly before and during games.

## `includeInjuries` (type: `boolean`):

Both teams' injured players with status (out, doubtful, questionable, day-to-day), injury and expected return date.

## `onlyChanged` (type: `boolean`):

Save only games that are new or whose status, score, period or start time changed since the previous run with the same settings. Use it with a schedule (for example every 5 minutes) to follow live scores without paying for unchanged rows.

## `maxItems` (type: `integer`):

Stop after this many games. 0 means no limit. A full NFL Sunday has about 14 games; a busy college basketball day has 150 or more.

## `maxConcurrency` (type: `integer`):

How many days or games are loaded at the same time.

## `proxyConfiguration` (type: `object`):

Not needed in most cases: ESPN answers Apify's servers directly. Turn it on only if runs start failing.

## Actor input object example

```json
{
  "leagues": [
    "nba",
    "nfl",
    "mlb",
    "nhl",
    "wnba",
    "mls",
    "premier-league"
  ],
  "dateFrom": "2 days",
  "teams": [],
  "statuses": [],
  "seasonTypes": [],
  "includeBoxScore": false,
  "includePlayByPlay": false,
  "includeOdds": false,
  "includeInjuries": false,
  "onlyChanged": false,
  "maxItems": 50,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `games` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "leagues": [
        "nba",
        "nfl",
        "mlb",
        "nhl",
        "wnba",
        "mls",
        "premier-league"
    ],
    "dateFrom": "2 days",
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("keelwright/espn-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "leagues": [
        "nba",
        "nfl",
        "mlb",
        "nhl",
        "wnba",
        "mls",
        "premier-league",
    ],
    "dateFrom": "2 days",
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("keelwright/espn-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "leagues": [
    "nba",
    "nfl",
    "mlb",
    "nhl",
    "wnba",
    "mls",
    "premier-league"
  ],
  "dateFrom": "2 days",
  "maxItems": 50
}' |
apify call keelwright/espn-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,keelwright/espn-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/4BHpo1QcmQBbe5Xtj/builds/oLcFpjUINHbL6vyOv/openapi.json
