Sports Odds Scraper
Moneylines, spreads, totals and player props from DraftKings and Pinnacle, plus Underdog and Sleeper player lines, one row per selection.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
sports,leagues,sources(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.00001 per odds row = $0.01 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Odds row returned | One odds or player-prop row returned in the dataset. | $0.00001 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-09-14, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
sports | Every league of the sports you tick, on every source you keep. Leave it empty and fill in Leagues instead if you only want one or two. Soccer on Pinnacle alone is close to 300 leagues, so for soccer it's worth naming them. | array |
leagues | League names, for example NFL, MLB, WNBA, Premier League, La Liga or UFC. Short forms work too: EPL, NCAAF, NCAAB. The big leagues are matched by name across all four sources, so Premier League means England's, not Canada's or Malta's. Any other name is looked for inside each book's own league name, so WTA finds WTA - Guadalajara. Case doesn't matter. | array |
sources | DraftKings and Pinnacle are sportsbooks: game lines and player props, priced in odds. Underdog and Sleeper are pick'em apps: player lines only. Underdog gives its own American and decimal price and a payout multiplier; Sleeper gives the multiplier alone. | array |
marketTypes | Game lines are the full-game main lines. Player props are over/under lines on one player's stat. Futures, alternate lines, halves and quarters of game lines, and novelty props aren't included. | array |
playerNames | Only props on these players. A last name is enough, and accents don't matter: Mbappe finds Kylian Mbappé. Game lines are left out when this is filled in, because they aren't about a player. | array |
startFrom | Only games that start on or after this day (UTC), written like 2026-09-13. Leave it empty for everything on the board. | string |
startTo | Only games that start on or before the end of this day (UTC). Sleeper gives a game's day but not its start time, so its rows are matched on the day. | string |
includeLive | Off, you get pre-game prices only. On, games that have started are included too, at whatever price the book showed at that second. | boolean |
extraOddsFormats | Every sportsbook row already has American and decimal odds. Tick these to add fractional odds (oddsFractional, like 5/2 or 10/11) and the implied probability (impliedProbability, 1 divided by the decimal odds, with the book's edge still in, so the two sides of a bet add up to a little over 1). Sleeper rows leave both empty, because Sleeper pays by multiplier. Leave it empty for American and decimal only. | array |
maxRows | The most rows one run returns, shared fairly between the sources you keep. Each row is one charge. | integer |
What you get
A structured dataset — each result includes fields like:
bookmakerleagueeventstartTimegameDaymarketplayerselectionlineoddsAmericanoddsDecimalpayoutMultiplierisLivescrapedAtExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
Related tools in Developer & Research Tools
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
GitHub Scraper
Search GitHub repos and users: stars, forks, language, topics, licence, plus user bio, company and followers. No token needed. $0.90 per 1,000 rows.
Stack Overflow / Stack Exchange Scraper
Search Stack Overflow and Stack Exchange by keyword or tag. Score, answer count, views, reputation and body text. $2 per 1,000 questions.
Package Registry Scraper (npm + PyPI)
Get npm and PyPI package metadata as JSON. Version, license, author, repo, keywords and npm monthly downloads. $2 per 1,000 packages.
arXiv Scraper
Search arXiv papers by title, author, abstract or category. Get full abstracts, authors, categories, DOI, dates and PDF links. $2 per 1,000 papers.
OpenAlex Scholarly Works Scraper
Search 250M+ OpenAlex papers with no API key. Get titles, authors, venue, year, citations, DOI, OA links and full abstracts. $2.00 per 1,000 papers.
Crossref Scholarly Works Scraper
Search 150M+ papers on Crossref: DOI, title, authors, journal, publisher, date, citations and abstract. No API key. $1.00 per 1,000 works.
Where this tool sits
- Categories
- Developer & Research Tools
Sports Odds Scraper: game lines and player props from four boards, as rows
Name a sport or a league and get back one row per selection: the game, the start time, the market, the player where there is one, the line, and American and decimal odds or a payout multiplier. Two sportsbooks, DraftKings and Pinnacle, and two pick'em apps, Underdog and Sleeper, in the same shape so you can put them side by side.
It reads full-game main lines and player over/unders. Futures, alternate lines, halves, quarters, team totals and novelty props are not in there, and every row is a snapshot of the price at the second it was read.
| Input | Sports or league names, plus optional players, markets and dates |
| Output | One row per selection |
| Ceiling | 30,000 rows per run |
| Account needed | None |
| Price | $0.01 per 1,000 rows, flat on every plan |
🎲 What Sports Odds Scraper does
It walks each source you keep, in turn, and pulls the board for the sports or leagues you named. Every selection becomes a row with the same field names whatever produced it, so a DraftKings moneyline and a Sleeper player line sit in one table and join on the game.
The row limit is shared evenly between the sources you keep, and whatever one source does not use passes to the next. That is what stops a single busy board eating the whole run.
The fifteen best-known leagues are matched by their common name across all four sources, so Premier League means England's and not Canada's. Any other word is looked for inside each book's own league name, so WTA finds WTA - Guadalajara.
📥 What you give it
{
"sports": ["football"],
"leagues": ["NFL"],
"sources": ["draftkings", "pinnacle", "underdog", "sleeper"],
"marketTypes": ["moneyline", "spread", "total", "player-prop"],
"startFrom": "2026-09-14",
"maxRows": 200
}
| Field | Default | What it is |
|---|---|---|
sports | none, box starts at football | Every league of the sports you tick. Soccer on Pinnacle alone is close to 300 leagues, so for soccer name the leagues instead. |
leagues | none, box starts at NFL | League names, up to 40. NFL, MLB, WNBA, Premier League, La Liga, UFC. Short forms work: EPL, NCAAF, NCAAB. Case does not matter. |
sources | all four | DraftKings and Pinnacle are sportsbooks, priced in odds. Underdog and Sleeper are pick'em apps and carry player lines only. |
marketTypes | all four | moneyline, spread, total, player-prop. Drop player-prop and the two apps sit the run out. |
playerNames | none | Up to 100. A last name is enough and accents do not matter, so Mbappe finds Kylian Mbappé. Filling this in drops game lines, since they are not about a player. |
startFrom | none | Only games starting on or after this UTC day, written 2026-09-13. |
startTo | none | Only games starting on or before the end of this UTC day. |
includeLive | off | On, games already under way come too, at whatever price showed that second. |
extraOddsFormats | none | fractional adds oddsFractional, like 5/2. impliedProbability adds impliedProbability, which is 1 divided by the decimal odds, with the book's edge still in, so the two sides of a bet add up to a little over 1. Worked out from the price on the row, so it changes no rows and costs nothing extra. |
maxRows | 1000, box starts at 200 | Rows in one run, up to 30,000, shared between the sources. |
📤 What you get back
A real row from a recent run:
{
"bookmaker": "DraftKings",
"source": "draftkings",
"sport": "football",
"league": "NFL",
"event": "DAL Cowboys @ NY Giants",
"homeTeam": "NY Giants",
"awayTeam": "DAL Cowboys",
"startTime": "2026-09-14T00:20:00.000Z",
"gameDay": null,
"isLive": false,
"marketType": "moneyline",
"market": "Moneyline",
"selection": "DAL Cowboys",
"player": null,
"playerTeam": null,
"line": null,
"oddsAmerican": -166,
"oddsDecimal": 1.602,
"payoutMultiplier": null,
"eventId": "34118096",
"marketId": "1_84695529",
"selectionId": "0ML84695529_3",
"sourceUpdatedAt": null,
"scrapedAt": "2026-09-13T21:26:17.516Z"
}
| Field | What it is |
|---|---|
event | Always written "away @ home", whichever source it came from. |
startTime | UTC, and null on every Sleeper row. Sleeper publishes the day, which lands in gameDay. |
oddsAmerican, oddsDecimal | Both filled for DraftKings, Pinnacle and Underdog. Empty on Sleeper rows, which price in a multiplier only. |
oddsFractional, impliedProbability | Only there when you tick them in extraOddsFormats. The fraction is the American price reduced exactly, so -325 reads 4/13 and +150 reads 3/2. Empty on Sleeper rows. |
payoutMultiplier | Underdog and Sleeper. null on the two sportsbooks. |
line | The number being bet over or under. null on a moneyline. |
player, playerTeam | Filled on player props, null on game lines. |
selectionId | The source's own id. Combined with source it is unique in a run, which is how repeats get dropped. |
sourceUpdatedAt | When the app last touched the line. Underdog and Sleeper only. |
🧾 Reading the output
| Row | How to spot it | Charged |
|---|---|---|
| A selection | it has a selectionId | yes |
| The sample row | _sample: true | no |
Run with no sport, no league and no player and you get that one sample row and nothing else. It is a real DraftKings NFL price, there to show you the shape.
No diagnostic rows go into the dataset. The run's status message leads with the split, like "Returned 200 odds rows: DraftKings 50, Underdog 75, Sleeper 75", then names anything that did not come through. RUN_REPORT in the key-value store has the long version: per source, how many rows, how much of its share it used, which leagues were read and which pages were not, plus counts for everything dropped on live, dates, market, sport, league, player and repeats.
A source that cannot be read on a given run is reported as not read. It returns nothing and nothing is charged for it, and the other sources carry on.
▶️ How to run it
1. Open Sports Odds Scraper and click Try for free. 2. Tick a sport, or type league names into Leagues, one per line. 3. Leave Bookmakers and apps on all four, or untick the ones you do not want. 4. Set Maximum rows. Start around 200, then click Start. 5. Download the dataset as JSON, CSV or Excel, or read it from the Apify API.
💰 How much does it cost?
$0.01 per 1,000 rows. Flat on every Apify plan, no volume tiers.
You pay per selection delivered. Selections your filters drop, live prices while Include games already under way is off, a selection already delivered in the same run, the sample row, and a source that could not be read are all free.
💡 What people use it for
- Comparing the same game across two sportsbooks and two pick'em apps in one table.
- Tracking a line through the week on a schedule, keyed on
sourceandselectionId. - Pulling every prop on a handful of players before a slate, with Players filled in.
- Feeding a model, since the American and decimal prices are both there and the ids are stable.
- Checking whether an app's multiplier is worth more or less than a book's price on the same line.
🚧 What it does not do
- Main lines and player over/unders only. No futures, alternates, halves, quarters, team totals
or novelty props.
- Sleeper rows have no start time, and no game at all for soccer, CS2 and tennis lines. They
carry gameDay.
- A multiplier is not odds. Sleeper rows leave
oddsAmericanandoddsDecimalempty. - Season-long app lines are left out. Weekly and per-game lines only.
- DraftKings prices come from its New Jersey board. Another state can price differently.
- Naming players removes game lines from that run, because a moneyline is not about a player.
- It is not a live feed. Each row is what the source showed when it was read, and
scrapedAt
says when.
- Only these four sources. Nothing else is read, and none of them is a betting account: this
returns numbers, it does not place anything.
- Soccer across a whole sport is slow. Close to 300 leagues on Pinnacle alone, so name the
league you want.
🧭 Which odds scraper do you need?
| If you want | Use |
|---|---|
| Game lines and player props across two books and two apps | This one |
| Tennis results, surface, round and match odds | Tennis Matches Scraper |
| Event contract prices on politics, economics and sport | Kalshi Markets Scraper |
❓ Questions people ask
Do I need an account with any of them? No. No login, no key, nothing to apply for.
Why did Pinnacle come back with less than the others? Some of its pages will not answer on a given run. The status message says which sources were partly read, and you are not charged for what did not arrive.
Can I get just one book? Yes. Untick the rest in Bookmakers and apps and the whole row limit goes to the one you kept.
Why are the apps missing from my run? They only carry player lines. Without player-prop in Markets they sit it out, and the status message says so.
How do I follow a line through the week? Schedule it with the same league and a small Maximum rows, and key your store on source plus selectionId.
Is scraping odds legal? These are public prices on public pages. Sportsbook and app terms do restrict automated collection, so read the terms of whichever source you care about and decide for yourself. Apify's write-up on scraping and the law is a starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the run ID and the input. The status message and RUN_REPORT name which source fell short and why.