# ESPN Scraper: Scores, Standings, Stats, Odds (`automation_craft/espn-sports-scraper`) Actor

Scrape ESPN for game scores, fixtures, standings, team rosters, box scores, league news and the posted betting line, across the NFL, NBA, MLB, NHL, college sports and 350 more leagues with no API key. Rows carry teams, score, status, venue, broadcast and ids. JSON, CSV, Excel or API, billed per row.

- **URL**: https://apify.com/automation\_craft/espn-sports-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** Sports, News, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 games

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### ESPN Scraper: Scores, Standings, Stats, Odds

This **ESPN scraper** turns ESPN's public sports data into clean rows: scores and fixtures, standings tables, team
directories, rosters, box scores, league news and the betting line ESPN posts before a game. No API key, no login,
no browser. 44 leagues sit in the dropdown and all 356 leagues ESPN publishes are reachable by code, from the NFL
and the NBA to Serie A, the Copa Libertadores, the UFC, Formula 1 and NCAA basketball.

You pay for the rows you receive. Name a memory and a scheduled run pays for a game once, then only pays again if
the score or the line actually moved.

### Quick start

1. Click **Try for free**.
2. Choose **What to scrape**: scores, odds, standings, teams, rosters, box scores or news.
3. Pick your **Leagues** from the dropdown, or type any ESPN league code (`ger.2`, `usa.nwsl`) into **Other leagues**.
4. For scores, odds and box scores, set the date window: **Days back** and **Days ahead**, or an explicit
   **Date from** and **Date to**.
5. Set **Maximum rows** while you are experimenting, then click **Start**. Results appear in the dataset and export
   as JSON, CSV, Excel or XML, or come back through the API.

### What you get

#### Scores and fixtures (one row per game)

| Field | What it is | Fill rate |
|---|---|---|
| `gameId` | ESPN's event id, always a string | 100% |
| `date` | Start time, ISO 8601 UTC | 100% |
| `name`, `shortName` | Matchup as ESPN prints it | 100% |
| `state`, `status` | `pre`, `in` or `post`, plus the readable status such as `Final` | 100% |
| `homeTeam`, `awayTeam`, `homeScore`, `awayScore` | Teams and score (team sports) | 100% |
| `participants` | Everyone in the competition with score, order and winner flag (how MMA, golf and racing arrive) | 100% |
| `homeRecord`, `awayRecord` | Season record as shown on the card | 99.1% |
| `venueName`, `venueCity` | Stadium and city | 99.3% |
| `broadcast` | Networks and streams carrying the game | 99.9% |
| `attendance` | Crowd, once the game is played | 80.9% |
| `leaders` | Top performer per statistic category | 84.6% |
| `home.linescores`, `away.linescores` | Period by period scores | 76.6% |
| `oddsDetails`, `oddsSpread`, `oddsOverUnder`, `oddsHomeMoneyline`, `oddsAwayMoneyline` | The line ESPN posts | see below |
| `gameUrl` | Link to the game on espn.com | 100% |

Fill rates measured over **1,081 live events** across the NFL, NBA, MLB, NHL, Premier League, college football,
MLS and the WNBA on 2026-09-15.

#### Odds

Odds mode returns one row per bookmaker line, with the matchup, kick-off time, provider, `spread`, `overUnder`,
both money lines and which side is the favourite. **ESPN posts a single provider's line, close to kick-off, and
drops it from most games once they are final.** Measured on 2026-09-15 over a ten day forward window: NFL 17 of 17
upcoming games carried a line, Premier League 10 of 10, LaLiga 15 of 15, college football 28 of 30, MLS 15 of 16,
MLB 15 of 130, and a league that was out of season carried none. Across all completed games in the fill-rate
sample, only 1.4 percent still had a line attached.

#### Standings, teams, rosters and news

- **Standings**: one row per team per group, with `position`, `wins`, `losses`, `ties`, `points`, `pointsFor`,
  `pointsAgainst`, `gamesBehind`, `streak` and a `stats` object holding every number ESPN publishes for that league.
- **Teams**: the league directory, with team id, abbreviation, location, colours, logo and the clubhouse link.
- **Rosters**: every player with jersey number, position, age, height, weight, birthplace, college, experience and
  injury status. NFL rosters also carry the position group (offense, defense, special teams).
- **News**: league headlines with byline, publish time, the teams and athletes mentioned, and the article link.

#### Box scores

One row per game with team totals, both line scores, venue, attendance, officials and, unless you turn them off,
every player stat line from the box score. Give it game ids, pasted ESPN game URLs, or a date window and let it
find the games itself; the games it reads to find them are not charged.

#### Leagues covered

