# BetRivers & Unibet Odds Scraper (`normdata/betrivers-unibet-odds-scraper`) Actor

Live and pre-match odds from BetRivers (13 US states + Ontario) and Unibet (UK, EU, Canada): moneyline, spread, total and every market incl. player props, for NFL, NBA, MLB, NHL, soccer, tennis, UFC and more. 1,000 events in under a minute.

- **URL**: https://apify.com/normdata/betrivers-unibet-odds-scraper.md
- **Developed by:** [Norm Data](https://apify.com/normdata) (community)
- **Categories:** Automation
- **Stats:** 2 total users, 1 monthly users, 76.5% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 event scrapeds

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

![Norm Data](https://raw.githubusercontent.com/FabriAV/normdata/refs/heads/main/assets/banner_norm2.png)

## 🎲 BetRivers & Unibet Odds Scraper

Scrape live and pre-match odds from **BetRivers** (13 US states plus Ontario) and **Unibet** (UK, Sweden, Denmark, Netherlands, Belgium, Canada). Every row is one match with the moneyline, main spread and main total as flat columns. It also carries **every market the book offers**: player props, quarters, halves, alternate lines, corners and more. Each price comes in decimal, American and fractional odds. NFL, NCAAF, NBA, MLB, NHL, soccer, tennis, UFC, esports and 20 more sports. About **1,000 events with every market in under 10 seconds**, no proxy.

Live games also get the score and the game clock, so you can track in-play line movement on a schedule.

### 🎯 Who uses it?

#### 📈 Bettors and odds comparison sites

Compare BetRivers and Unibet prices with other books, find the best line and spot arbitrage or middles.

#### 🤖 Betting model builders and quants

Feed a model with clean, structured odds for every market, including player props, and record closing lines over time.

#### 📰 Sports media and fantasy apps

Show current lines, spreads and totals next to your previews, scores and fantasy projections.

#### 🔬 Researchers and analysts

Study how lines move between states and countries, before and during games, on the same Kambi platform.

### ✨ What it does

- **Two big books, 20 markets in one run:** BetRivers NJ, PA, NY, IL, MI, OH, AZ, CO, IN, VA, MD, LA, WV, Ontario, and Unibet UK, SE, DK, NL, BE, CA.
- **27 sports:** American football, basketball, baseball, ice hockey, soccer, tennis, UFC/MMA, boxing, golf, esports, cricket, rugby, AFL, darts, snooker, table tennis, handball, volleyball, Formula 1, NASCAR and more.
- **League, team and player filters:** "NFL", "Premier League", a whole country like "Spain", or just the games of "Chiefs", "Real Madrid" or "Sinner".
- **Live or upcoming:** in-play games only, upcoming only, or both; games starting within the next N hours; only games the book streams.
- **Market filters:** pick main lines, game lines (alternates and team totals included), player props, periods (halves, quarters, sets) or other markets, search markets by keyword ("Passing Yards", "Mahomes", "Corners") and hide suspended markets.
- **Headline odds as columns:** home, draw and away odds (decimal and American), spread line and odds, total line and over/under odds.
- **Every market as a list:** name, type, group, period, main-line flag, open or suspended, cash out and bet builder flags, closing time, and every outcome with player, line, decimal, American and fractional odds, status and last price change.
- **Live data:** score, game clock, and for soccer corners and yellow and red cards, for tennis, table tennis and volleyball the score of every set and the points of the current game.
- **Event details:** full team names and IDs, when pre-match betting closes, and whether the event is streamed, offers live betting, bet builder, or is on neutral ground.

### 🏆 Why this scraper

- **The only BetRivers and Unibet odds actor on Apify.** Other odds actors cover DraftKings, FanDuel or aggregators, not these books.
- **Every market, not just the moneyline.** Player props, period lines and alternate spreads come on the same row, with no extra cost per market.
- **Fast without shortcuts.** 1,000 events with every market in about 9 seconds in our tests, with no browser and no proxy.
- **State by state.** US odds differ by state; pick the ones you need and compare them side by side.
- **Clean and consistent.** Odds as numbers, American odds with their sign, rows sorted by start time so games in play come first.

### ⚖️ How it compares

| Capability | This actor | [DraftKings odds](https://apify.com/zen-studio/draftkings-odds) | Odds aggregators |
|---|:--:|:--:|:--:|
| BetRivers odds | **yes, 13 states + Ontario** | no | some, main lines only |
| Unibet odds | **yes, 6 countries** | no | some, main lines only |
| Every market incl. player props | **yes** | yes | rarely |
| Live score and game clock | **yes** | no | no |
| Live corners, cards and set scores | **yes** | no | no |
| Filter by team, market type or market keyword | **yes** | not stated | rarely |
| Decimal, American and fractional odds | **yes** | American | varies |
| Price | **$0.01 per event, every market included** | per request | per row or per event |
| Proxy | **none needed** | not stated | not stated |

### 📦 What data you get

| Field | Description |
| --- | --- |
| `eventId`, `url` | The book's event ID and the event page. |
| `bookmaker` | Book and market, e.g. "BetRivers New Jersey" or "Unibet UK". |
| `sport`, `category`, `league` | Sport, country or sub-group, and league or tournament. |
| `eventName`, `homeTeam`, `awayTeam` | Match name and teams or players as the book shows them ("WAS Commanders"). |
| `homeTeamFullName`, `awayTeamFullName`, `homeTeamId`, `awayTeamId` | Full names ("Washington Commanders") and the book's team or player IDs, stable across events. |
| `startTime`, `bettingClosesAt` | Start time and when pre-match betting closes (UTC, ISO 8601). |
| `status` | `upcoming` or `live`. |
| `score`, `matchClock` | Live only: score (sets won for tennis, table tennis and volleyball) and clock, e.g. "4th Quarter 2:00" or "67'". |
| `liveStats` | Live only: corners and yellow and red cards for soccer; the score of every set and the points of the current game for set sports. |
| `streamed`, `liveBetting`, `betBuilder`, `neutralVenue` | Whether the book streams the event, offers in-play betting, offers bet builder, and whether it's on neutral ground. |
| `homeOdds`, `drawOdds`, `awayOdds` | Moneyline in decimal odds. `drawOdds` only for sports with a draw. |
| `homeOddsAmerican`, `drawOddsAmerican`, `awayOddsAmerican` | The same in American odds ("-225", "+180"). |
| `spreadHome`, `spreadHomeOdds`, `spreadAwayOdds` | Main spread (handicap) line for the home side and its odds. |
| `totalLine`, `overOdds`, `underOdds` | Main total line and over/under odds. |
| `marketCount`, `markets` | Number of markets and the list (see below). |
| `scrapedAt` | When the row was collected (UTC). |

Each market in `markets` has `marketId`, `name`, `type`, `group` (`game_lines`, `player_props`, `periods` or `other`), `period` ("Full Game", "1st Half", "Quarter 1", "Set 2"...), `isMainLine`, `status` (`open` or `suspended`), `cashOut`, `betBuilder`, `closesAt`, and `outcomes` with `name`, `participant`, `participantId`, `line`, `oddsDecimal`, `oddsAmerican`, `oddsFractional`, `status` and `changedAt` (last price change).

The headline columns are always filled from the full market list, even when you filter the markets.

Example row (markets shortened):

```json
{
  "eventId": 1028812618,
  "url": "https://nj.betrivers.com/?page=sportsbook#event/1028812618",
  "bookmaker": "BetRivers New Jersey",
  "sport": "American Football",
  "category": null,
  "league": "NFL",
  "eventName": "IND Colts @ WAS Commanders",
  "homeTeam": "WAS Commanders",
  "awayTeam": "IND Colts",
  "homeTeamFullName": "Washington Commanders",
  "awayTeamFullName": "Indianapolis Colts",
  "homeTeamId": 1000000334,
  "awayTeamId": 1000000174,
  "startTime": "2026-10-04T13:30:00Z",
  "bettingClosesAt": "2026-10-04T13:30:00Z",
  "status": "upcoming",
  "score": null,
  "matchClock": null,
  "liveStats": null,
  "streamed": true,
  "liveBetting": true,
  "betBuilder": true,
  "neutralVenue": false,
  "homeOdds": 2.8,
  "drawOdds": null,
  "awayOdds": 1.45,
  "homeOddsAmerican": "+180",
  "drawOddsAmerican": null,
  "awayOddsAmerican": "-225",
  "spreadHome": 4.5,
  "spreadHomeOdds": 1.88,
  "spreadAwayOdds": 1.94,
  "totalLine": 47.5,
  "overOdds": 1.91,
  "underOdds": 1.91,
  "marketCount": 21,
  "markets": [
    {
      "marketId": 2697921688,
      "name": "Total Passing Yards by the Player - Including Overtime",
      "type": "Player Occurrence Line",
      "group": "player_props",
      "period": "Full Game incl. Overtime",
      "isMainLine": false,
      "status": "open",
      "cashOut": true,
      "betBuilder": true,
      "closesAt": "2026-10-04T13:30:00Z",
      "outcomes": [
        { "name": "Over", "participant": "Daniel Jones", "participantId": 1005252422, "line": 226.5, "oddsDecimal": 1.87, "oddsAmerican": "-115", "oddsFractional": "17/20", "status": "OPEN", "changedAt": "2026-10-02T23:09:09Z" },
        { "name": "Under", "participant": "Daniel Jones", "participantId": 1005252422, "line": 226.5, "oddsDecimal": 1.87, "oddsAmerican": "-115", "oddsFractional": "17/20", "status": "OPEN", "changedAt": "2026-10-02T23:09:09Z" }
      ]
    }
  ],
  "scrapedAt": "2026-10-03T04:29:04.340Z"
}
```

A live soccer match carries `liveStats` like `{ "homeCorners": 7, "awayCorners": 1, "homeYellowCards": 2, "awayYellowCards": 1, "homeRedCards": 0, "awayRedCards": 0 }`, and a live tennis match `{ "homeSets": [2, 6, 4], "awaySets": [6, 3, 2], "gamePoints": "40-40" }`.

### 💡 Use cases

#### 🏈 Every NFL market in New Jersey and Pennsylvania

```json
{ "maxItems": 100, "bookmakers": ["betrivers-nj", "betrivers-pa"], "sports": ["american_football"], "leagues": ["NFL"] }
```

#### 🎯 NFL passing yards props only

```json
{ "maxItems": 50, "leagues": ["NFL"], "markets": ["player_props"], "marketKeywords": ["Passing Yards"] }
```

#### 👤 Every prop on one player

```json
{ "maxItems": 5, "leagues": ["NFL"], "marketKeywords": ["Mahomes"] }
```

#### 🔴 Live NBA and NHL lines you can bet right now

```json
{ "maxItems": 200, "bookmakers": ["betrivers-ny"], "sports": ["basketball", "ice_hockey"], "eventStatus": "live", "hideSuspended": true }
```

#### ⚽ Real Madrid and Barcelona games, main odds, on Unibet UK

```json
{ "maxItems": 20, "bookmakers": ["unibet-uk"], "teams": ["Real Madrid", "Barcelona"], "markets": ["main"] }
```

#### ⏱️ Everything starting in the next 3 hours, all sports

```json
{ "maxItems": 1000, "bookmakers": ["betrivers-nj"], "startsWithinHours": 3 }
```

#### 🗺️ Compare one state against another

```json
{ "maxItems": 500, "bookmakers": ["betrivers-nj", "betrivers-mi", "betrivers-on"], "sports": ["baseball"], "markets": ["main"] }
```

### ⚙️ How the input is organised

| Section | What it's for |
| --- | --- |
| **Maximum events** | Always first, caps the whole run. Empty means no limit. |
| **Sportsbook** | Which BetRivers states and Unibet countries to read. Several books share the limit fairly. |
| **What to scrape** | Sports, leagues or countries, teams or players, live or upcoming, how soon the games start, streamed only. |
| **Markets** | Market types (main lines, game lines, player props, periods, other), market keywords, hide suspended markets. Empty means every market. |

### 💰 Pricing

Pay-per-event: a one-time **$0.003** when the run starts, plus a price per event saved to your dataset, with every market included. The price depends on your Apify plan tier:

| Your Apify plan | Price per event |
| --- | --- |
| Free | $0.014 |
| Bronze | $0.0125 |
| Silver | $0.011 |
| Gold / Platinum / Diamond | $0.01 |

Approximate total cost (includes the $0.003 start fee):

| Events collected | Free | Bronze | Silver | Gold+ |
| --- | --- | --- | --- | --- |
| 100 | $1.40 | $1.25 | $1.10 | $1.00 |
| 1,000 | $14.00 | $12.50 | $11.00 | $10.00 |
| 10,000 | $140.00 | $125.00 | $110.00 | $100.00 |

New Apify accounts start with $5 in free credit. On the Free plan a run saves up to 10 events.

### 🚀 Run it

1. Create a free Apify account with $5 in credit.
2. Open the BetRivers & Unibet Odds Scraper.
3. Pick the books and sports (or keep the prefilled NFL in New Jersey), set Maximum events, then click **Start**.
4. Export the results as CSV, Excel, JSON, or XML from the Dataset tab.

Run it programmatically through the Apify API (`run-sync-get-dataset-items`) or the ApifyClient for JavaScript and Python, and schedule it with Apify's built-in Scheduler to track line movement.

### 🤖 Use with AI agents (MCP)

Give an AI agent live access to BetRivers and Unibet odds through the Model Context Protocol:

```
claude mcp add --transport http apify "https://mcp.apify.com?tools=normdata/betrivers-unibet-odds-scraper"
```

Then prompt it in plain language to run the scraper and read back the results.

### 🔧 Troubleshooting

**A league was skipped.**
Use the name the book shows ("NFL", "NBA", "Premier League") or country plus league ("England Premier League"). A league with no games right now is skipped with a warning.

**`totalLine` or `spreadHome` is empty.**
The book has no main total or spread open for that event, which is common for live games near the end, futures-style sports and some tennis matches. The other markets are still in `markets`.

**Fewer events than expected.**
Events that close between the listing and the odds request, or that have none of the markets you filtered for, are skipped and the next events take their place, so you only pay for rows with data. Fewer rows means fewer events had those markets: player props, for example, open only a few days before a game. Outrights (season winners, golf tournaments) are not included; only matches are.

**The log says the sportsbook refused the server's IP address.**
The sportsbook blocks some cloud server IP addresses. When that happens before anything is saved, the run restarts on another Apify server by itself (up to 4 times) and carries on, at no extra cost to you. If every try is refused, the run stops with a clear message: run it again a bit later.

**A team filter found nothing.**
Teams match on whole words of the name the book uses: "Chiefs" or "Kansas City Chiefs" work, "Chief" doesn't.

**Odds differ between states.**
That's real: each state and country has its own trading. Use it to compare.

### ❓ FAQ

| Question | Answer |
| --- | --- |
| Do I need a BetRivers or Unibet account? | No. Only public odds are read. |
| Does it need a proxy? | No, not even for US states. |
| Is there a limit on results? | No. Leave Maximum events empty to get every match on the books you pick. |
| How fresh are the odds? | Read live on every run. Schedule it every few minutes to track movement. |
| Are player props included? | Yes. Leave Market types empty for everything, or pick Player props to get only them. |
| Can I get only one player's props? | Yes. Put the player's name in Market keywords, e.g. "Mahomes". |
| Does a filter make it cheaper? | You pay per event saved, not per market, so filters keep your rows small but cost the same per event. |
| Are other Kambi books included? | Not yet. Write to us if you need one. |
| Can I place bets with it? | No. It only reads odds. |

### 🛡️ Limits & responsible use

This Actor reads only public odds that BetRivers and Unibet show to any visitor. It never signs in and never places bets. Odds change quickly; always check the book before acting on a price. Use the data in line with the books' terms and the gambling laws where you are. Please gamble responsibly.

### 📧 Contact

Need a scraper for a different site, or found something wrong with this one? norm.data.scrapers@gmail.com

### 🧪 Local development

```powershell
bun install
bun run typecheck
bun test/qa.mjs
apify run
```

Local results are stored in `storage/datasets/default`.

# Actor input Schema

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

Stop after this many events (games, matches, fights). Leave empty for no limit (the run stops once the matching events run out). The Apify Free plan is always capped at 10.

## `bookmakers` (type: `array`):

Which sportsbook (and which state or country) to read the odds from. Pick several to compare lines: each event comes back once per bookmaker.

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

Only these sports. Leave empty for all sports.

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

Only these competitions, by the name the sportsbook uses, e.g. "NFL", "NBA", "NCAAF", "Champions League", "England Premier League" (country + league when the name is shared), or a whole country like "Spain". Leave empty for every league.

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

Only events with one of these teams or players, e.g. "Chiefs", "Real Madrid", "Sinner". Whole words; accents and case do not matter. Leave empty for every event.

## `eventStatus` (type: `string`):

Upcoming games, games in play right now (with live score), or both.

## `startsWithinHours` (type: `integer`):

Only events starting in the next N hours, e.g. 24 for today's slate. Live games are always included. Leave empty for every scheduled event.

## `onlyStreamed` (type: `boolean`):

Only events the sportsbook streams live on its site or app.

## `markets` (type: `array`):

Only these kinds of markets. Main lines: the moneyline, main spread and main total. Game lines: every full-game moneyline, spread and total, alternates and team totals included. Player props: markets on one player (yards, points, goalscorer...). Periods: halves, quarters, innings, sets. Other: everything else (specials, corners, cards, winning margin...). Leave empty for all.

## `marketKeywords` (type: `array`):

Only markets whose name or player contains one of these words, e.g. "Passing Yards", "Touchdown", "Mahomes", "Corners". Leave empty for all.

## `hideSuspended` (type: `boolean`):

Skip markets that are suspended right now (common during live play) and keep only those open for betting.

## Actor input object example

```json
{
  "maxItems": 10,
  "bookmakers": [
    "betrivers-nj"
  ],
  "sports": [
    "american_football"
  ],
  "leagues": [
    "NFL",
    "NBA",
    "England Premier League"
  ],
  "teams": [
    "Chiefs",
    "Lakers",
    "Real Madrid"
  ],
  "eventStatus": "all",
  "onlyStreamed": false,
  "marketKeywords": [
    "Passing Yards",
    "Touchdown"
  ],
  "hideSuspended": false
}
```

# Actor output Schema

## `events` (type: `string`):

One row per event per bookmaker, with every market nested.

# 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 = {
    "maxItems": 10,
    "bookmakers": [
        "betrivers-nj"
    ],
    "sports": [
        "american_football"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("normdata/betrivers-unibet-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 = {
    "maxItems": 10,
    "bookmakers": ["betrivers-nj"],
    "sports": ["american_football"],
}

# Run the Actor and wait for it to finish
run = client.actor("normdata/betrivers-unibet-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 '{
  "maxItems": 10,
  "bookmakers": [
    "betrivers-nj"
  ],
  "sports": [
    "american_football"
  ]
}' |
apify call normdata/betrivers-unibet-odds-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,normdata/betrivers-unibet-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/yyIjHLB2zhYkHAJIc/builds/4sdhyepooZpjWPd5f/openapi.json
