# Live Odds Scraper: NFL, NBA, MLB In-Play & Closing Lines (`scrapersdelight/sports-odds-scraper`) Actor

Opening, closing and current moneyline, spread and total for every game in American, decimal and fractional odds, plus the in-play line while a game runs and the graded result after it ends. NFL, NCAAF, NCAAB, NBA, MLB, NHL, WNBA and 20 soccer leagues. No API key, no browser.

- **URL**: https://apify.com/scrapersdelight/sports-odds-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Developer tools, Business, Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 per odds line returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## 🎯 Live Odds Scraper — In-Play & Closing Lines for NFL, NBA, MLB and 25 more leagues

**Every game's betting line, including the two that other ESPN-based scrapers structurally cannot give you: the line while the game is running, and the line it closed at.**

Opening, closing and current **moneyline, spread and total** for every game — in American, decimal *and* fractional odds — plus the **in-play line** while a game is live and the **graded result** (moneyline / against-the-spread / over-under) once it ends. 154 fields per row. No API key, no login, no browser, no proxy.

***

### 🧨 Why this one and not the other ESPN odds scrapers

Every other actor in this lane reads ESPN's **public scoreboard** feed. That feed has one property nobody mentions on their store page:

> **The scoreboard silently drops the odds the moment a game starts, and never brings them back.**

Measured on the MLB slate of 2026-09-02 — 15 events:

| Game state | Events | Carrying odds on the **scoreboard** feed | Carrying odds on the **core API** |
|---|---:|---:|---:|
| Scheduled | 1 | 1 | 1 |
| **In progress** | 5 | **0** | **5** (count = 2 each) |
| Final | 9 | **0** | 9 |

This actor reads the scoreboard for **context** (teams, venue, weather, score, status) and ESPN's **core sports API** for the **line**. That is where the extra data lives:

- a **`close`** block appears on every game once it starts — the actual closing line, the number a betting model is graded against;
- a **second provider, `200` — "DraftKings - Live Odds"** — appears while the game is running, carrying the real in-play market.

Real example from that run: **DET @ MIN, top of the 8th.** Pre-match line `MIN -120`, total 8.5 (opened at 9). In-play line at the same instant: `DET -1940`, total 7.5. The scoreboard feed showed neither.

Reconciliation check on a 91-game college-football slate: the core API covered **91 of 91** games the scoreboard had odds for, and there were **0** games where the scoreboard had a line the core API lacked. It is a strict superset.

***

### 📊 What you get

- 🏈 **28 leagues**, all live-probed: NFL · NCAA Football · NBA · WNBA · NCAA Men's & Women's Basketball · MLB · NCAA Baseball · NHL · MLS · NWSL · Premier League · Championship · LaLiga · Serie A · Bundesliga · Ligue 1 · Eredivisie · Primeira Liga · Liga MX · Süper Lig · Argentine Liga Profesional · Brasileirão · Champions League · Europa League · Conference League · Libertadores · Leagues Cup
- 💰 **Three price states** per market — `open`, `close`, `current` — for moneyline, spread **and** total
- 🔢 **Three odds formats** on every price — American (`-175`), decimal (`1.57`), fractional (`4/7`)
- ⚡ **The in-play line** (`lineType: "live"`) while a game is running
- 📈 **Derived analytics**: implied probability, **no-vig probability**, book **hold %** on both the moneyline and the total, open→current movement on all three markets, **CLV** (open→close in probability points), and line direction
- 🏆 **Graded results** once a game is final: `moneylineWinnerSide`, `spreadResultSide` (ATS), `totalResult` (O/U)
- 🏟️ **Full game context**: venue + city/state, weather, broadcaster, attendance, team records, live score, period and clock
- 🔗 Direct **bet-slip deep links** for home / away / over / under / game

***