44 leagues in the dropdown: NFL, NCAA football, CFL, UFL, NBA, WNBA, NCAA men's and women's basketball, MLB, NCAA
baseball, NHL, NCAA men's hockey, 22 soccer competitions including the Premier League, LaLiga, Bundesliga, Serie A,
Ligue 1, Eredivisie, Liga MX, MLS, NWSL, the Champions League and both World Cups, plus the UFC, Bellator, PGA,
LPGA, Formula 1, NASCAR, ATP, WTA, the AFL and the Premier Lacrosse League. Any of ESPN's other published leagues
works as free text: 356 across 17 sports.

Team sports have teams, standings and rosters. Individual sports have no team data on ESPN, so they behave
differently: an MMA card, a golf tournament, a race session or a tennis event returns one row per competition with
a `participants` list (fighter, golfer or driver, with score, finishing order and winner flag) instead of home and
away columns. ESPN's tennis scoreboard is tournament level, so tennis returns the event, not individual matches.

### How much does it cost to scrape ESPN?

Pay per event, in US dollars:

| Event | What triggers it | Price |
|---|---|---|
| **Game** (primary) | One delivered game or odds row | $0.001 per row, $1.00 per 1,000 |
| **Record** | One delivered standings, team, roster or news row | $0.001 per row, $1.00 per 1,000 |
| **Box score** | One delivered box score for a single game | $0.003 per row, $3.00 per 1,000 |
| **Actor start** | Apify's standard per-run start fee, per gigabyte of memory | $0.00005 per run |

Store discounts apply to the result events: Silver pays 10 percent less and Gold 20 percent less than the prices
above. The Actor start event carries no discount.

Worked example: 1,000 Premier League fixtures with scores, venue and the posted line cost $1.00 plus $0.00005 for
the run start. The same scheduled run a day later, using the same memory name, pays only for the games whose score
or line changed.

Nothing else is charged. Rows your memory has already delivered unchanged are free, the run summary and status rows
are free, the requests used only to discover game ids or team ids are free, and a run that finds no data charges no
result events at all.

### Input

| Field | Meaning |
|---|---|
| `dataType` | `scores`, `odds`, `standings`, `teams`, `rosters`, `boxscores` or `news` |
| `leagues` | League codes from the dropdown, such as `football/nfl` or `soccer/eng.1` |
| `customLeagues` | Any other ESPN league: a code (`ger.2`), an abbreviation (`epl`, `ucl`, `nascar`) or a pasted ESPN URL |
| `lastNDays`, `nextNDays` | Date window around today for scores, odds and box scores |
| `dateFrom`, `dateTo` | Explicit window as `YYYY-MM-DD`, overriding the days settings |
| `gameState` | `any`, `scheduled`, `in-progress` or `final` |
| `teamIds` | Team ids or abbreviations: filters games, or picks which rosters to fetch |
| `eventIds` | Game ids or pasted game URLs for box scores |
| `groups` | College conference or division id, for example `80` for FBS |
| `season` | Season year for standings |
| `maxItems` | Hard cap on delivered rows, shared fairly across the leagues you picked |
| `includePlayerStats` | Keep or drop the player lines inside box scores |
| `includeRawJson` | Attach ESPN's untouched event object to each game row |
| `dedupMemoryName` | Name a cross-run memory so repeat runs pay only for new or changed rows |
| `resetDedupMemory`, `emitDuplicates` | Clear the memory, or return unchanged rows free of charge |
| `maxRequestsPerSecond`, `proxyConfiguration` | Pace and network settings; the defaults work |

A run with an empty input `{}` returns the last day and the next day of NFL, NBA, MLB and Premier League games.
That default has **no row cap**: it delivers and charges for every game in that three day window (yesterday,
today and tomorrow), which is a few dozen rows in season. Set `maxItems` if you want a hard ceiling. If you set only `customLeagues`, only those leagues are
scraped, and if none of the leagues, teams or game ids you give can be read the run delivers nothing and charges
nothing rather than widening the scope.

#### Honest limits

News returns the latest 50 articles per league, and the team directory and rosters are a single page each: ESPN
does not paginate those feeds. ESPN serves at most 1,000 events in one scoreboard page. A window longer than a week is read one month per
request, and if a month comes back at that cap the Actor re-reads it day by day so nothing is lost; any page that
still hits the cap is listed in `truncatedPages` in the run summary and called out in a free status row. The run
summary also reports every request made, every league's row count, the fill rates of the run and any warning.

### What this Actor does NOT do

- No play by play, drive charts, win probability, injury reports or fantasy projections.
- No bookmaker comparison and no arbitrage: ESPN publishes one provider's line per game, and only for part of the
  schedule. This is a sports data product; the odds fields are one part of a game row, not betting advice.
