# ESPN Sports Odds Scraper (`automation-lab/espn-multi-league-odds-scraper`) Actor

Extract current ESPN betting lines across NFL, NBA, MLB, and English soccer for comparison and movement analysis.

- **URL**: https://apify.com/automation-lab/espn-multi-league-odds-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Sports
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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 Sports Odds Scraper

Collect current **ESPN sports odds** for NFL, NBA, MLB, and English Premier League events in one normalized dataset.

The Actor extracts event schedules, teams, moneylines, spreads, totals, sportsbook provider details, and ESPN's opening and current values. Run it once for a comparison export or schedule it to build snapshots for line-movement analysis.

No ESPN login, betting account, browser, or user-supplied API key is required.

### What can you do with ESPN Sports Odds Scraper?

- Compare upcoming lines across NFL, NBA, MLB, and English soccer.
- Export ESPN MLB moneylines, run lines, and totals to a spreadsheet.
- Record opening and current prices on a schedule.
- Flag records where an available line or price changed.
- Join odds snapshots to internal event, team, or forecasting data.
- Feed normalized records into dashboards, databases, and alerts.

Each dataset item represents one ESPN event and odds provider. Events without published odds are skipped rather than returned as empty betting records.

### Who is this Actor for?

**Sports analysts** can collect a consistent cross-league feed without maintaining four league-specific parsers.

**Betting-data teams** can store scheduled snapshots and compare opening values with current values.

**Data engineers** can send typed JSON, CSV, or Excel output into a warehouse or BI workflow.

**Researchers** can create reproducible event-level datasets with ESPN IDs and source URLs.

**Automation builders** can schedule runs and trigger downstream processing from Apify webhooks or integrations.

### Supported leagues

| Input value | League | ESPN sport path |
| --- | --- | --- |
| `nfl` | National Football League | football |
| `nba` | National Basketball Association | basketball |
| `mlb` | Major League Baseball | baseball |
| `epl` | English Premier League | soccer |

Odds are seasonal. A supported league can legitimately return no records when no events are scheduled or when ESPN has not published lines for the selected dates.

### What data is extracted?

| Field group | Examples |
| --- | --- |
| Event identity | `eventId`, `eventName`, `shortName`, `eventUrl` |
| League and season | `sport`, `league`, `leagueName`, `seasonYear`, `seasonType` |
| Schedule and status | `startTime`, `status`, `statusDetail` |
| Venue | `venueName`, `venueCity` |
| Teams | home/away ESPN ID, display name, and abbreviation |
| Provider | `provider`, `details` |
| Headline lines | `spread`, `overUnder`, favorite flags |
| Moneyline | home/away opening and current American odds |
| Spread | home/away opening/current line and price |
| Total | over/under opening/current line and price |
| Movement | `hasLineMovement` |
| Provenance | `apiUrl`, `scrapedAt` |

Nullable values remain `null`. The Actor does not invent prices when ESPN omits a market.

### How to scrape ESPN sports odds

1. Open the Actor in Apify Console.
2. Select one or more leagues.
3. Optionally enter a start and end date.
4. Choose the maximum number of records.
5. Click **Start**.
6. Open the **Dataset** tab to inspect or export results.

If dates are omitted, the Actor scans today through 30 days ahead. Date ranges can cover at most 60 days.

### Input parameters

#### `leagues`

An array containing one or more of `nfl`, `nba`, `mlb`, and `epl`.

Default: all four supported leagues.

#### `startDate`

Optional first event date in `YYYY-MM-DD` format.

Default: today in UTC.

#### `endDate`

Optional final event date in `YYYY-MM-DD` format.

Default: 30 days after the effective start date.

The end date must not precede the start date and the range cannot exceed 60 days.

#### `maxItems`

Maximum event/provider odds records written to the dataset.

Default: `250`.

Allowed range: `1` to `5000`.

### Example input

```json
{
  "leagues": ["mlb", "epl"],
  "startDate": "2026-08-07",
  "endDate": "2026-08-31",
  "maxItems": 100
}
```

For a small recurring snapshot, narrow the date range and league list instead of fetching events you will discard downstream.

### Example output