### ⚙️ Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `leagues` | multi-select | NFL, NCAAF, NBA, MLB, NHL, NCAAM, MLS, EPL | Which leagues to pull. The enum is a hard-coded, live-probed list — ESPN's slugs are not guessable. |
| `dateFrom` | string | today (US Eastern) | `YYYY-MM-DD`. Past dates work and are how you build a closing-line dataset. |
| `dateTo` | string | — | `YYYY-MM-DD`. Blank ⇒ uses **Days ahead**. |
| `daysAhead` | integer | `6` | Days past the start date when `dateTo` is blank. |
| `lineTypes` | select | `all` | `prematch`, `live`, or both. |
| `gameStatus` | select | `any` | `scheduled` / `live` / `final`. Use `final` for a CLV dataset. |
| `maxEvents` | integer | `50` | Stop after N games, earliest kickoff first. `0` = unlimited. |
| `maxConcurrency` | integer | `10` | Parallel requests. 10 measured clean. |
| `proxyConfiguration` | proxy | off | Not needed — see *Anti-bot* below. |

> ⏱ **Dates are US-Eastern**, because that is how ESPN files a game. A 10pm-ET Tuesday game is 02:00 UTC Wednesday and ESPN still returns it for the Tuesday date. Taking "today" from UTC would skip the entire evening slate — every in-progress game, which is exactly where the in-play and closing lines live.

**Example input**

```json
{
  "leagues": ["nfl", "college-football", "mlb", "usa.1", "eng.1"],
  "daysAhead": 3,
  "maxEvents": 25
}
```

**Closing-line-value dataset** (settled games only, with graded results):

```json
{
  "leagues": ["nfl", "nba", "mlb", "nhl"],
  "dateFrom": "2026-01-01",
  "dateTo": "2026-01-31",
  "gameStatus": "final",
  "maxEvents": 0
}
```

***

### 📐 Output — measured field fill

**One row per game per line type.** A game usually yields one row; a *running* game or a top-European-soccer match yields two.

All percentages below are **measured on real Apify runs on 2026-09-03**, not estimated.

- **Run A — the default (empty input `{}`)**: `SUCCEEDED` in **3.1 s**, **45 rows** from **40 games** across MLB / NCAAF / EPL / MLS. 4 in-play rows, 15 rows carrying a closing line. `chargedEventCounts.odds_row` = **45** = row count.
- **Run B — wide (10 leagues, 2026-08-29 → 2026-09-06, `maxEvents: 200`)**: `SUCCEEDED` in **3.8 s**, **237 rows** from **183 games**. Books: DraftKings 183, Bet 365 50, DraftKings-Live-Odds 4. **132 rows (56%) carried a closing line.** `chargedEventCounts.odds_row` = **237** = row count.

`A%` = fill on run A · `B%` = fill on run B.

#### Game identity & context

| Field | A% | B% | Notes |
|---|---:|---:|---|
| `eventId` | 100 | 100 | ESPN event id |
| `sport` | 100 | 100 | football / basketball / baseball / hockey / soccer |
| `league` · `leagueSlug` · `leagueAbbrev` | 100 | 100 | e.g. `National Football League` / `nfl` / `NFL` |
| `seasonYear` · `seasonType` | 100 | 100 | e.g. `2026` / `regular-season` |
| `week` | 33 | 14 | NFL & college football only |
| `eventName` · `shortName` | 100 | 100 | `New England Patriots at Seattle Seahawks` / `NE @ SEA` |
| `kickoffUtc` | 100 | 100 | ISO 8601 |
| `statusName` · `statusState` · `statusDetail` · `statusCompleted` | 100 | 100 | `STATUS_IN_PROGRESS` / `in` / `Top 8th` |
| `statusPeriod` · `statusClock` | 93 | 86 | inning / quarter / period, and the clock |
| `neutralSite` · `conferenceCompetition` | 93 | 50 | absent on soccer |
| `attendance` | 100 | 100 | |
| `venueName` · `venueCity` | 100 | 100 | |
| `venueState` · `venueIndoor` | 93 | 50 | US venues |
| `venueCountry` | 40 | 64 | |
| `broadcast` | 100 | 100 | e.g. `NBC` |
| `weatherCondition` · `weatherTemperature` | 73 | 18 | outdoor US games |
| `gameUrl` | 78 | 96 | ESPN game page |

#### Teams & score

| Field | A% | B% | Notes |
|---|---:|---:|---|
| `homeTeamId` · `homeTeamAbbrev` · `homeTeamName` · `homeTeamDisplayName` · `homeTeamRecord` | 100 | 100 | same five for `away*` |
| `homeScore` · `awayScore` | 42 | 72 | **null until the game starts** — ESPN reports `"0"` for an unplayed game and this actor refuses to ship that as a 0-0 score |

