ESPN Odds & Line Movement Scraper avatar

ESPN Odds & Line Movement Scraper

Pricing

from $2.00 / 1,000 odds rows

Go to Apify Store
ESPN Odds & Line Movement Scraper

ESPN Odds & Line Movement Scraper

Betting lines for NFL, NBA, MLB, NHL, NCAA, WNBA and soccer, back to 2014 and up to 17 sportsbooks a game. Moneyline, spread and total with opening and closing prices, de-vigged fair odds, the book's hold, line movement, and how every bet settled — computed from the final score.

Pricing

from $2.00 / 1,000 odds rows

Rating

0.0

(0)

Developer

Elena Vance

Elena Vance

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Betting lines for NFL, NBA, MLB, NHL, NCAA football and basketball, WNBA and soccer — moneyline, spread and total, from every sportsbook ESPN carries, back to 2014.

One row is one book's complete pricing of one game: the opening line and the closing line, the margin the book charged, the de-vigged fair price, how far the number moved, and — for finished games — whether each bet actually won.

gameDate league game book ML home spread open move total ATS
2024-01-15 nba HOU @ PHI DraftKings -355 -8.0 -7.5 -0.5 229.0 home
2024-01-15 nba HOU @ PHI MGM -350 -8.0 -7.0 -1.0 228.5 home
2024-01-15 nba HOU @ PHI Caesars (NJ) -355 -8.0 -7.0 -1.0 228.5 home

What this does that the other ESPN scrapers cannot

Historical odds live on one ESPN host, and it is not the obvious one. The scoreboard endpoint every other ESPN Actor is built on returns odds: [] for any game that has finished — verified on completed MLB games from 2020, 2024 and 2025 — and so does the game-summary endpoint. Only sports.core.api.espn.com keeps them, and it keeps every book that ever priced the game.

That difference is the product:

Scoreboard-based ActorsThis Actor
Today's slate
A game from last season❌ empty
Books per game1up to 17
Opening line✅ (2024 onward)
Bet settlement✅ computed

Bet settlement is computed, not copied. Every ESPN odds item carries moneylineWinner and spreadWinner. Across 691 provider rows on 67 finished games in three leagues, both were false every single time — including the 395 where the home team won. They carry no information at all. This Actor ignores them and settles from the final score instead, with pushes handled properly and a soccer draw kept distinct from a tie.

The betting maths is done for you. Implied probability, the book's overround, its vig and its hold, de-vigged fair probabilities that sum to exactly 1, the fair price at zero margin, line movement in points and in probability, and closing-line value as a percentage.


What one row looks like

{
"recordId": "401585183-40",
"gameDate": "2024-01-15",
"league": "nba",
"shortName": "HOU @ PHI",
"home": { "abbreviation": "PHI", "score": 124 },
"away": { "abbreviation": "HOU", "score": 115 },
"provider": { "id": "40", "name": "DraftKings", "kind": "sportsbook" },
"moneyline": {
"home": { "open": { "american": -285, "decimal": 1.3509, "impliedProbability": 0.7402 },
"current": { "american": -355, "decimal": 1.2817 },
"fairProbability": 0.7468, "fairAmerican": -295,
"clvPercent": 5.4 },
"away": { "current": { "american": 278 }, "fairProbability": 0.2532 },
"draw": { "current": { "american": null } }, // soccer only
"holdPercent": 4.28, "vigPercent": 4.48, "overround": 1.0448
},
"spread": { "openLine": -7.5, "currentLine": -8.0, "movementPoints": -0.5 },
"total": { "openLine": 228.5, "currentLine": 229.0, "movementPoints": 0.5 },
"settlement": {
"isFinal": true, "homeMargin": 9, "combinedScore": 239,
"moneyline": "home", "spread": "home", "total": "over",
"homeSpreadProfitUnits": 0.9091, "awaySpreadProfitUnits": -1.0
},
"dataQuality": { "snapshots": ["current", "open"], "hasOpeningLine": true }
}

Full field reference: .actor/dataset_schema.json — 196 fields, all documented, all nullable.


Input

FieldDefaultWhat it does
leaguesNFL, NBA, MLB, NHL16 leagues to choose from.
customLeaguesAny other ESPN competition as "soccer/ned.1".
dateFrom / dateToa 5-day window around todayInclusive. Up to 400 days per run.
eventIdsSpecific games, by the id in their espn.com URL.
providersevery bookFilter by name or id.
includeModelProvidersfalseAdd ESPN's forecasting partners.
onlyCompletedfalseKeep only games with a settled result.
maxItems200One row is one book per game.

maxItems is the cost lever and it is easy to underestimate: a 2026 game produces 1 row and a 2021 game produces ten, so a date range costs far more rows than it has games.

Examples

Yesterday's closing lines from every book:

{ "leagues": ["nba"], "dateFrom": "2025-01-15", "dateTo": "2025-01-15" }

A season of NFL history to backtest against — every book, settled:

{ "leagues": ["nfl"], "dateFrom": "2023-09-07", "dateTo": "2024-01-08",
"onlyCompleted": true, "maxItems": 20000 }

One specific game:

{ "leagues": ["nba"], "eventIds": ["401585183"] }

What ESPN actually has, by era

Measured on the 15 January slate of every NBA season:

SeasonSportsbooks per gameOpening lines
2012 and earliernone
2013none — forecasting models onlyno
2014 – 20236 – 13no
2024~11yes
20252 (ESPN BET)yes
20261 (DraftKings)yes

Two consequences worth planning around:

  • Multi-book comparison is a historical product. ESPN carried a dozen books through 2024 and its own single book afterwards. For line shopping across today's market you want a book-by-book scraper; for eleven years of closing lines from a dozen books, this is the only place they exist.
  • Opening lines start in 2024. Earlier seasons carry the closing line only, so movementPoints and clvPercent are null there. dataQuality.hasOpeningLine says so per row rather than leaving you to infer it.

Known ESPN quirks, handled

QuirkWhat it would doWhat this Actor does
moneylineWinner / spreadWinner always falseA "did it win" column that is wrong half the timeNot republished; settlement computed from the score
close.pointSpread sometimes holds a price (provider 58, some 2023 games)A closing spread of -115; a closing total of -115close is never read; dataQuality.closeDisagreesWithCurrent flags the games
details names the favourite, not the home teamA line whose sign points at an unknown teamPassed through as a label; spread.currentLine is always home-relative
Provider id 1001 is accuscore in the NBA and Bet365 in the NHLA forecasting model billed as a sportsbookClassified by name, with the league carried alongside
Soccer has a drawA three-way market de-vigged as two-way reports a negative holdThree-way markets priced and settled as three outcomes
Provider 2000 quotes decimal odds and no AmericanNull prices for a book that published themBoth directions converted
A game listed on two calendar datesPriced — and billed — twiceDe-duplicated on the competition id

Notes

  • No API key, no proxy, no browser. ESPN's public API has no bot defence: 42 concurrent requests at concurrency 24 all returned 200 with no throttling. A proxy option exists for the case your own network is the problem.
  • Odds requests take about 1.7 seconds each regardless of load, so a wide date range is bounded by latency. Runs stop cleanly at a 210-second budget and report how many games went unpriced.
  • Unofficial and not affiliated with ESPN or any sportsbook. Informational use only — check the rules that apply where you are before betting.

Built and verified against the live API on 2026-09-08; docs/architecture.md carries every measurement behind the claims above.