# DraftKings Player Props Scraper & Line Movement Monitor (`neverempty/draftkings-line-movement-monitor`) Actor

DraftKings odds API for player props, alternate lines and game lines (moneyline, spread, total) across NFL, NBA, MLB, NHL, college and soccer. Turn on monitoring and each later run returns only the prices that moved, with the previous and current odds and line.

- **URL**: https://apify.com/neverempty/draftkings-line-movement-monitor.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Sports, Developer tools, Automation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 price 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## DraftKings Player Props Scraper & Line Movement Monitor

**A DraftKings odds API for player props, alternate lines and game lines: pick a league (NFL, NBA, MLB, NHL, college, soccer and more) and get every DraftKings price as a flat JSON row - market, selection, player, line, American and decimal odds, start time.** Turn on monitoring to track line movement on DraftKings: after a free first run, each scheduled run returns only the selections whose odds or line moved since the last run, with the previous value, the current value and the size of the move, plus any market that newly appeared.

Built for bettors, prop modellers, odds-screen and Discord-alert builders, and analysts who want DraftKings props and line moves in a spreadsheet, database or bot without copying them by hand.

### What you get

- **Player props** - passing, rushing and receiving yards, receptions, touchdown scorers, kicking and defensive props (NFL, college football), batter and pitcher props (MLB), goalscorers and goalie props (NHL), player points, rebounds and threes (NBA), both the over/under line and the milestone ladders ("250+ yards").
- **Alternate lines** - every alternate spread and alternate total DraftKings has posted for a game, each point on its own row.
- **Game lines** - moneyline, spread and total for every game on a league board, from a single request per league.
- **Any other DraftKings category by name** - Quarters, Halves, Team Props, Game Props and so on.
- **Line movement** - in monitoring mode a row says what changed (`odds-moved`, `line-moved`, `line-and-odds-moved`, `new-selection`, `new-market`) and carries `previousLine`, `previousOddsAmerican`, `previousOddsDecimal`, `lineMove`, `oddsDecimalMove` and when the previous price was seen.

One row is one selection, so the output drops straight into a sheet or a database table with no nested arrays to unpack.

### Why this Actor

- **Props and alternate lines, not just the headline line.** Game lines come from the league board; props and alternate lines are read game by game, only for the categories each game actually has, so no request is spent on markets that are not posted yet.
- **Pay for moves, not for repeats.** With monitoring on, unchanged prices are not returned and not charged. If nothing at all moved, the run charges one small monitoring check per league instead of re-selling the same board.
- **Stable keys for tracking.** DraftKings changes a selection's ID when its line moves; this Actor follows each selection by market, side, player and label (`selectionKey`), so a spread moving from -3 to -3.5 shows up as one `line-moved` row, not as a disappearing and a new selection.
- **Clean numbers.** DraftKings prints negative American odds with a typographic minus sign; every row carries real numbers (`oddsAmerican: -112`, `oddsDecimal: 1.89`, `impliedProbability: 0.5291`).
- **Every empty result explains itself** in a free row: off-season league, unknown league ID, a game that is no longer on the board, a page DraftKings refused.

### Input

| Field | What it does |
|---|---|
| `leagues` | Short names (`nfl`, `ncaaf`, `nba`, `wnba`, `ncaab`, `mlb`, `nhl`, `mls`, `epl`, `laliga`, `bundesliga`, `seriea`, `ligue1`, `ucl`, `ligamx`, `ufc`, `euroleague`) or any DraftKings league ID (`88808` is the NFL). |
| `marketGroups` | `game-lines`, `alternate-lines`, `player-props`. Empty = game lines only. |
| `extraCategories` | Other DraftKings categories by name, for example `Quarters`, `Team Props`. |
| `maxGamesPerLeague` | How many games per league are opened for props and alternate lines, soonest first (default 10). |
| `maxRows` | Cap on returned rows (default 1000). |
| `monitoringMode` | Return only what moved since the previous run with the same input. |
| `resetMonitoringState` | Start monitoring over from a fresh starting point. |
| `minOddsMove` | Monitoring: return an odds move only once it reaches this size in decimal odds, measured from the last value you received, so small moves add up instead of being lost. Line moves and new markets are always returned. |
| `eventIds`, `teams`, `players`, `marketNames`, `excludeMarketNames` | Narrow down to games, teams, players or market names. |