#### Book & line type

| Field | A% | B% | Notes |
|---|---:|---:|---|
| `providerId` · `providerName` · `providerPriority` | 100 | 100 | `100` DraftKings · `200` DraftKings - Live Odds · `2000` Bet 365 |
| `lineType` | 100 | 100 | `prematch` or `live` |

#### Headline line

| Field | A% | B% | Notes |
|---|---:|---:|---|
| `details` | 98 | 79 | e.g. `SEA -3.5` |
| `spread` · `overUnder` · `overOdds` · `underOdds` | 98 | 79 | |
| `initialSpread` · `initialOverUnder` | 60 | 36 | |
| `moneylineWinner` · `spreadWinner` | 100 | 100 | ⚠️ ESPN's own booleans — **`false` on every game we sampled**, including settled finals the favourite won. Shipped verbatim because they are real API fields; use `moneylineWinnerSide` / `spreadResultSide` for the actual graded result. |
| `homeFavorite` · `homeUnderdog` · `homeFavoriteAtOpen` (+ `away*`) | 98 | 79 | |
| `homeMoneyline` · `awayMoneyline` | 87 | 76 | flat American shortcut |
| `drawMoneyline` | 7 | 49 | soccer only |
| `homeSpreadOdds` · `awaySpreadOdds` | 38 | 43 | |

#### Moneyline — open / close / current × American / decimal / fractional

| Field group | A% | B% |
|---|---:|---:|
| `homeMoneylineOpen{American,Decimal,Fraction}` (+ `away*`) | 87 | 76 |
| `homeMoneylineClose{American,Decimal,Fraction}` (+ `away*`) | **33** | **56** |
| `homeMoneylineCurrent{American,Decimal,Fraction}` (+ `away*`) | 89 | 96 |
| `drawMoneylineCurrent{American,Decimal}` | 7 | 49 |
| `drawMoneylineCurrentFraction` | 2 | 21 |

#### Spread — the handicap line **and** the price on it

| Field group | A% | B% |
|---|---:|---:|
| `homeSpreadOpenLine` · `homeSpreadOpenOdds{American,Decimal,Fraction}` (+ `away*`) | 98 | 79 |
| `homeSpreadCloseLine` · `homeSpreadCloseOdds{…}` (+ `away*`) | **33** | **56** |
| `homeSpreadCurrentLine` · `homeSpreadCurrentOdds{…}` (+ `away*`) | 98 | 79 |

> `*SpreadOpenLine` is the handicap (`-3.5`); `*SpreadOpenOddsAmerican` is the juice on it (`-110`). Most competitors collapse these into one column and lose the price.

#### Total (over / under)

| Field group | A% | B% |
|---|---:|---:|
| `totalOpenLine` · `over/underOpen{American,Decimal,Fraction}` | 98 | 79 |
| `totalCloseLine` · `over/underClose{…}` | **33** | **56** |
| `totalCurrentLine` · `over/underCurrent{…}` | 98 | 79 |

#### Bet-slip deep links

| Field | A% | B% |
|---|---:|---:|
| `bettingLinkHome` · `bettingLinkAway` | 89 | 97 |
| `bettingLinkOver` · `bettingLinkUnder` · `bettingLinkGame` | 98 | 79 |

#### Derived analytics

| Field | A% | B% | Definition |
|---|---:|---:|---|
| `impliedProbHome` / `Away` / `Draw` | 89 / 89 / 7 | 96 / 96 / 49 | `100 / decimal`, vig included |
| `noVigProbHome` / `Away` / `Draw` | 89 / 89 / 7 | 96 / 96 / 49 | implied, normalised so the book's outcomes sum to 100% |
| `holdPercentMoneyline` | 89 | 96 | the book's moneyline vig, in points |
| `holdPercentTotal` | 98 | 79 | the book's vig on over/under |
| `moneylineMoveOpenToCurrent` | 87 | 76 | home implied-probability move, **percentage points** (positive = home shortened). Points, not raw American, because American odds do not subtract across the ±100 boundary |
| `spreadMoveOpenToCurrent` | 98 | 79 | `homeSpreadCurrentLine − homeSpreadOpenLine` |
| `totalMoveOpenToCurrent` | 98 | 79 | `totalCurrentLine − totalOpenLine` |
| `clvHomeMoneylineOpenToClose` | **33** | **56** | **the CLV number** — home implied-prob move open→close, in points |
| `lineDirection` | 100 | 100 | `home` / `away` / `none` |

