# Sports Odds Scraper - DraftKings, Pinnacle, Underdog, Sleeper (`dami_studio/sports-odds-scraper`) Actor

Pre-game odds and player props from DraftKings and Pinnacle, plus player lines from Underdog and Sleeper. One row per selection: game, start time, market, player, line, and American and decimal odds or the payout multiplier. Filter by sport, league, market, player or date.

- **URL**: https://apify.com/dami\_studio/sports-odds-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Sports, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / 1,000 odds row 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

## Sports Odds Scraper

Pick a sport or a league and get what's on the board right now. That means game lines and player props from two sportsbooks, DraftKings and Pinnacle, and player lines from two pick'em apps, Underdog and Sleeper. Every row is one selection: the game and when it starts, the market, the player if it's a prop, the line, and the price.

It reads the odds each book's own website or app shows its visitors. There's no API key to get and no account to log in to.

For scale: on 13 September 2026, the first Sunday of the NFL season, Underdog's board held 9,166 player lines and Pinnacle listed 780 NFL player props.

### What it doesn't do

- **No PrizePicks.** It isn't covered.
- **It doesn't place bets** and never touches an account.
- **No futures, alternate lines, half or quarter game lines, or novelty props.** Game lines are the full-game main line. Player props are the over/under on one player's stat.
- **Sleeper shows multipliers, not odds.** Its rows carry the payout multiplier and leave the odds columns empty. Sleeper also gives the day of a game rather than its start time, and for soccer, CS2 and tennis it doesn't say which game a line belongs to.
- **Prices are the moment of the run.** Lines move, sometimes by the second close to kick-off. Nothing here is historical.
- **DraftKings prices are its New Jersey site's.** Other states can differ now and then.

### Input

**Sports.** Tick the ones you want and you get every league of those sports, on every source you keep.