```json
{
  "source": "ESPN",
  "sport": "baseball",
  "league": "mlb",
  "leagueName": "MLB",
  "eventId": "401816428",
  "eventName": "New York Mets at Pittsburgh Pirates",
  "startTime": "2026-08-07T22:40Z",
  "status": "STATUS_SCHEDULED",
  "venueName": "PNC Park",
  "homeTeamName": "Pittsburgh Pirates",
  "awayTeamName": "New York Mets",
  "provider": "DraftKings",
  "details": "PIT -145",
  "overUnder": 8,
  "spread": -1.5,
  "moneylineHomeOpen": "-149",
  "moneylineHomeCurrent": "-145",
  "moneylineAwayOpen": "+123",
  "moneylineAwayCurrent": "+120",
  "spreadHomeOpen": "-1.5",
  "spreadHomeCurrent": "-1.5",
  "totalOverLineOpen": "o8",
  "totalOverLineCurrent": "o8",
  "hasLineMovement": true,
  "eventUrl": "https://www.espn.com/mlb/game/_/gameId/401816428",
  "scrapedAt": "2026-08-07T12:00:00.000Z"
}
```

The schema contains the complete opening/current fields for both sides of moneyline, spread, and total markets.

### How line movement is represented

ESPN's nested odds payload can expose `open` and `close` values. This Actor names `close` fields as `Current` because they represent the latest value available at extraction time for scheduled events.

`hasLineMovement` is `true` when at least one comparable opening/current line or price differs.

It does not calculate implied probability, vigorish, or movement direction. Keep the raw American-odds strings for exact source fidelity and perform domain-specific calculations downstream.

When an opening value is unavailable, its field is `null` and it does not independently trigger the movement flag.

### How much does it cost to extract ESPN sports odds?

Pricing uses one `start` event per run plus one `item` event per saved odds record.

The current start price is **$0.003 per run**. On the BRONZE tier, each saved item is **$0.0024**; other Apify plan tiers use the live discounted curve shown in Console.

Approximate BRONZE examples:

| Saved records | Estimated Actor charge |
| ---: | ---: |
| 1 | $0.0054 |
| 10 | $0.027 |
| 25 | $0.063 |
| 100 | $0.243 |

Events without odds, rejected rows, and duplicate event/provider records are not charged as items. Apify displays the authoritative charge estimate for your plan before and after each run.

### Schedule odds snapshots

Create an Apify Schedule for a repeatable movement dataset:

1. Save an input with the leagues and date horizon you monitor.
2. Run hourly, daily, or at another cadence appropriate for your analysis.
3. Send each run's dataset to a database or webhook target.
4. Match snapshots by `league`, `eventId`, and `provider`.
5. Compare `scrapedAt` and current market fields over time.

The Actor returns current source state; it does not retain history between runs. Your scheduled datasets or downstream store provide the history.

### Export to CSV, Excel, or a data pipeline

The default Apify dataset supports JSON, JSONL, CSV, XML, RSS, and Excel exports.

Useful pipeline keys are:

- `eventId` for ESPN event joins;
- `startTime` for time windows;
- `league` for partitioning;
- `provider` for event/provider uniqueness;
- `scrapedAt` for snapshot ordering.

Use the Overview view for human review and the full dataset API when you need every opening/current field.

### Run with the Apify API

