# Sleeper Player Props Scraper - Lines, Odds & Line Moves (`neverempty/sleeper-player-props-scraper`) Actor

For betting-model builders: every line on Sleeper's Picks board as one row - player name, team, stat, line value and the over and under payout multipliers. 2,855 lines across 9 sports in one request on 2026-09-22. Monitoring returns only the lines that moved, with the previous value.

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

## Pricing

from $0.11 / 1,000 line 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

## Sleeper Player Props Scraper - Lines, Odds & Line Moves

For betting-model builders and sports-data teams: every line on Sleeper's Picks board as one row - player id and name, team, position, sport, game id, stat, line value, the over and the under payout multiplier, line and game status, how the crowd is picking it, and the recent games Sleeper shows beside it. One request returned **2,855 lines** across **9 sports** with **5,710 over/under sides** on 2026-09-22. You get the whole board in a single run, and in monitoring mode only the lines that actually moved, each carrying its own previous value - so you can diff a board without storing it yourself.

Export as JSON, CSV or Excel.

### What one row contains

| Column | What it is |
| --- | --- |
| `lineKey` | Stable id of this line: sport, game, player and market. It does **not** change when the price moves, so you can join runs on it. |
| `sport`, `league` | Sleeper's own value (`nfl`, `cfb`, `clubsoccer:mls`) and a short league name (`NFL`, `CFB`, `MLS`). |
| `gameId`, `gameStatus` | Sleeper's game id and state. Sleeper does not publish the two team names in this feed, so the game id is how you group the lines of one match. |
| `playerId`, `playerName`, `playerFirstName`, `playerLastName` | The id is always there; the names come from Sleeper's player record, which this Actor reads for you. `playerDetailsFound` says whether the name was actually found. |
| `playerTeam`, `playerPosition`, `playerPositionRank`, `playerTeamFull`, `playerStatus` | Team code and position as written on the line, plus the team and status from the player record. |
| `statType`, `statLabel`, `marketType` | Sleeper's stat (`receiving_yards`), the same value formatted (`Receiving Yards`), and the raw market key. |
| `lineValue`, `overLineValue`, `underLineValue` | The number the pick is over or under. Every side read on 2026-09-22 sat on a half point. |
| `overPayoutMultiplier`, `underPayoutMultiplier` | What one unit of stake returns on each side, as a decimal. On 2026-09-22 the range was **1.15** to **3.53** and 1.78 was the most common. |
| `overLineId`, `underLineId`, `overStatus`, `underStatus`, `lineStatus`, `optionCount`, `outcomes` | Sleeper's own ids and states for each side. |
| `pickPopularity`, `pickCountOver`, `pickCountUnder`, `pickCountTotal` | How Sleeper's users are picking this line, when Sleeper publishes it (1,718 of the 2,855 lines carried it). |
| `recentPerformance`, `recentGamesCount`, `recentAverage` | The recent games Sleeper shows next to the line (date, opponent, value) and their mean. |
| `updatedAt`, `updatedAtMs`, `scrapedAt` | When Sleeper last touched the line, and when this run read it. |
| `isNewSinceLastRun`, `changedFields`, `previousLineValue`, `lineValueChange`, `previousOverPayoutMultiplier`, `overPayoutMultiplierChange`, `previousUnderPayoutMultiplier`, `underPayoutMultiplierChange`, `previousLineStatus`, `previousGameStatus`, `previousSeenAt` | Filled in monitoring mode: what moved, what it was before, and by how much. |

### Inputs