- No team, standings or roster data for individual sports such as MMA, golf and tennis, because ESPN has none.
- No data from before a league existed, and no seasons ESPN no longer serves on its public scoreboard.
- No match-level tennis: ESPN's tennis scoreboard is tournament level, so that is what you get.
- No results for a league code ESPN does not recognise. If every league you name is unusable the run delivers
  nothing and charges nothing, rather than quietly scraping something else.
- No login, no cookies, no personal ESPN Fantasy data.

### API examples

Run the Actor and wait for the dataset, with your token from the Apify Console.

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~espn-sports-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"dataType":"scores","leagues":["football/nfl"],"lastNDays":1,"nextNDays":7,"maxItems":50}'
```

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation_craft/espn-sports-scraper').call({
    dataType: 'standings',
    leagues: ['soccer/eng.1'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.dataType === 'standing'));
```

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("automation_craft/espn-sports-scraper").call(run_input={
    "dataType": "odds",
    "leagues": ["football/nfl"],
    "nextNDays": 7,
    "gameState": "scheduled",
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item.get("name"), item.get("spread"), item.get("overUnder"))
```

### FAQ

#### Is the ESPN API free, and do I need an API key?

ESPN publishes these JSON endpoints for its own site and does not sell keys or document them, so there is nothing
to sign up for and no key to paste. This Actor calls those public endpoints politely, at a rate you control, and
turns the responses into flat rows.

#### Which sports and leagues can I scrape?

17 sports and 356 leagues, of which 44 are in the dropdown. Team sports return scores, odds, standings, teams,
rosters, box scores and news; individual sports such as MMA, golf and tennis return scores and news only.

#### Does it include betting odds?

Yes, as data. Every game row carries the spread, over under and money lines that ESPN posts, and `odds` mode gives
one row per bookmaker line. ESPN shows one provider's line and posts it close to kick-off, so upcoming games in
the current week are well covered while completed games mostly are not. It is not a bookmaker comparison and it is
not betting advice.

#### How far back can I pull scores?

As far back as ESPN's public scoreboard serves for that league, which for the major US leagues and the big soccer
competitions is many seasons. Windows longer than a week are read one month per request, so a full season is a
few dozen requests rather than hundreds.

#### How do I get a full box score for one game?

Set **What to scrape** to box scores and paste the game id or the ESPN game URL into **Game ids**. You get team
totals, both line scores, venue, attendance, officials and every player stat line. Leave the ids empty and the
Actor takes the games from your date window instead.

#### Can two schedules share one memory name?

Run one schedule at a time per memory name. The memory is a key-value store the Actor reads when a run starts and
writes at each checkpoint and at the end, merging in whatever another run saved meanwhile. That merge reduces lost
updates but cannot remove them: two runs sharing one name can both see the same game as new and both charge for
it. Give each schedule its own name and they never collide.

#### Do I pay for a run that returns nothing?

No result events are charged when nothing is delivered, and rows your memory has already seen unchanged are free.
Apify's standard Actor start fee of $0.00005 per run applies to every run of every Actor on the platform.

#### Why does this Actor run with limited permissions?

Least privilege. It only reads and writes its own storages on your account, nothing else. The cross-run memory is a
named key-value store the Actor creates itself on its first run, so limited permissions are enough for it.

### Changelog

- **0.1** First release: seven data types, 356 leagues, cross-run memory, pay per delivered row.

### More data tools by Automation Craft

- [Google News Scraper: Search, Topics, Decoded URLs](https://apify.com/automation_craft/google-news-scraper)
- [Google Trends Scraper - Compare and Trending Now](https://apify.com/automation_craft/google-trends-scraper)
- [Telegram Channel Scraper: Posts, Views, Dates](https://apify.com/automation_craft/telegram-channel-scraper)
- [Substack Scraper: Posts, Notes and Profiles](https://apify.com/automation_craft/substack-scraper)
- [Amazon Product Scraper - Search, Best Sellers](https://apify.com/automation_craft/amazon-data-scraper)
- [G2 Reviews Scraper: Ratings, Pros and Cons](https://apify.com/automation_craft/g2-reviews-scraper)

# Actor input Schema

## `dataType` (type: `string`):

The kind of rows you want. Scores returns one row per game with teams, score, status, venue, broadcast and the betting line when ESPN shows one. Odds returns one row per bookmaker line. Standings, teams, rosters and news return reference rows, and box scores return full team and player statistics for finished games.

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

Leagues to cover, as ESPN's sport and league codes. Pick as many as you like; each one is requested separately and the run summary reports per league. Leave this empty and set Other leagues to scrape only the codes you type. An input with neither falls back to the NFL, NBA, MLB and Premier League.

## `customLeagues` (type: `array`):

Any other ESPN league that is not in the dropdown: 356 are published. Accepts a full code (soccer/ger.2), a bare league code (ger.2), a common abbreviation (epl, ucl, nascar) or a pasted ESPN URL. Unknown entries are reported as a warning, never as a failed run.

## `lastNDays` (type: `integer`):

How many days before today to include. Used for scores, odds and box scores when no explicit dates are set. Example: 3 covers the last three days of results.

## `nextNDays` (type: `integer`):

How many days after today to include, for upcoming fixtures and pre-game betting lines. Example: 7 covers the coming week of fixtures.

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

First day to include, as YYYY-MM-DD. Overrides the days back setting. Example: 2026-03-01.

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

Last day to include, as YYYY-MM-DD. Overrides the days ahead setting. Example: 2026-03-31.

## `gameState` (type: `string`):

Filter games by their state. Scheduled games are the ones that carry betting lines; final games carry the result and the box score.

## `teamIds` (type: `array`):

Limit the run to these teams, by ESPN team id or by abbreviation (LAL, GB, ARS). For scores and odds this keeps only games the team plays in; for rosters it is the list of rosters to fetch. Leave empty for the whole league.

## `eventIds` (type: `array`):

Specific games to pull box scores for, as ESPN game ids or pasted game URLs. Leave empty to use every game in the date window.

## `groups` (type: `string`):

College leagues only: ESPN's group id, for example 80 for FBS football, 50 for Division I basketball, 8 for the SEC. Leave empty to use the sensible default for the league.

## `season` (type: `integer`):

Standings only: the season to read, for example 2025. Leave empty for the current season.

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

Hard cap on delivered rows, shared fairly across the leagues you picked. 0 means no cap. You are only ever charged for rows that are actually delivered.

## `includePlayerStats` (type: `boolean`):

Box scores only. On, every player line from the box score is included in the row. Off, only the team totals are kept, which makes the rows much smaller.

## `includeRawJson` (type: `boolean`):

Adds the untouched ESPN event object as a `raw` field on every game row, for developers who want a field we do not map. It makes the dataset considerably larger.

## `dedupMemoryName` (type: `string`):

Give this run a memory name and the Actor remembers every row it has delivered under that name. Later runs skip rows that have not changed, free of charge, and only deliver new or changed ones. Leave empty to treat every run as a fresh start. Example: nfl-daily.

## `resetDedupMemory` (type: `boolean`):

Clears the memory named above before the run starts, so everything counts as new again.

## `emitDuplicates` (type: `boolean`):

Returns rows the memory has already seen and that have not changed, flagged with changeType DUPLICATE. They are delivered free of charge.

## `maxRequestsPerSecond` (type: `integer`):

How fast the Actor calls ESPN. The default is polite and reliable; raise it only if you know you need to.

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

ESPN answers Apify's datacenter proxy reliably, which is the default and costs almost nothing. Residential proxies are not needed.

## Actor input object example

```json
{
  "dataType": "scores",
  "leagues": [
    "football/nfl",
    "basketball/nba",
    "baseball/mlb",
    "soccer/eng.1"
  ],
  "customLeagues": [],
  "lastNDays": 3,
  "nextNDays": 3,
  "gameState": "any",
  "teamIds": [],
  "eventIds": [],
  "maxItems": 20,
  "includePlayerStats": true,
  "includeRawJson": false,
  "resetDedupMemory": false,
  "emitDuplicates": false,
  "maxRequestsPerSecond": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "BUYPROXIES94952"
    ]
  }
}
```

# Actor output Schema

## `rows` (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 = {
    "dataType": "scores",
    "leagues": [
        "football/nfl",
        "basketball/nba",
        "baseball/mlb",
        "soccer/eng.1"
    ],
    "lastNDays": 3,
    "nextNDays": 3,
    "gameState": "any",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/espn-sports-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 = {
    "dataType": "scores",
    "leagues": [
        "football/nfl",
        "basketball/nba",
        "baseball/mlb",
        "soccer/eng.1",
    ],
    "lastNDays": 3,
    "nextNDays": 3,
    "gameState": "any",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/espn-sports-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 '{
  "dataType": "scores",
  "leagues": [
    "football/nfl",
    "basketball/nba",
    "baseball/mlb",
    "soccer/eng.1"
  ],
  "lastNDays": 3,
  "nextNDays": 3,
  "gameState": "any",
  "maxItems": 20
}' |
apify call automation_craft/espn-sports-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation_craft/espn-sports-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/G7P85PTrhwXibMtZy/builds/33lAOe0e1zumPa1a6/openapi.json
