# Action Network Odds, Betting Splits & Line Movement Scraper (`artsiom_k/actionnetwork-scraper`) Actor

Sports betting odds from every major US sportsbook, public money/ticket percentages, scores, timestamped line movement and player props from Action Network - NFL, NBA, MLB, NHL, college and soccer, with incremental runs.

- **URL**: https://apify.com/artsiom\_k/actionnetwork-scraper.md
- **Developed by:** [Artsiom Kunitsyn](https://apify.com/artsiom_k) (community)
- **Categories:** Other, E-commerce
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 results

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?

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

## actionnetwork-scraper

Scrapes sports-betting data from [Action Network](https://www.actionnetwork.com): **odds from every major
US sportsbook**, the **public betting splits** (money and ticket percentages), scores and game status,
**timestamped line movement**, and **player and game props** — for the NFL, NCAA Football, NBA, NCAA
Basketball, WNBA, MLB, NHL and soccer. No login required.

### Contents

- [Key features](#key-features)
- [Output](#output)
- [Input](#input)
- [Input examples](#input-examples)
- [Line history: what to expect](#line-history-what-to-expect)
- [Incremental mode](#incremental-mode)
- [FAQ](#faq)

### 🔑 Key features

- **Odds from every book.** Moneyline, spread and total per game from Consensus, the opening line and the
  major US sportsbooks (DraftKings, FanDuel, BetMGM, BetRivers, Caesars, bet365 and more) — pick the books
  you want with `bookIds`. Alternate lines and team totals are included where the book lists them.
- **Public betting splits.** The share of bets (`tickets_pct`) and of money (`money_pct`) on each side of
  every market, so you can spot where the public and the money disagree.
- **Line movement.** Every odds and line change with its timestamp, per outcome, per sportsbook.
- **Player and game props.** Every prop market with every sportsbook's lines, player name and position.
- **Scores and status** for every game, with the winner.
- **Two ways to choose games.** Leave the dates empty for each league's current slate, walk a date range for
  the daily leagues, or a season and weeks for NFL and NCAA Football (regular season or playoffs).
- **Incremental runs.** Schedule the `games` data type: after the first run you only receive new games and
  games whose status, score or closing line changed.
- **`maxItems` defaults to 50** — a fast, cheap preview. Clear it (`null`) for everything in your scope.

### 📋 Output

Three data types, chosen with `entityType`. See [`.actor/dataset_schema.json`](.actor/dataset_schema.json)
for every field.

**`games`** — one row per game:

```json
{
  "source": "actionnetwork",
  "external_id": "256552",
  "league": "nfl",
  "season": 2025,
  "week": 1,
  "start_time": "2025-09-05T00:20:00.000Z",
  "away_team": "Dallas Cowboys",
  "home_team": "Philadelphia Eagles",
  "status": "complete",
  "away_score": 20,
  "home_score": 24,
  "winner": "home",
  "moneyline_home": -425,
  "spread_home": -8.5,
  "total_line": 47.5,
  "consensus": {
    "spread": {
      "home": {"odds": -110, "value": -8.5, "tickets_pct": 64, "money_pct": 72},
      "away": {"odds": -110, "value": 8.5, "tickets_pct": 36, "money_pct": 28}
    }
  },
  "books": [{"book_id": 68, "book": "DK NJ", "moneyline": {}, "spread": {}, "total": {}}],
  "change_type": "new"
}
```

**`lineHistory`** — one row per game, sportsbook and market line, with `outcomes[].history` as the
timestamped series `[{updated_at, odds, value, line_status}]`, the opening point and the number of moves.

**`props`** — one row per prop market (a player and stat, or a game-level prop) with `lines` listing every
sportsbook's odds and value.

### 🔧 Input

| Field | Type | Default | Description |
|---|---|---|---|
| `entityType` | string | `games` | `games`, `lineHistory` or `props`. |
| `leagues` | array | all 8 | NFL, NCAA Football, NBA, NCAA Basketball, WNBA, MLB, NHL, soccer. Out-of-season leagues return nothing. |
| `dateFrom` / `dateTo` | string | — | Game days (`YYYY-MM-DD`, US Eastern) for the daily leagues. Empty = the current slate. At most 400 days. |
| `season` | integer | — | NFL / NCAA Football season year. Setting it walks the weeks below. |
| `weekFrom` / `weekTo` | integer | 1 / end of season | Week range when `season` is set. |
| `seasonType` | string | `reg` | `reg` or `post` (playoffs / bowl games). |
| `bookIds` | array | site default | Restrict to these sportsbooks. Consensus is always kept because it carries the splits. |
| `maxItems` | integer | `50` | Stop after this many rows. `null` = everything in scope. |
| `mode` | string | `auto` | `auto` / `full` / `incremental` — `games` only. |
| `concurrency` | integer | `10` | Parallel requests (max 20). |
| `impersonate` | string | `firefox` | Browser TLS fingerprint. Change only if requests are blocked. |
| `proxyConfiguration` | object | no proxy | Apify Proxy settings. Not needed in testing. |

### 📥 Input examples

**Default preview (current slate of every league, first 50 games):**

```json
{}
```

**Today's MLB slate with only DraftKings and FanDuel:**

```json
{ "leagues": ["mlb"], "bookIds": ["68", "69"], "maxItems": null }
```

**A full NFL regular season of closing odds and betting splits:**

```json
{ "leagues": ["nfl"], "season": 2025, "maxItems": null }
```

**Daily incremental feed of new and changed games (schedule this):**

```json
{ "leagues": ["nfl", "mlb", "nba", "nhl"], "maxItems": null }
```

**Daily line-movement capture (schedule this):**

```json
{ "entityType": "lineHistory", "leagues": ["nfl", "mlb", "nba", "nhl"], "maxItems": null }
```

**NBA prop markets for a single night:**

```json
{ "entityType": "props", "leagues": ["nba"], "dateFrom": "2025-01-01", "maxItems": 2000 }
```

### 📈 Line history: what to expect

Action Network keeps the full timestamped line history for a game for only **a few days after it is
played**. Games from about a week ago come back with every outcome present but an empty history. That
makes `lineHistory` a **capture** product, not a backfill one: schedule it daily (or more often) and each
game's complete history — from the opening line to the close — is saved before the site drops it.

Closing odds, the final public betting splits, scores and props *are* kept much longer (roughly the last
two seasons for odds and splits; props for at least the past year), so `games` and `props` can be
back-filled for a season with the season/week or date inputs.

### 🔁 Incremental mode

`games` only, and only for a run with `maxItems` cleared (`null`) — a capped run is a preview and always returns games. In `auto` mode the first uncapped run returns every game in scope and remembers it. Later uncapped runs return
only new games and games whose **status, start time, score or closing consensus line** changed
(`change_type` is `new` or `changed`). The memory covers every league and date you have run and forgets
games that started more than 60 days ago. A run stopped by `maxItems`, by your spending limit or by an
error does not update it. `lineHistory` and `props` are always a fresh pull.

### ❓ FAQ

**Which sportsbooks are covered?** Consensus, Open (the opening line), DraftKings, FanDuel, BetMGM,
BetRivers, Caesars, bet365 and Unibet across several states. Pick them in `bookIds`.

**Why is a league empty?** It is out of season, or has no games in the selected scope.

**What are the money and ticket percentages?** Ticket % is the share of bets placed on a side; money % is
the share of the dollars wagered. A big gap between them usually means large bets are on one side.

**Do you cover UFC, tennis or golf?** Not yet — those use a different data shape and were not in season
when this actor was built.

# Actor input Schema

## `entityType` (type: `string`):

"games": one row per game with every sportsbook's moneyline/spread/total, public money & ticket percentages, scores and status. "lineHistory": one row per game/sportsbook/market with the full timestamped odds and line movement of every outcome (the site keeps this for only a few days after a game, so schedule it). "props": one row per player or game prop market with every sportsbook's lines.

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

Which leagues to pull. Leave all selected for every league. Leagues that are out of season simply return nothing.

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

First game day for the daily leagues (NBA, NCAAB, WNBA, MLB, NHL, soccer), in US Eastern time. With dateFrom/dateTo empty you get each league's current slate. NFL and NCAA Football ignore dates - use season/week instead. Odds and betting splits go back roughly two seasons; line history only a few days.

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

Last game day (inclusive). Defaults to dateFrom when only dateFrom is set. At most 400 days per run.

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

Season year for NFL and NCAA Football, e.g. 2025. Setting it walks the weeks below; leave empty for the current week's slate.

## `weekFrom` (type: `integer`):

First week to pull when season is set. With only weekFrom, just that week. Defaults to week 1.

## `weekTo` (type: `integer`):

Last week to pull when season is set. Defaults to the end of the regular season (18 for NFL, 16 for NCAA Football) or of the postseason.

## `seasonType` (type: `string`):

Regular season or postseason (playoffs / bowl games) for NFL and NCAA Football.

## `bookIds` (type: `array`):

Restrict output to these sportsbooks. Empty means the site's default set (Consensus plus about five major US books). Consensus is always included because it carries the public betting splits.

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

Stop after pushing this many rows. Defaults to 50 - a fast, cheap preview, and what keeps an unconfigured run within Apify's automated 5-minute QA check. Set to null for everything in the selected scope. Props rows are numerous (hundreds per game), so cap them.

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

Applies to "games" only. "auto": the first run returns every game; later runs, with maxItems cleared, only new games and games whose status, score or closing lines changed. A capped run (the default preview) always returns games. "full": always every game. "incremental": only new/changed. Line history and props are always a fresh pull.

## `concurrency` (type: `integer`):

Parallel requests (max 20). Line-history and props runs fetch one request per game.

## `impersonate` (type: `string`):

curl\_cffi browser TLS-impersonation target. Defaults to "firefox" internally; change only if requests start being blocked.

## `proxyConfiguration` (type: `object`):

Apify Proxy settings. Not needed: the API answered every request from Apify's infrastructure in testing without a proxy.

## Actor input object example

```json
{
  "entityType": "games",
  "leagues": [
    "nfl",
    "ncaaf",
    "nba",
    "ncaab",
    "wnba",
    "mlb",
    "nhl",
    "soccer"
  ],
  "seasonType": "reg",
  "maxItems": 50,
  "mode": "auto",
  "concurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

# 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("artsiom_k/actionnetwork-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("artsiom_k/actionnetwork-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 artsiom_k/actionnetwork-scraper --silent --output-dataset

```

## MCP server setup

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