| Input | What it does |
| --- | --- |
| `sports` | Keep only these sports, written as Sleeper writes them (`nfl`, `cfb`, `mlb`, `clubsoccer:mls`). The short league name (`MLS`) works too. Empty = every sport on the board. |
| `players` | Keep only these players. Part of a name is enough; a Sleeper player id (digits only) is matched without looking any name up. |
| `statTypes` | Keep only these stats (**49** stat types were on the board). Spaces and underscores are the same: `receiving yards` = `receiving_yards`. |
| `teams` | Keep only players on these teams, written as they appear on the line (`KC`, `GB`). Individual sports carry no team, so those lines drop out. |
| `gameIds` | Keep only these Sleeper game ids (**113** games were on the board). |
| `gameStatuses` | Keep only games in these states. Every line read on 2026-09-22 was `pre_game`. |
| `keywords` / `keywordMatch` / `excludeKeywords` | Keep or drop lines by words in the player name, team, position, stat, market type, league or sport. `any` or `all`. |
| `minPayoutMultiplier` / `maxPayoutMultiplier` | Keep only lines where the over or the under pays inside this band. Lines with no multiplier drop out when you set either. |
| `maxLines` | Stop after this many line rows (monitoring mode ignores it, so nothing is silently left behind). |
| `includePlayerDetails` | Look up each returned player's name, team and status. On by default; Sleeper's line feed has only the id. |
| `includeRecentPerformance` | Include the recent games Sleeper shows beside the line, with their count and mean. |
| `playerLookupCap` | How many player records one run may read. Rows past it keep the id, team and position and say so in a free row. |
| `monitoringMode` | Return only the lines that moved since the last run with the same filters. |
| `onlyLineValueMoves` / `minLineValueMove` | Narrow what counts as a move: line value only, and by at least this much. |
| `resetMonitoringState` | Forget everything remembered and start over on the next run. |
| `requestTimeoutSecs` / `maxRetries` | How long one request to Sleeper may take, and how many attempts it gets. |
| `useProxy` | Route through an Apify datacenter address and take a new session on each retry. Off by default; every measurement so far went through without it. |

### Filtering

Everything is filtered inside this Actor, after the board has been read: `sports`, `players` (name or Sleeper id), `statTypes` (**49** stat types were on the board), `teams`, `gameIds` (**113** games), `gameStatuses`, `keywords` / `excludeKeywords`, and a payout-multiplier band.

Sleeper's own `sport` parameter is ignored by its server - asking for `sport=nfl` returned the same whole board with baseball first - so filtering server-side is not possible here and this Actor does not pretend otherwise.

### Monitoring mode

Turn `monitoringMode` on and schedule the run. The Actor remembers, for your exact set of filters, the line value, both payout multipliers, the line status and the game status of every line it read. Later runs return only the lines that moved, that changed status, or that are new - each with its earlier values in the same row. The first run returns every matching line once as a baseline.

Pick popularity and pick counts are deliberately **not** watched. Reading the same board twice 120 seconds apart on 2026-09-22 changed the popularity of 1,060 lines and the pick counts of 143, against 18 payout moves and 1 line-value move. Watching the crowd numbers would hand you almost the whole board on every poll.

`onlyLineValueMoves` and `minLineValueMove` narrow it further. A line that moved but not far enough keeps its **earlier** remembered value, so two moves of 0.5 add up to 1 and the line reaches you; the free row of a run with nothing to return says how many lines moved too little. `resetMonitoringState` forgets everything and starts over.

Do not put the same filters in two schedules that can run at the same time: Apify's key-value store has no atomic update, so two runs finishing together can lose part of what one of them remembered, and a few lines can come back once more as new. The Actor writes its memory, reads it back and retries up to three times, and warns in the log if it still cannot confirm it.

### Reliability

Sleeper's available-lines feed is 5.28 MB of JSON and its speed swings: 14.2 s and 14.6 s through an Apify datacenter proxy on 2026-09-22, but under 2 s straight from an Apify container on 2026-09-23. Timeouts, refusals and 5xx answers are retried (`maxRetries`, default 4, waiting 1.5 s, 3 s and 4.5 s), the per-request timeout is yours to set (`requestTimeoutSecs`, default 90 s), and `useProxy` takes a fresh Apify datacenter session on every retry if you ever need it.

A run that could never read the feed is **not charged at all** - not even the run start. Runs that read the board and found nothing to return charge the run start only, and say why in a free row.

### Rows that are free

Nothing is guessed and nothing empty is sold. These rows are written to the dataset and never charged: an empty board (`no-results`), a feed that could not be read (`unreadable`), lines with no usable side (`no-usable-option`), a sport you asked for that is not on the board (`unknown-sport`, with the sports that are), filters that matched nothing (`no-filter-match`), a monitoring run with no move (`no-line-move`), the `maxLines` or player-lookup cap (`not-returned-limit`), and the run's own charge limit (`charge-limit-reached`).

### Pricing

Two events: one per line row returned, and one per run start. The run start is charged only after Sleeper's feed has actually been read, so a run that fails to read it costs nothing. In monitoring mode you pay the run start plus only the lines that moved - a poll that finds no move costs one run start.

