
Website Content Crawler
scrape.ly/store/querystone/website-content-crawlerAIDeveloper tools
1 monthly user

Sports betting odds from DraftKings, Pinnacle and Bovada on one row per game: moneyline, spread and total for NFL, NBA, NHL, MLB, college, UFC, tennis and top soccer leagues, with the best price per outcome and arbitrage. No login needed.
Get live pregame betting odds from DraftKings, Pinnacle and Bovada side by side, one row per game. Pick your leagues and every game comes back with moneyline, spread and total from each sportsbook, the best available price per outcome and any arbitrage between the books. No login, no API key, no browser: a full NBA or Premier League slate takes a few seconds.
| Field | What it does |
|---|---|
sports | Leagues to read: nfl, ncaaf, nba, wnba, ncaab, mlb, nhl, ufc, boxing, tennis_atp, tennis_wta, soccer_epl, soccer_laliga, soccer_bundesliga, soccer_seriea, soccer_ligue1, soccer_mls, soccer_uefa_cl, soccer_uefa_el, soccer_uefa_ecl, soccer_championship, soccer_eredivisie, soccer_primeira, soccer_brazil, soccer_ligamx |
maxItems | Maximum game rows for the run, spread across the leagues (0 = all) |
customLeagues | Any other ESPN league as sport/league, e.g. soccer/sco.1 (DraftKings lines) |
books | draftkings, pinnacle, bovada (empty = all three) |
markets | h2h (moneyline), spreads, totals, team_totals, first_half |
oddsFormat | american, decimal, fractional or implied_probability |
teams, lookAheadHours, includeLive, minBooks, maxItemsPerLeague | Filters |
computeBestPrice, computeArbitrage, minArbPct, minBestEdgePct, onlyArbitrage | Best price and arbitrage options |
onlyNewGames | Skip games returned in earlier runs (a new-games feed for schedules) |
{
"sports": ["nba", "nfl", "mlb", "soccer_epl"],
"maxItems": 20,
"oddsFormat": "american",
"minBooks": 2
}
One row per game:
| Field | Description |
|---|---|
sport, sportName, league | League key, sport and league name |
home, away, commenceTime, status | Teams (or players), start time in UTC, upcoming or live |
books, bookCount | Sportsbooks that price the game |
bestHomeMoneyline, bestAwayMoneyline, bestDrawMoneyline | Best moneyline across books |
spreadLine, totalLine | Main home spread and total (most common line across books) |
markets[] | Each market with its outcomes; each outcome has name, side, point, prices per book (price, decimal, and for DraftKings openPrice / openPoint) and bestPrice |
hasArbitrage, maxArbitragePct, arbitrage[] | Arbitrage found across books, with legs, books and stake split |
bookEventIds, url, sources, espnUrl | Event ids and pages at each sportsbook |
eventKey, oddsFormat, scrapedAt | Stable game key, price format and read time |
Example (trimmed to the moneyline and total of one NBA game):
{
"eventKey": "nba|san-antonio-spurs|oklahoma-city-thunder|2026-10-21",
"sport": "nba",
"sportName": "Basketball",
"league": "NBA",
"home": "San Antonio Spurs",
"away": "Oklahoma City Thunder",
"commenceTime": "2026-10-21T01:30:00Z",
"status": "upcoming",
"books": [
"draftkings",
"pinnacle",
"bovada"
],
"bookCount": 3,
"bestHomeMoneyline": -102,
"bestAwayMoneyline": -108,
"bestDrawMoneyline": null,
"spreadLine": 1,
"totalLine": 229.5,
"hasArbitrage": false,
"maxArbitragePct": null,
"arbitrage": [],
"markets": [
{
"key": "h2h",
"label": "Moneyline",
"outcomes": [
{
"name": "San Antonio Spurs",
"side": "home",
"point": null,
"prices": {
"draftkings": {
"price": -102,
"decimal": 1.9804,
"openPrice": -125
},
"pinnacle": {
"price": -102,
"decimal": 1.9804
},
"bovada": {
"price": -105,
"decimal": 1.9524
}
},
"bestPrice": {
"book": "draftkings",
"price": -102,
"decimal": 1.9804,
"averageDecimal": 1.9711,
"edgePctVsAverage": 0.47
}
},
{
"name": "Oklahoma City Thunder",
"side": "away",
"point": null,
"prices": {
"draftkings": {
"price": -118,
"decimal": 1.8475,
"openPrice": 105
},
"pinnacle": {
"price": -108,
"decimal": 1.9259
},
"bovada": {
"price": -115,
"decimal": 1.87
}
},
"bestPrice": {
"book": "pinnacle",
"price": -108,
"decimal": 1.9259,
"averageDecimal": 1.8811,
"edgePctVsAverage": 2.38
}
}
]
},
{
"key": "totals",
"label": "Total",
"outcomes": [
{
"name": "Over",
"side": "over",
"point": 229.5,
"prices": {
"draftkings": {
"price": -115,
"decimal": 1.8696,
"openPrice": -115,
"openPoint": 228.5
}
}
},
{
"name": "Under",
"side": "under",
"point": 229.5,
"prices": {
"draftkings": {
"price": -105,
"decimal": 1.9524,
"openPrice": -105,
"openPoint": 228.5
}
}
}
]
}
],
"bookEventIds": {
"draftkings": "34510039",
"pinnacle": "1633801640",
"bovada": "29469363"
},
"url": "https://sportsbook.draftkings.com/event/34510039",
"sources": [
"https://sportsbook.draftkings.com/event/34510039",
"https://www.pinnacle.com/en/basketball/nba/san-antonio-spurs-vs-oklahoma-city-thunder/1633801640/",
"https://www.bovada.lv/sports/basketball/nba/oklahoma-city-thunder-san-antonio-spurs-202610202130"
],
"espnUrl": "https://www.espn.com/nba/game/_/gameId/401909090/thunder-spurs",
"oddsFormat": "american",
"scrapedAt": "2026-10-21T00:47:20.194Z"
}
You pay $0.01 per game row ($10 per 1,000 games), plus a small amount of platform usage (a few seconds of compute and a few hundred kilobytes of proxy traffic per run, about $0.001 in our tests). Games without odds are skipped and never charged, and a run that finds nothing costs only its usage.
Example: a 20-game slate across NBA, NFL and Premier League costs about $0.20 in events plus well under a cent of usage.
Where do the odds come from? DraftKings lines come from ESPN's public scoreboard (DraftKings is ESPN's odds provider). Pinnacle and Bovada prices come from the public feeds that power their own websites. Nothing needs a login.
Is it legal? The scraper reads publicly available odds that anyone can see without an account. Check the terms of the sites and the betting rules where you live before using the data commercially.
How are games matched across books? By team names (normalized for accents, abbreviations and suffixes such as FC or college mascots) and a start time within a few hours. A game is joined only when both sides agree, so a wrong pairing never invents a price gap.
Why does a game show only one or two books? Each book posts lines on its own schedule. ESPN only shows DraftKings lines for games in the next few days, and some leagues (UFC, boxing, tennis) are not on ESPN at all. Use minBooks to keep only games priced by several books.
Do I need a proxy? No setup needed. The default setting uses datacenter exits and switches to residential exits on its own where a sportsbook refuses datacenter or US visitors (Pinnacle is always read through residential exits outside the US). A typical run moves well under a megabyte through the proxy.
Can I schedule it or use the API? Yes. Schedule runs from the console or start them over the API, and turn on onlyNewGames if you only want games you have not received yet.
includeLive adds games that are in progress. Their prices are what the books still publish at that moment (mostly Bovada's in-play lines; DraftKings rows show the last pregame line).scrapedAt.Every field below can be set in the run form, passed through the API, or saved as a task. Unset fields fall back to the defaults shown.
sportsarrayOptionalSports and leagues
Leagues to read. Each game comes back as one row with every sportsbook that prices it. NFL, NBA, NHL, MLB, WNBA and college games carry all three books; UFC, boxing and tennis come from Pinnacle and Bovada.
maxItemsintegerOptionaldefault 20Max games
Maximum game rows for the whole run, spread evenly across the leagues and sorted by start time. 0 means every game with odds.
customLeaguesarrayOptionalOther ESPN leagues (DraftKings lines)
Any other league as an ESPN path sport/league, for example soccer/bra.2, soccer/arg.1 or soccer/sco.1. These rows carry DraftKings lines as published on ESPN.
booksarrayOptionalSportsbooks
Sportsbooks to read. Leave empty for all three.
lookAheadHoursintegerOptionaldefault 0Starting within (hours)
Only games that start within this many hours from now. 0 means no limit.
includeLivebooleanOptionaldefault falseInclude games already in progress
Off keeps the feed to upcoming games. On adds games in progress, with the prices the books still publish (mostly Bovada's in-play lines).
teamsarrayOptionalTeams
Only games where the home or away name contains one of these words, for example Lakers or Arsenal. Case and accents are ignored.
minBooksintegerOptionaldefault 1Min sportsbooks per game
Only games priced by at least this many sportsbooks. Use 2 or 3 to compare lines.
maxItemsPerLeagueintegerOptionaldefault 0Max games per league
Cap per league, useful when one league has far more games than the others. 0 means no cap.
onlyNewGamesbooleanOptionaldefault falseOnly games not returned before
Skip games this account already received in earlier runs, so a schedule works as a new-games feed. Off returns the full slate with fresh prices every run.
marketsarrayOptionaldefault ["h2h","spreads","totals"]Markets
Markets to return. Team totals and first-half lines come from Pinnacle.
oddsFormatenumOptionaldefault "american"Odds format
Format of the price field. Decimal odds are always included too.
computeBestPricebooleanOptionaldefault trueBest price per outcome
Add bestPrice to every outcome priced by two or more books: the highest price, the book offering it and its edge over the average.
minBestEdgePctnumberOptionaldefault 0Min best-price edge over average (%)
Only flag a best price that beats the average of the books by at least this percent.
computeArbitragebooleanOptionaldefault trueFind arbitrage
Flag two-way and three-way markets where the best prices across books guarantee a profit, with the stake split per leg.
minArbPctnumberOptionaldefault 0Min arbitrage edge (%)
Ignore arbitrage below this guaranteed return. 0.5 means at least 0.5%.
onlyArbitragebooleanOptionaldefault falseOnly games with arbitrage
Return only games where an arbitrage was found.
proxyConfigurationobjectOptionaldefault {"useScrapelyProxy":true,"scrapelyProxyGroups":["DATACENTER…Proxy configuration
Datacenter by default. Where a sportsbook refuses datacenter or US visitors, the scraper switches to residential exits on its own (Pinnacle is always read through residential exits outside the US).
Every run writes its results to a dataset. Preview it in the dashboard, then export it or read it through the API.
| Field | Type | Description |
|---|---|---|
| eventKey | string | Stable game key: league, both teams and the UTC date |
| sport | string | League key, e.g. nba or soccer_epl |
| sportName | string | null | Sport |
| league | string | null | League name |
| home | string | Home team or first competitor |
| away | string | Away team or second competitor |
| commenceTime | string | Start time (UTC, ISO 8601) |
| status | string | null | upcoming or live |
| books | array | Sportsbooks that price this game |
| bookCount | number | Number of sportsbooks |
| bestHomeMoneyline | number | string | null | Best home moneyline across books (in the chosen format) |
| bestAwayMoneyline | number | string | null | Best away moneyline across books |
| bestDrawMoneyline | number | string | null | Best draw price (soccer) |
| spreadLine | number | null | Main home spread (most common line across books) |
| totalLine | number | null | Main total points (most common line across books) |
| hasArbitrage | boolean | null | True when the best prices across books guarantee a profit |
| maxArbitragePct | number | null | Largest guaranteed return found (%) |
| arbitrage | array | null | Arbitrage opportunities with legs, books and stake split |
| markets | array | Markets with outcomes, line and price per sportsbook |
| bookEventIds | object | null | Event id at each sportsbook |
| url | string | null | Sportsbook event page |
| sources | array | Event pages at each sportsbook |
| espnUrl | string | null | ESPN game page |
| oddsFormat | string | null | Format of the price fields |
| scrapedAt | string | null | When the odds were read (UTC) |
You pay for the events the actor reports, such as each result or page it produces. Platform usage is included in the event prices.
| Event | Charged when | Price |
|---|---|---|
| Game with odds | Charged for each game saved with its odds from DraftKings, Pinnacle and Bovada, best prices and arbitrage. Games without odds, invalid inputs and empty leagues are free. | $0.01 |
Run this actor from your own code. Swap in your API token and the examples work as-is.
import { ScrapelyClient } from 'scrapely-client'
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN })
// Start the actor and wait for the run to finish.
const run = await client.actor('querystone/sports-odds-scraper').call({
"sports": [
"nba",
"nfl",
"mlb",
"soccer_epl"
],
"maxItems": 20,
"proxyConfiguration": {
"useScrapelyProxy": true,
"scrapelyProxyGroups": [
"DATACENTER"
]
}
})
// Read the dataset the run produced.
const { items } = await client.dataset(run.defaultDatasetId).listItems()
console.log(items)Tokens live in your account settings. Keep them server-side: a token carries the full permissions of your account.
Connect the Scrape.ly MCP server once and your agent can run this actor as a tool. Pick your tool:
Fetch scrape.ly/agents.md and run querystone/sports-odds-scraperPaste into Claude Code, Codex, Cursor or any AI agent. It signs you in once in the browser.
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp?tools=actors,runs,storage,docs&actors=querystone/sports-odds-scraper"
}
}
}No key in the file: your client opens the browser to sign you in the first time it connects.
Inputs the developer prepared for common jobs. Open one to see its input, then copy it to your account to run it as-is or adjust it.
Premier League, La Liga, Bundesliga, Serie A, Ligue 1, Brasileirao and MLS with the draw price.
NBA, NFL, NHL, MLB and college football games priced by at least two books.
Sharp Pinnacle lines with team totals and first-half markets as implied probabilities.
Fight and match odds from Pinnacle and Bovada.
Argentina, Scotland, Belgium and Turkey top flights with DraftKings lines.
Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes. The advantage lasts forever.