#### Graded result (null until the game is completed)

| Field | A% | B% | Values |
|---|---:|---:|---|
| `homeWon` | 20 | 61 | `true` / `false` / `null` (draw) |
| `moneylineWinnerSide` | 20 | 68 | `home` / `away` / `draw` |
| `spreadResultSide` | 20 | 53 | `home` / `away` / `push` — graded against the **closing** line, falling back to current |
| `totalResult` | 20 | 53 | `over` / `under` / `push` |
| `capturedAt` | 100 | 100 | ISO timestamp of the snapshot |

**37 of 154 fields are 100% filled on run B; not one field was 0% filled.** Every sub-100% number above has a stated structural reason.

***

### 💵 Pricing

**Pay per event — $0.003 per odds line returned.** No monthly fee, no platform-usage surcharge.

| | |
|---|---|
| Event | `odds_row` — *Per odds line returned* |
| Price | **$0.003** per row (**$3 / 1,000**) |
| Billed for | Each betting line delivered to your dataset |
| **Never** billed for | Starting a run · a game with no line posted (skipped before delivery) · the dataset write itself |

Billing is **budget-aware**: rows are delivered through `Actor.pushData(items, 'odds_row')`, which charges atomically as it pushes and stops cleanly at your charge cap. Delivered always equals billed — verified on the runs above (45 rows → `odds_row: 45`; 237 rows → `odds_row: 237`).

The current market rate on the Apify Store for the same event is **$0.012 per row**. This actor is **4× cheaper**.

Worked example: a daily 06:00 snapshot of the default eight leagues ≈ 45–200 rows/day ≈ **$4–18/month**.

***

### ⚠️ Honest limits — what this does NOT do

**1. ESPN carries ONE sportsbook. This is not a book-comparison product.**
Verified across 26 events in 5 leagues: **DraftKings (provider 100) only** for NFL, NCAAF, NCAAB, MLB, NHL, NBA and MLS. **Bet 365 (provider 2000) appears as a second book on top European and South American soccer only** — measured on EPL, Championship, LaLiga, Serie A, Bundesliga, Ligue 1, Eredivisie, Primeira Liga, Süper Lig, Argentine Liga Profesional, Brasileirão, Champions League, Europa League, Conference League and Libertadores. Requests for other providers (`/odds/58` ESPN BET, `/odds/1002`) return **404 "no instance found"** on an NFL event. If you need a five-book line shop, this is the wrong actor — and no ESPN-based actor can honestly claim one.

**2. The closing line is null until the game starts.** A scheduled game's odds object carries `open` + `current` only; the `close` block appears at kickoff. Every `*Close*` field, and `clvHomeMoneylineOpenToClose`, is **null** on a pre-match row and is **never** silently mirrored from `current`. That is why close fill was 33% on the default (mostly upcoming games) and 56% on the wide backfill run.

**3. Coverage is line-posting dependent, not game dependent.** DraftKings posts most lines roughly a day out — MLB especially. Measured over an 8-day forward window: **8 of 100 MLB games** carried a line; the other 92 did not have one posted yet. A far-future date range legitimately returns fewer rows than games. When that happens the run **exits SUCCEEDED with a status message naming the reason** ("No betting line posted yet… This is a real answer from ESPN, not a block"), never a failure, and never as "no results found".

**4. Bet 365 rows are moneyline-only.** Provider 2000 ships home/away/draw prices with no spread, no total and no open/close history. Those columns are null on a Bet 365 row by design — that is what ESPN returns, not a parsing gap.

**5. ESPN's own `moneylineWinner` / `spreadWinner` booleans are dead.** They read `false` on every completed game sampled, including a settled NFL final the favourite won. They are shipped verbatim as real API fields; the usable graded result is in `moneylineWinnerSide` / `spreadResultSide` / `totalResult`, computed here from the final score against the closing line.