### Sister Actors

Same shelf, same build: **Sports Betting Odds Scraper** (sportsbook spreads, totals and money lines with the opening line beside the current one), **ESPN Injury Report Scraper**, **UFC Stats Scraper** and **Kalshi Markets Scraper**.

### Notes

Unofficial. Public data only. This Actor is not affiliated with, endorsed by or connected to Sleeper. It reads `api.sleeper.app`, which is served without a login; `api.sleeper.app/robots.txt` was fetched on 2026-09-23 and every line in it is a comment, so it sets no rule. Nothing behind a login is touched and no personal data is collected: the people in the output are professional athletes, named as Sleeper names them.

This Actor reports what Sleeper publishes. It is data, not advice, and it does not tell you what to pick. Every number in this README was measured from the feed itself on 2026-09-22 and 2026-09-23 and is a snapshot of that moment: how many lines are on the board, and which sports, change with the season and with the day.

# Actor input Schema

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

Keep only lines for these sports, one per line. Sleeper's own values are used, so write them exactly as Sleeper does: nfl, cfb, mlb, wnba, cs, tennis, mma, golf, clubsoccer:mls (those nine were on the board on 2026-09-22; which ones appear depends on the season). The short league name works too (MLS for clubsoccer:mls). Leave empty for every sport on the board. Sleeper's own sport parameter is ignored by its server, so this Actor filters in its own process after reading the board.

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

Keep only lines for these players, one per line. A part of a name is enough and case does not matter, for example 'mahomes'. A Sleeper player id (digits only, for example 1111) also works and is faster, because ids are matched without looking any name up. Leave empty for every player.

## `statTypes` (type: `array`):

Keep only these stats, one per line. Sleeper's own values are used and spaces work like underscores, so 'receiving yards' and 'receiving\_yards' both match. 49 stat types were on the board on 2026-09-22, the most common being anytime\_touchdowns, total\_bases, hits\_runs\_rbis, singles, runs, hits, rbis, bat\_walks, receiving\_yards, points, rushing\_yards, rebounds, receptions, pts\_reb\_ast, threes\_made, assists, passing\_yards, strike\_outs. Leave empty for every stat.

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

Keep only lines whose player is on one of these teams, one per line, written the way Sleeper writes them on the line: KC, GB, ATL, CWS, LAD. 138 team codes were on the board on 2026-09-22. Individual sports (tennis, golf, MMA) carry no team, so those lines are removed when you set this.

## `gameIds` (type: `array`):

Keep only lines of these Sleeper game ids, one per line (the gameId column of an earlier run). 113 games were on the board on 2026-09-22. Sleeper does not publish the two teams of a game in this feed, so the game id is the way to group lines of one match.

## `gameStatuses` (type: `array`):

Keep only lines whose game is in one of these states, one per line. Every one of the 2,855 lines read on 2026-09-22 was pre\_game, because Sleeper's available-lines feed drops a market once the game is under way. Leave empty for every state.

## `keywords` (type: `array`):

Keep only lines whose player name, team, position, stat, market type, league or sport contains these words (case-insensitive). Using this looks the player names up before filtering, which costs one small request per player in the run.

## `keywordMatch` (type: `string`):

any = a line is kept when it contains at least one keyword. all = it must contain every keyword.

## `excludeKeywords` (type: `array`):

Drop lines that contain any of these words in the same fields as Keywords.

## `minPayoutMultiplier` (type: `number`):

Keep only lines where the over or the under pays at least this multiple of the stake. Sleeper publishes the multiplier as a decimal (on 2026-09-22 the 5,710 over and under sides ranged from 1.15 to 3.53, and 1.78 was the most common), so 2 keeps only the lines that pay at least double on one side. 0 = do not filter. Lines with no multiplier are removed when you set this.

## `maxPayoutMultiplier` (type: `number`):

Keep only lines where the over or the under pays at most this multiple of the stake. 0 = do not filter.

## `maxLines` (type: `integer`):

With monitoring off, the run stops once this many line rows have been returned, and a free row says how many more matched. Free rows do not count. In monitoring mode this is ignored, because cutting the changed lines would mean the ones left out never reach you.

## `includePlayerDetails` (type: `boolean`):