Replace `YOUR_TOKEN` with an Apify API token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~espn-multi-league-odds-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"leagues":["nfl"],"maxItems":50}'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/espn-multi-league-odds-scraper').call({
  leagues: ['mlb', 'epl'],
  maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient(token="YOUR_TOKEN")
run = client.actor("automation-lab/espn-multi-league-odds-scraper").call(
    run_input={"leagues": ["mlb"], "maxItems": 50}
)
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use with MCP and AI agents

#### Claude Code

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/espn-multi-league-odds-scraper"
```

#### Claude Desktop

Add this server object to the Claude Desktop MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/espn-multi-league-odds-scraper"
    }
  }
}
```

#### Cursor

Open **Settings → Tools & MCP → Add custom MCP** and use the same Apify MCP URL shown above.

#### VS Code

Add the same HTTP MCP server URL through your MCP-compatible VS Code extension or workspace MCP configuration.

Example prompts:

- "Collect upcoming ESPN MLB odds and return the current moneylines as a table."
- "Run the ESPN odds Actor for NFL and identify records where opening and current fields differ."
- "Export the next 30 days of English Premier League ESPN odds for my data pipeline."

### Reliability and retries

The Actor uses ESPN's public structured scoreboard data instead of rendering web pages.

Each league request has a 30-second timeout and up to three bounded attempts for transient failures.

Deterministic client errors are surfaced as failed runs instead of silently returning fabricated or partial values.

A successful zero-item run is possible when:

- the league is between seasons;
- the selected dates contain no events;
- ESPN has events but has not posted odds;
- posted odds were removed or unavailable in the selected region.

Try a currently active league or a wider upcoming range before treating zero output as an error.

### Limits and data freshness

- Coverage is limited to NFL, NBA, MLB, and English Premier League scoreboard data.
- The feed reflects what ESPN exposes at run time; it is not a bookmaker guarantee.
- ESPN may expose one provider rather than a full multi-book comparison.
- Historical snapshots are not reconstructed.
- The Actor does not place bets or access betting accounts.
- Postponed, cancelled, or rescheduled events follow ESPN's status and timing.
- A 60-day maximum keeps each run bounded and predictable.

### Legality

ESPN names, event data, and odds may be protected by terms, database rights, or other applicable rules. Use the Actor only for lawful purposes and review ESPN's terms and the rules that apply in your jurisdiction.

Betting regulations vary by location. This Actor provides data extraction, not betting advice, wagering services, or a representation that any market is available to you.

Avoid republishing data in a way that violates source rights. Do not use the output to target vulnerable people or evade local restrictions.

### Troubleshooting

#### Why did the run return no records?

Check that the league is in season and that ESPN has posted odds for the selected event dates. MLB is usually a useful in-season smoke test; NBA may be empty during the off-season.

#### Why are some fields `null`?

ESPN does not expose every market for every event. Nulls preserve missing source values rather than replacing them with zero or inferred prices.

#### Why did my input fail before fetching?

Use exact `YYYY-MM-DD` dates, keep the end date on or after the start date, limit the range to 60 days, and set `maxItems` from 1 to 5000.

#### Can I request a team instead of a league?

Not currently. Filter the normalized dataset by team ID, name, or abbreviation after extraction.

### Related Automation Lab Actors

- [Covers Sports Odds and Consensus Scraper](https://apify.com/automation-lab/covers-sports-odds-consensus-scraper) for Covers-specific odds and consensus signals.
- [FanDuel Sportsbook Odds Scraper](https://apify.com/automation-lab/fanduel-sportsbook-odds-scraper) for sportsbook-specific FanDuel coverage.
- [ESPN News Scraper](https://apify.com/automation-lab/espn-news-scraper) for league news and article metadata that can complement odds monitoring.

Choose this Actor when you need a compact ESPN event/provider odds record with explicit opening/current fields across supported leagues.

### FAQ

#### Does the Actor need a proxy?

No. The current implementation uses a public ESPN JSON surface directly and does not enable an automatic proxy or browser fallback.

#### Are the values live in-play odds?

The Actor returns the latest values present in ESPN's scoreboard response at extraction time. It does not promise tick-level or in-play market streaming.

#### Does it return all sportsbooks?

It returns each provider object ESPN includes for an event. In current responses, ESPN often exposes a single provider.

#### How do I detect changes between scheduled runs?

Store each dataset, join records on `league`, `eventId`, and `provider`, then compare the current market fields and `scrapedAt`. The per-record `hasLineMovement` flag compares ESPN's available opening/current values within a single snapshot.

#### Can I increase the limit?

Yes, up to 5000 records. Increase the date range only when you need that scope; narrower snapshots are faster and easier to compare.

# Actor input Schema

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

ESPN leagues to collect. Defaults to NFL, NBA, MLB, and the English Premier League.

## `startDate` (type: `string`):

First event date in YYYY-MM-DD format. Leave empty to start today.

## `endDate` (type: `string`):

Last event date in YYYY-MM-DD format, up to 60 days after the start. Leave empty to scan 30 days.

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

Maximum event/provider records saved to the dataset.

## Actor input object example

```json
{
  "leagues": [
    "nfl",
    "nba",
    "mlb",
    "epl"
  ],
  "maxItems": 20
}
```

# Actor output Schema

## `overview` (type: `string`):

Dataset containing one row per ESPN event and odds provider.

# 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": [
        "nfl",
        "nba",
        "mlb",
        "epl"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/espn-multi-league-odds-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": [
        "nfl",
        "nba",
        "mlb",
        "epl",
    ],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/espn-multi-league-odds-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": [
    "nfl",
    "nba",
    "mlb",
    "epl"
  ],
  "maxItems": 20
}' |
apify call automation-lab/espn-multi-league-odds-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/espn-multi-league-odds-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/UjEcrObXNDKDDqoe5/builds/7gW3vERGU2sq7mbPx/openapi.json