**6. Leagues deliberately excluded because ESPN carries no line for them:** UFC/MMA (27 fights across three cards sampled — **zero** with odds, including past cards), PGA, F1, NCAA men's hockey and the NBA G League. They are absent from the enum rather than present and empty.

**7. Player props and futures are out of scope.** ESPN exposes a `propBets` collection on the same object (242 items on one NFL game) and an FPI predictor. Both are deliberately not scraped — bundling them would make this a combo actor rather than one that does one thing completely.

**8. Two league slugs need per-day queries.** `mens-college-basketball` and `womens-college-basketball` **404 on a date range** and return 200 on a single date. The actor walks those day by day automatically, and falls back to day-by-day for any league that starts refusing a range.

#### 🤖 Anti-bot / proxy — measured, not assumed

There is **no** anti-bot on this feed. No API key, no auth, no Cloudflare, no browser, no cookies.

| Path | Result |
|---|---|
| Home IP → scoreboard | `200`, 250,817 bytes |
| Apify proxy `groups-AUTO` → scoreboard | `200`, **250,817 bytes — byte-identical** |
| Apify proxy `groups-RESIDENTIAL,country-US` → scoreboard | `200`, **250,817 bytes**, 0.96 s |
| Burst: 30 core-API `/odds` calls @ concurrency 10 through the proxy | **30 × 200**, 0 non-200, 1.5 s wall |
| 91-game college-football slate @ concurrency 10 | 91 × 200, 0 failures, 0.8 s |

The proxy option is therefore **off by default**. Turn it on only if your own network blocks ESPN.

#### 📄 robots.txt

Neither API host serves a robots.txt. Quoted verbatim, fetched 2026-09-03:

```
$ curl -i https://sports.core.api.espn.com/robots.txt
HTTP/1.1 403 Forbidden
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
</body>
</html>

$ curl -i https://site.api.espn.com/robots.txt
HTTP/1.1 403 Forbidden
<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD><BODY>
<H1>Access Denied</H1>
You don't have permission to access "http://site.api.espn.com/robots.txt" on this server.
</BODY></HTML>
```

There is no crawl directive to honour on either host, and no rule on the separate `www.espn.com` robots.txt covers these API paths. Data returned is public, unauthenticated sports information. You are responsible for how you use it, and for gambling regulation in your own jurisdiction — this actor reports published prices and is not betting advice.

***

### ❓ FAQ

**What is "closing line value" and why does this actor exist?**
CLV is the gap between the price you took and the price the game closed at. It is the single best predictor of whether a betting model is actually profitable, and it is why the `close` block matters more than the `current` one. Scoreboard-based scrapers cannot give it to you, because that feed drops odds at kickoff.

**Which sportsbook are these odds from?**
DraftKings for everything, plus Bet 365 as a second book on top European and South American soccer. See honest limit #1 — this is not a multi-book comparison tool.

**Can I get the in-play line for a game happening right now?**
Yes — set `lineTypes: "live"` and `gameStatus: "live"`. Rows come back with `lineType: "live"` and `providerName: "DraftKings - Live Odds"`.

**Can I backfill historical closing lines?**
Yes. Set `dateFrom` / `dateTo` to a past range and `gameStatus: "final"`. Those rows carry the `close` block and the graded `moneylineWinnerSide` / `spreadResultSide` / `totalResult`.

**How do I track line movement over time?**
You don't need to. ESPN ships `open`, `close` and `current` **inline on a single fetch** — no cross-run diffing, no key-value store, no scheduled snapshots required for the basic move. Re-run on a schedule only if you want intraday granularity between open and close.

**Why are odds in three formats?**
American for US books, decimal for modelling (implied probability is `100 / decimal`), fractional because ESPN ships it. All three are taken straight from the API where present and derived from each other where not.

**Why did my run return fewer rows than games?**
The line was not posted yet for those games. See honest limit #3. The run's status message tells you exactly which case you hit.

**Does it need a proxy?**
No. See the measured table above — home IP, Apify AUTO and Apify RESIDENTIAL all returned byte-identical payloads.

**How fast is it?**
Measured: 45 rows in 3.1 s, 237 rows across 183 games and 10 leagues in 3.8 s, at concurrency 10.