Example - NFL game lines and player props for the next three games:

```json
{ "leagues": ["nfl"], "marketGroups": ["game-lines", "player-props"], "maxGamesPerLeague": 3, "maxRows": 300 }
```

Example - track one quarterback's props every 15 minutes:

```json
{ "leagues": ["nfl"], "marketGroups": ["player-props"], "players": ["Mahomes"], "monitoringMode": true }
```

### Output

A player-prop row (values as DraftKings listed them on 2026-10-12):

```json
{
  "status": "ok",
  "changeType": null,
  "sport": "Football",
  "league": "nfl",
  "leagueName": "NFL",
  "leagueId": "88808",
  "eventId": "34118277",
  "eventName": "SEA Seahawks @ DEN Broncos",
  "startTime": "2026-10-16T00:15:00.000Z",
  "eventStatus": "NOT_STARTED",
  "homeTeam": "DEN Broncos",
  "awayTeam": "SEA Seahawks",
  "marketGroup": "player-props",
  "categoryName": "Passing Props",
  "marketName": "Sam Darnold Passing + Rushing Yards O/U",
  "marketType": "Passing + Rushing Yards O/U",
  "isPlayerProp": true,
  "isAlternateLine": false,
  "isMainLine": true,
  "selectionLabel": "Over",
  "outcomeType": "Over",
  "playerName": "Sam Darnold",
  "line": 225.5,
  "oddsAmerican": -112,
  "oddsDecimal": 1.89,
  "oddsFractional": "25/28",
  "impliedProbability": 0.5291
}
```

In monitoring mode the same row comes back only when it changes, for example with `"changeType": "odds-moved"`, `"previousOddsAmerican": -112`, `"oddsAmerican": -125`, `"previousOddsDecimal": 1.89`, `"oddsDecimal": 1.8`, `"oddsDecimalMove": -0.09`.

Every row also has `marketId`, `selectionId`, `selectionKey`, `playerId`, `sourceUrl` and `scrapedAt`.

### Pricing

Pay per event:

- **`line-returned`** - one returned price row (one selection). Rows dropped by your filters are not charged.
- **`league-checked`** - monitoring only, and only when a run finds that nothing moved: one per league compared. The first monitoring run, which only records the starting point, is free, and so is every run that returns at least one moved price.

Free rows (never charged) explain empty results: `no-such-league`, `no-events`, `event-not-found`, `blocked`, `unreadable`, `no-filter-match`, `no-markets-yet`, `no-line-move`, `baseline-saved`, `budget-reached`, `row-limit-reached`.

### Scheduling a line-movement monitor

1. Run once with `monitoringMode: true` - it remembers the current prices and returns a free `baseline-saved` row.
2. Save the input as a task and schedule it (every 5, 15 or 60 minutes).
3. Each run returns only moves and new markets. Connect the dataset to a webhook, Google Sheets, Slack or your own API.

Monitoring memory is kept per input (leagues, market groups, extra categories, games and `maxGamesPerLeague`), so different watch lists do not interfere. Prices that did not fit within `maxRows` or the maximum charge are not marked as seen and are returned on the next run.

### Good to know

- This is an unofficial tool and is not affiliated with DraftKings. It reads only the public odds that the DraftKings Sportsbook website shows to any visitor, with no login. It is not betting advice.
- Prices are DraftKings' New Jersey board. When this Actor was built, the New York, Pennsylvania and Ohio boards returned the same prices for the NFL.
- Player props and alternate lines are posted closer to the game, often a few days before kick-off; a game far in the future may have game lines only. Off-season leagues return a free `no-events` row.
- Props and alternate lines are read game by game, so a full league with many games takes longer and costs more requests than game lines; `maxGamesPerLeague` keeps runs short.
- Odds move quickly once a game is live. A monitoring run is a snapshot at the moment it runs; moves between two runs are reported as one move from the old value to the new value.
- If DraftKings refuses a page several times in a row, that page is reported in a free row and nothing is guessed.

### Thanks for using this Actor

We build these tools for people who run them every day, and we improve them from what users tell us.

- **Missing a field, or need another filter?** Tell us in the **Issues** tab. If the data is there, we add it.
- **Found a bug or a wrong value?** Post the run ID in the **Issues** tab. Wrong data is the thing we fix first.

If this Actor saved you time, a short review helps other people find it.

# Actor input Schema

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