On = the Actor reads Sleeper's player record for each player it returns and fills playerName, playerFirstName, playerLastName, playerTeamFull and playerStatus. Sleeper's line feed carries only a player id, a team code and a position, so without this the rows have no names. One small request per player (about 1 KB, measured 0.17-0.62 s), at most five at a time. The whole board held 837 players on 2026-09-22, in 863 sport-and-id pairs. Off = faster and no extra requests, and playerDetailsFound stays empty.

## `includeRecentPerformance` (type: `boolean`):

On = each row carries recentPerformance (the last games Sleeper shows next to the line, with date, opponent and the value of that stat), recentGamesCount and recentAverage. Every one of the 2,855 lines read on 2026-09-22 carried this block. Off = smaller rows.

## `playerLookupCap` (type: `integer`):

How many player records the run may read at most. Rows beyond it keep Sleeper's player id, team and position and have playerName empty, and a free row says so. The whole board held 837 players on 2026-09-22, in 863 sport-and-id pairs.

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

Off = every line that matches your filters comes back, charged per row. On = the Actor remembers the line value, the over and under payout multipliers, the line status and the game status of every line it read for these filters, and later runs return only lines that moved, whose status changed, or that are new, each with its earlier values in the same row. The first run returns every matching line once as a baseline (the whole board was 2,855 lines on 2026-09-22). Pick popularity and pick counts are deliberately not watched: reading the same board twice 120 seconds apart changed the popularity of 1,060 lines and the pick count of 143, against 18 payout moves and 1 line-value move, so watching them would return almost the whole board every time. Do not put the same filters in two schedules that can run at the same time (Apify's key-value store has no atomic update, so this cannot be fully prevented).

## `onlyLineValueMoves` (type: `boolean`):

Monitoring mode: return a line only when its line value moved (for example 16.5 to 17.5), and ignore moves in the payout multipliers alone. New lines are always returned.

## `minLineValueMove` (type: `number`):

Monitoring mode: return a line only when its line value moved by at least this much. Sleeper publishes every line value on a half point (all 5,710 sides read on 2026-09-22 ended in .5), so 1 means a full point and 0.5 the smallest move there is. 0 = any move. Small moves add up: two moves of 0.5 count as 1. New lines are always returned.

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

Clears everything this Actor remembered for monitoring, so the next monitoring run returns every line again as a first check. This affects all your monitoring runs of this Actor. Turn it off again after one run: left on in a schedule, every run returns every line again and charges for it.

## `requestTimeoutSecs` (type: `integer`):

How long one request to Sleeper may take before it is retried. Sleeper's available-lines feed is 5.28 MB of JSON and its speed swings: 14.2 s and 14.6 s through an Apify datacenter proxy on 2026-09-22, but under 2 s straight from an Apify container on 2026-09-23. Raise this if you see timeouts in the log.

## `maxRetries` (type: `integer`):

How many times one request is attempted before the run gives up on it, waiting 1.5 s, 3 s and 4.5 s in between. Timeouts, refusals and 5xx answers are retried; a run that could never read the feed is not charged at all.

## `useProxy` (type: `boolean`):

Off = the run talks to Sleeper directly, which was enough in every measurement (200 on every attempt). On = an Apify datacenter address is used and a new session is taken on each retry. Turn it on only if you see refusals in the log; proxy traffic is billed by Apify on top of this Actor.

## Actor input object example

```json
{
  "keywordMatch": "any",
  "maxLines": 1000,
  "includePlayerDetails": true,
  "includeRecentPerformance": true,
  "playerLookupCap": 1500,
  "monitoringMode": false,
  "onlyLineValueMoves": false,
  "resetMonitoringState": false,
  "requestTimeoutSecs": 90,
  "maxRetries": 4,
  "useProxy": false
}
```

# Actor output Schema

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

One row per Sleeper Picks line: player id and name, team, position, sport, league, game id, stat, line value, over and under payout multipliers, line and game status, pick popularity and counts, the recent games Sleeper shows, and when Sleeper last updated it. In monitoring mode only lines whose line value, payout multipliers, line status or game status moved, with the earlier values in the same row. An empty board, a filter that matched nothing, a run with no move, a failed read and a limit 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/sleeper-player-props-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/sleeper-player-props-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 '{}' |
apify call neverempty/sleeper-player-props-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/sleeper-player-props-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/RXrjygaKa67sv1bNy/builds/FiQgJ1eVrcJz14Jye/openapi.json