**What happens if ESPN changes the payload?**
There is an integrity gate: if the actor pulls 10+ odds objects and **not one** yields a moneyline, spread or total, it fails loudly rather than delivering a dataset of empty rows you would still be charged for.

**Are the derived probabilities de-vigged?**
Both are shipped. `impliedProb*` includes the book's margin; `noVigProb*` is normalised so the outcomes sum to 100%. `holdPercentMoneyline` and `holdPercentTotal` tell you how big that margin was.

***

### 🔧 Technical

| | |
|---|---|
| Data source | `site.api.espn.com/apis/site/v2/sports/…/scoreboard` (context) + `sports.core.api.espn.com/v2/sports/…/odds` (the line) |
| Auth | none |
| Runtime | Node 20, plain HTTP (`got-scraping`), 1024 MB, no browser |
| Concurrency | 10 by default |
| Zero-row behaviour | exits **SUCCEEDED** with an explanatory status message — a block and an empty slate are reported differently and are never conflated |

# Actor input Schema

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

Which leagues to pull the betting line for. Every slug in this list was probed live and confirmed to carry a DraftKings line on the ESPN feed. Leave empty for the default eight (NFL, NCAAF, NBA, MLB, NHL, NCAAM, MLS, Premier League). Note: UFC, PGA, F1, NCAA hockey and the NBA G League are deliberately absent — ESPN carries no line for them (27 UFC fights sampled, zero with odds).

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

First day of the window, `YYYY-MM-DD` (UTC). Leave blank for today. Past dates work and are how you pull settled games with their closing line and graded result.

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

Last day of the window, `YYYY-MM-DD` (UTC). Leave blank to use **Days ahead** counted from the start date.

## `daysAhead` (type: `integer`):

Used only when **Date to** is blank: how many days past the start date to include. 6 covers a full NFL week and the Saturday college slate. DraftKings posts most lines roughly a day out (MLB especially), so days far in the future often have games but no line yet.

## `lineTypes` (type: `string`):

`prematch` is the standard DraftKings market (and Bet 365 on top European soccer). `live` is ESPN's provider 200, "DraftKings - Live Odds" — the in-play line, which exists only while a game is actually running and which the public scoreboard feed never shows.

## `gameStatus` (type: `string`):

Filter by where the game is in its lifecycle. Use `final` to build a closing-line-value dataset — the `close` block and the graded result only exist once a game has started/finished.

## `maxEvents` (type: `integer`):

Stop after this many games (earliest kickoff first). One game usually yields one row; a running game or a top European soccer match yields two. 0 = no limit — raise it once you know the scope you want, a full autumn Saturday is 130+ college football games on its own.

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

Parallel requests to ESPN's core API. 10 measured clean (30 calls, 30 x 200, zero failures). Lower it if you are running through a shared proxy.

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

Optional. ESPN's public feed has no anti-bot and needs no proxy — both endpoints returned byte-identical payloads from a home IP, Apify AUTO and Apify RESIDENTIAL. Add one only if your own network blocks ESPN or you are running at very high volume.

## Actor input object example

```json
{
  "leagues": [
    "nfl",
    "college-football",
    "mlb",
    "usa.1",
    "eng.1"
  ],
  "dateFrom": "",
  "dateTo": "",
  "daysAhead": 3,
  "lineTypes": "all",
  "gameStatus": "any",
  "maxEvents": 25,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `oddsRows` (type: `string`):

The dataset of scraped betting lines (one item per game per line type).

# 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",
        "college-football",
        "mlb",
        "usa.1",
        "eng.1"
    ],
    "dateFrom": "",
    "dateTo": "",
    "daysAhead": 3,
    "maxEvents": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/sports-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",
        "college-football",
        "mlb",
        "usa.1",
        "eng.1",
    ],
    "dateFrom": "",
    "dateTo": "",
    "daysAhead": 3,
    "maxEvents": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/sports-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",
    "college-football",
    "mlb",
    "usa.1",
    "eng.1"
  ],
  "dateFrom": "",
  "dateTo": "",
  "daysAhead": 3,
  "maxEvents": 25
}' |
apify call scrapersdelight/sports-odds-scraper --silent --output-dataset

```

## MCP server setup

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