Which DraftKings leagues to read. Use a short name (nfl, ncaaf, nba, wnba, ncaab, mlb, nhl, mls, epl, laliga, bundesliga, seriea, ligue1, ucl, ligamx, ufc, euroleague) or the league ID from a DraftKings league page address (88808 is the NFL). At least one is needed; a name that is not recognised comes back as a free row that says so.

## `marketGroups` (type: `array`):

game-lines = moneyline, spread and total for every game on the league board (one request per league). alternate-lines = every alternate spread and total DraftKings has posted. player-props = player markets such as passing, rushing and receiving yards, touchdown scorers, batter and pitcher props, goalscorers and player points. Empty = game-lines only.

## `extraCategories` (type: `array`):

Any other DraftKings category to read for each game, by its name as shown on the DraftKings page, for example Quarters, Halves, Team Props or Game Props. Case does not matter. Empty = none.

## `maxGamesPerLeague` (type: `integer`):

Player props and alternate lines are read game by game, soonest kick-off first, so this caps how many games are opened per league. Game lines always cover the whole league board. Default 10.

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

How many rows to return in total. One row is one selection, for example 'Over 225.5' in one player's passing yards market. You are charged only for the rows you receive. Default 1000.

## `monitoringMode` (type: `boolean`):

Off = return every current price. On = the first run remembers today's prices for free, and every later run with the same leagues and markets returns only selections whose odds or line changed (with the previous and current value and the size of the move) plus markets that newly appeared. Run it on a schedule to follow line movement.

## `resetMonitoringState` (type: `boolean`):

Forget the remembered prices for this input before the run. With monitoring on, the run then records a fresh starting point.

## `minOddsMove` (type: `number`):

Monitoring only: return a moved price only if its decimal odds moved at least this much, for example 0.05. Line moves and new markets are always returned. 0 = every move.

## `eventIds` (type: `array`):

Limit the run to these games, by the DraftKings event ID (the number at the end of a DraftKings game page address, also in the eventId column). Empty = every game on the chosen league boards.

## `teams` (type: `array`):

Keep a row only if the game name or either team contains one of these (case-insensitive, partial), for example Chiefs or KC. Empty = all teams.

## `players` (type: `array`):

Keep only player-prop rows for players whose name contains one of these (case-insensitive, partial), for example Mahomes. Empty = all players and non-player markets.

## `marketNames` (type: `array`):

Keep a row only if the market name, market type or DraftKings subcategory contains one of these (case-insensitive), for example Passing Yards, Receptions or Alternate Spread. Empty = all markets.

## `excludeMarketNames` (type: `array`):

Drop a row if the market name, market type or subcategory contains any of these (case-insensitive), for example Milestones or 1st Quarter. Empty = drop nothing.

## Actor input object example

```json
{
  "leagues": [
    "nfl"
  ],
  "marketGroups": [
    "game-lines",
    "player-props"
  ],
  "maxGamesPerLeague": 3,
  "maxRows": 300,
  "monitoringMode": false,
  "resetMonitoringState": false,
  "minOddsMove": 0
}
```

# Actor output Schema

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

One row per DraftKings selection: league, game (DraftKings event ID, name, start time, status, home and away team), market group (game-lines, alternate-lines, player-props or other), DraftKings category, subcategory, market name and type, the selection label, side and player, the line, American, decimal and fractional odds and the implied probability. In monitoring mode each row also says what changed (odds-moved, line-moved, line-and-odds-moved, new-selection, new-market) with the previous line and odds and the size of the move. Empty results come back as free rows that say why.

# 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"
    ],
    "marketGroups": [
        "game-lines",
        "player-props"
    ],
    "maxGamesPerLeague": 3,
    "maxRows": 300
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/draftkings-line-movement-monitor").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"],
    "marketGroups": [
        "game-lines",
        "player-props",
    ],
    "maxGamesPerLeague": 3,
    "maxRows": 300,
}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/draftkings-line-movement-monitor").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"
  ],
  "marketGroups": [
    "game-lines",
    "player-props"
  ],
  "maxGamesPerLeague": 3,
  "maxRows": 300
}' |
apify call neverempty/draftkings-line-movement-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/draftkings-line-movement-monitor"
        }
    }
}
```

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/7VgnNCHibCmPGWBX8/builds/Xk2Vs5P6qrx2DPwYG/openapi.json
