# Sports Odds Scraper: Moneyline, Spread and Total (`deriverge/sports-odds-scraper`) Actor

\[$1.50 / 1K] Betting lines for upcoming NFL, NBA, MLB, NHL, college football and soccer games: moneyline, spread and total with closing odds and the bookmaker, from a public source. Games without a line are dropped and never charged. Date ranges split into days. Changes only since your last run.

- **URL**: https://apify.com/deriverge/sports-odds-scraper.md
- **Developed by:** [deriverge s.r.o.](https://apify.com/deriverge) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## Sports Odds Scraper

### What does Sports Odds Scraper do?

**Sports Odds Scraper** returns the betting lines for upcoming games in the NFL, NBA, MLB, NHL, college football, the major soccer leagues and more, in one table. Every row has the moneyline for both sides, the spread with its odds, the total with the over and under odds, the bookmaker that set them and the game itself: teams, start time, venue and broadcasters.

No browser, no proxies, no API key. The lines come from a public sports data interface that publishes them for the games it lists.

### Only games that have a line

Lines normally appear one to two days before a game. A run over a whole month would return hundreds of games with no line yet, and most tools charge you for every one of them. This actor drops games without a line and never charges for them. What you get is the board as it stands right now.

### Several leagues in one run

Pass any list of league keys and the result is one table with the league on every row, so you can compare the board across sports without merging exports. Keys: `nfl`, `ncaaf`, `nba`, `wnba`, `ncaab`, `mlb`, `nhl`, `epl`, `laliga`, `bundesliga`, `seriea`, `ligue1`, `mls`, `ucl`, `ufc`, `pga`, `f1` and the rest of the catalogue in the multi-sport actor.

### Line movement, only when it moves

Give the run a watch name or save it as a task and schedule it hourly. Each run compares against the previous snapshot and returns only games that are new or whose status or score moved, so a line-tracking task bills for changes and not for re-reading a static board.

### Input

```json
{
  "leagues": ["nfl", "nba", "mlb", "nhl"],
  "statusFilter": "scheduled",
  "oddsOnly": true,
  "dateFrom": "2026-09-23",
  "dateTo": "2026-09-30",
  "newOnly": false
}
```

### Output

```json
{
  "key": "espn:nfl:401872963",
  "league": "nfl",
  "name": "Philadelphia Eagles at Chicago Bears",
  "startsAt": "2026-09-29T00:15:00.000Z",
  "home": { "name": "Chicago Bears", "shortName": "CHI", "record": "1-1" },
  "away": { "name": "Philadelphia Eagles", "shortName": "PHI", "record": "2-0" },
  "odds": {
    "provider": "DraftKings",
    "details": "PHI -4.5",
    "spread": 4.5,
    "overUnder": 43.5,
    "homeMoneyLine": 180,
    "awayMoneyLine": -215,
    "homeSpreadLine": 4.5,
    "homeSpreadOdds": -110,
    "awaySpreadLine": -4.5,
    "awaySpreadOdds": -110,
    "overOdds": -110,
    "underOdds": -110,
    "favorite": "away"
  },
  "url": "https://www.espn.com/nfl/game/_/gameId/401872963/eagles-bears"
}
```

Odds are American style, exactly as the bookmaker publishes them. A field the source does not publish is `null`, never a guess.

### Pricing

| Event | Price |
|---|---|
| Game with a line returned | $0.003, falling to $0.0015 on higher plans |
| Games without a line, games removed by the status filter, games unchanged in change mode | **free** |

No start fee. A run that returns nothing costs nothing.

### Frequently asked questions

**Which bookmaker are the lines from?** The one the source shows for that game, named in `provider` on every row. In practice that is a major US sportsbook.

**How far ahead are lines available?** Usually one to two days for daily sports and the whole week for the NFL. Games beyond that come back without a line and are dropped by this actor.

**Can I get live in-play odds?** No. The lines are the pre-game board. Once a game starts the line field is no longer updated by the source.

**Can I track how a line moves?** Schedule the run with a watch name. Each row carries the line at run time, so consecutive runs give you the sequence, and the change mode tells you which games moved.

### How to use Sports Odds Scraper

1. Open the actor and pick the leagues in the input form, or paste the JSON input from the example above.
2. Click **Start**. The first rows appear in the **Output** tab within seconds; the run summary is in the **Storage** tab under the key `SUMMARY`.
3. Download the results as JSON, CSV or Excel from the Output tab, or read them through the API link shown there.
4. To run it on a schedule, click **Save as a task**, set the input once and add a schedule.

### Integrations

The actor is available in the Apify apps for **Make**, **Zapier**, **n8n** and **Keboola**, where you pick it by name and map the input fields. It is also exposed to AI agents through the Apify MCP server, and callable from any language through the Apify API; the API tab on this page has ready-made snippets for Node.js, Python and curl. Every run can post its results to a webhook when it finishes.

### Support

Questions and problems go into the **Issues** tab of this actor. Each issue is answered by the maintainer, and fixes ship as new builds without any change on your side.

Every sport and every mode is in **Sports Data Scraper**, the multi-sport actor this one is built from.

Built and operated by deriverge s.r.o. Same rules as our other actors: unified schema, honest billing, no charge for what you did not get.

# Actor input Schema

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

Which leagues to read. Use the short key: mlb, nba, wnba, ncaab, gleague, nhl, nfl, ncaaf, pga, lpga, f1, indycar, ufc, pfl, atp, wta, epl, laliga, bundesliga, seriea, ligue1, mls, ucl, cricket-worldcup, nll. Leave empty for the default league of this actor.

## `mode` (type: `string`):

Games and results is the live and finished fixture list. League table is one row per team with its record. Teams lists the clubs. Rosters and schedules read the teams given below, or every team in the league when none are given.

## `dateFrom` (type: `string`):

First day of the fixture range. ESPN answers one day per request, so the actor splits the range into days and merges the results. Leave both dates empty for today. You can also give a moving date instead of a fixed one: today, tomorrow, yesterday, or a day offset such as +7 or -3. A saved run or a schedule then keeps returning the current fixtures instead of going empty once the dates pass.

## `dateTo` (type: `string`):

Last day of the fixture range, inclusive. Ranges longer than 120 days are cut at 120 so a typo cannot run up a bill. You can also give a moving date instead of a fixed one: today, tomorrow, yesterday, or a day offset such as +7 or -3. A saved run or a schedule then keeps returning the current fixtures instead of going empty once the dates pass.

## `statusFilter` (type: `string`):

Games removed by this filter are never charged.

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

Team abbreviations or numeric identifiers for the roster and schedule modes, for example "nyy" or "6". Run the Teams mode once to get the list. Leave empty to read every team in the league.

## `season` (type: `integer`):

Season for the schedule mode, for example 2026. Leave empty for the current season.

## `includeGameDetail` (type: `boolean`):

Adds team statistics, the injury list, headlines and the last play to every game. Costs one extra request per game and is charged as a separate event, so turn it on only when you need it.

## `newOnly` (type: `boolean`):

Keeps a snapshot per watch name (or per saved task) and returns only rows that are new or whose status or score moved. Schedule it every few minutes and you have a live feed that bills only for real changes.

## `watchKey` (type: `string`):

Name of the snapshot used by the change mode, for example "my-league". Runs from a saved task get a snapshot automatically even without a name.

## `maxItems` (type: `integer`):

Hard cap on returned rows across all leagues in the run.

## `oddsOnly` (type: `boolean`):

Drops games the source has no betting line for. Lines normally appear one to two days before a game. Dropped rows are never charged.

## Actor input object example

```json
{
  "leagues": [
    "nfl",
    "nba",
    "mlb",
    "nhl",
    "ncaaf",
    "epl"
  ],
  "mode": "scoreboard",
  "statusFilter": "scheduled",
  "includeGameDetail": false,
  "newOnly": false,
  "maxItems": 2000,
  "oddsOnly": true
}
```

# Actor output Schema

## `rows` (type: `string`):

One row per game, team, athlete, standing or article, in one schema across every sport.

## `changes` (type: `string`):

Rows that appeared, disappeared or whose status or score moved compared with the previous snapshot of the same watch name or task.

## `summary` (type: `string`):

Per-league request counts, skipped leagues with reasons, and totals.

# 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",
        "nba",
        "mlb",
        "nhl",
        "ncaaf",
        "epl"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("deriverge/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 = { "leagues": [
        "nfl",
        "nba",
        "mlb",
        "nhl",
        "ncaaf",
        "epl",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("deriverge/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 '{
  "leagues": [
    "nfl",
    "nba",
    "mlb",
    "nhl",
    "ncaaf",
    "epl"
  ]
}' |
apify call deriverge/sports-odds-scraper --silent --output-dataset

```

## MCP server setup

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