**Leagues.** League names: NFL, MLB, WNBA, Premier League, La Liga, UFC. Short forms work as well (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. Those are NFL, College Football, MLB, NBA, WNBA, College Basketball, NHL, Premier League, La Liga, Serie A, Bundesliga, Ligue 1, MLS, Champions League and UFC. Any other name is looked for inside each book's own league name, so WTA finds WTA - Guadalajara and Brazil - Serie A finds Brazil's. Case doesn't matter, and you can fill in Leagues without ticking a sport.

**Bookmakers and apps.** All four unless you untick some. Underdog and Sleeper only list player props, so they sit out a run that asks for game lines only.

**Markets.** Moneyline, spread, total and player props. Run lines and puck lines count as spreads.

**Players.** Only props on these players. A last name is enough, and accents don't matter: Mbappe finds Kylian Mbappé. Game lines drop out when this is filled in, since they aren't about a player.

**Starting from, Starting up to.** Days in UTC, written like `2026-09-13`. Sleeper rows are matched on their game day.

**Include games already under way.** Off by default, so you get pre-game prices only.

**Maximum rows.** 1,000 unless you change it, and up to 30,000 per run. The limit is shared between the sources you keep, so a small one still gives each source a turn, and whatever one source doesn't use goes to the next.

```json
{
  "leagues": ["NFL"],
  "marketTypes": ["player-prop"],
  "playerNames": ["Josh Allen", "Jalen Hurts"],
  "maxRows": 500
}
```

### Output

One row per selection.

| Field | Example | Notes |
|---|---|---|
| `bookmaker` | `DraftKings` | DraftKings, Pinnacle, Underdog or Sleeper |
| `sport` | `football` | American football is `football`, association football is `soccer` |
| `league` | `NFL` | the big leagues get one name across all four sources, so Premier League reads the same everywhere |
| `event` | `NO Saints @ DET Lions` | away team first, in the book's own spelling |
| `homeTeam`, `awayTeam` | `DET Lions`, `NO Saints` | |
| `startTime` | `2026-09-13T17:00:00.000Z` | UTC. Empty on Sleeper rows |
| `gameDay` | `2026-09-13` | Sleeper rows only |
| `isLive` | `false` | `true` only when you include games already under way |
| `marketType` | `player-prop` | `moneyline`, `spread`, `total` or `player-prop` |
| `market` | `Passing Yards` | |
| `selection` | `Over` | a team, `Over`, `Under` or `Draw`. Underdog's Higher and Lower come through as Over and Under |
| `player` | `Jared Goff` | props only |
| `playerTeam` | `DET Lions` | when the book says |
| `line` | `259.5` | the spread, total or prop number. Empty for a moneyline |
| `oddsAmerican` | `-113` | |
| `oddsDecimal` | `1.885` | DraftKings' exact price to three places; worked out from the American odds for Pinnacle |
| `payoutMultiplier` | `1.6` | Underdog and Sleeper |
| `eventId`, `marketId`, `selectionId` | | the book's own ids, handy for matching one run against the next |
| `sourceUpdatedAt` | `2026-09-13T12:23:35.000Z` | when the book last changed the line, where it says (Underdog, Sleeper) |
| `scrapedAt` | `2026-09-13T14:25:04.238Z` | when this run read it |

The run also leaves a report, `RUN_REPORT`, in its key-value store: what each source returned, which leagues it read, what was left out and why, and why the run stopped.

### What you pay

Each row in your dataset is one charge. Nothing else is charged: not a source that doesn't answer, not rows your filters leave out, not games already under way while that box is off, and not a selection a book happens to list twice. If you set a maximum charge for the run, it stops when that's reached, and every row you get has been paid for. The price is on the Pricing tab.

### Limits

- 30,000 rows per run.
- Pinnacle lists close to 300 soccer leagues. Asking for all of soccer reads every one of them, which takes a few minutes, so name the leagues if you only want some.
- DraftKings player props are read one market at a time, about 30 for an NFL week, so props take longer than game lines.
- Underdog's board arrives as one download of about 25 MB, whatever you filter.

### Where the data comes from

Each book's own public odds, the same numbers its site or app shows. Treat them as information rather than advice, and check the price in the book before you bet, because odds can change between the run and your click. Whether you can bet at all depends on where you live.

### Questions

**Why are the odds columns empty on Sleeper rows?** Sleeper pays by multiplier: a pick at 1.6x pays 1.6 times its share of the entry. It doesn't publish odds, so the actor doesn't invent any.

**A price doesn't match what I see in the app.** Check `scrapedAt` first. Lines move, and a few minutes is plenty. DraftKings can also differ a little from state to state.

**Can I watch lines move?** Schedule the actor every few minutes and compare rows on `selectionId` from one run to the next. Each run is a fresh read of the board.

# Actor input Schema

## `sports` (type: `array`):

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.

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

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.

## `sources` (type: `array`):

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.

## `marketTypes` (type: `array`):

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.

## `playerNames` (type: `array`):

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.

## `startFrom` (type: `string`):

Only games that start on or after this day (UTC), written like 2026-09-13. Leave it empty for everything on the board.

## `startTo` (type: `string`):

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.

## `includeLive` (type: `boolean`):

Off, you get pre-game prices only. On, games that have started are included too, at whatever price the book showed at that second.

## `maxRows` (type: `integer`):

The most rows one run returns, shared fairly between the sources you keep. Each row is one charge.

## Actor input object example

```json
{
  "sports": [
    "football"
  ],
  "leagues": [
    "NFL"
  ],
  "sources": [
    "draftkings",
    "pinnacle",
    "underdog",
    "sleeper"
  ],
  "marketTypes": [
    "moneyline",
    "spread",
    "total",
    "player-prop"
  ],
  "includeLive": false,
  "maxRows": 200
}
```

# Actor output Schema

## `results` (type: `string`):

One row per selection: the book or app, sport, league, game, start time, market, player, selection, line, American and decimal odds or payout multiplier, and when it was read.

## `report` (type: `string`):

What each source returned, what was left out and why, and why the run stopped.

# 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 = {
    "sports": [
        "football"
    ],
    "leagues": [
        "NFL"
    ],
    "maxRows": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/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 = {
    "sports": ["football"],
    "leagues": ["NFL"],
    "maxRows": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/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 '{
  "sports": [
    "football"
  ],
  "leagues": [
    "NFL"
  ],
  "maxRows": 200
}' |
apify call dami_studio/sports-odds-scraper --silent --output-dataset

```

## MCP server setup

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