# OddsPortal Scraper (`piotrv1001/oddsportal-scraper`) Actor

The OddsPortal Scraper extracts fixtures, results and betting odds from OddsPortal.com, capturing every bookmaker's price, average and best odds, payouts, final scores and full market books with opening and closing lines - ideal for betting models and odds backtesting.

- **URL**: https://apify.com/piotrv1001/oddsportal-scraper.md
- **Developed by:** [FalconScrape](https://apify.com/piotrv1001) (community)
- **Categories:** Automation, Developer tools, Other
- **Stats:** 4 total users, 0 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 match with odds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### 🚀 OddsPortal Scraper

Extract **fixtures, results and betting odds** from [OddsPortal.com](https://www.oddsportal.com) in structured JSON. The **OddsPortal Scraper** pulls every bookmaker's price for a match — not just the average — along with final scores, payout percentages and full market books with **opening and closing lines**, across football, tennis, basketball, hockey, MMA and 15 more sports.

Paste a league URL, hit run, and get a clean dataset. Running it on Apify means you also get scheduled runs, an API, webhooks, integrations with Google Sheets, Zapier and Make, automatic proxy rotation, and run monitoring — no infrastructure to maintain.

### ✨ Features

- 🏆 **Every bookmaker, not just the average** — average odds, best odds, which bookmaker offers them, each bookmaker's individual price and its payout percentage.
- 📅 **Upcoming fixtures** — kick-off times, venues, teams, team pages and live match-winner odds.
- 📚 **Historical results archive** — final scores, half-time scores, winners and closing odds going back 20+ seasons, one season per URL.
- 🎯 **Full market books** — Over/Under, Asian Handicap, Correct Score, Both Teams to Score, Double Chance, Draw No Bet, HT/FT, European Handicap, Odd/Even and more, across full time, 1st half and 2nd half.
- 📈 **Line movement** — opening odds with timestamps *and* closing odds per bookmaker, so you can measure how the market moved.
- 🌍 **Choose your bookmaker region** — the proxy country decides which bookmakers you see; the default returns the widest international selection.
- ⚡ **Fast and lightweight** — hundreds of matches per minute, no browser required.

### 💡 Why use the OddsPortal Scraper?

- **Build and backtest betting models** on decades of results paired with the odds that were actually available.
- **Find value and arbitrage** by comparing every bookmaker's price on the same market side by side.
- **Track closing line value (CLV)**, the single best predictor of long-term betting edge, using opening→closing prices per bookmaker.
- **Power odds-comparison sites and dashboards** with a scheduled feed of upcoming fixtures.
- **Research bookmaker margins** using the payout percentages returned with every price.

### 🛠️ How to use the OddsPortal Scraper

1. **Pick your league URLs.** Copy a league page from OddsPortal, e.g. `https://www.oddsportal.com/football/england/premier-league/` for upcoming fixtures. Add `/results/` for finished matches, or use a season URL such as `https://www.oddsportal.com/football/england/premier-league-2024-2025/results/` for history.
2. **Set the match limit.** `maxItems` caps how many matches you get across all URLs.
3. **Optionally enable all betting markets.** Turn on `scrapeMatchMarkets` if you need the full market book per match rather than just match-winner odds.
4. **Run it.** Results appear in the dataset and can be downloaded as JSON, CSV, Excel, HTML or XML, or pulled from the API.

### 📥 Input

| Field | Type | Description |
|---|---|---|
| `startUrls` | array | OddsPortal league URLs. Plain league URL → upcoming fixtures. `/results/` URL → finished matches with scores and closing odds. |
| `maxItems` | integer | Maximum number of matches to return across all start URLs. Default `50`. |
| `scrapeMatchMarkets` | boolean | Also collect every betting market per match with opening and closing odds. Slower and billed separately. Default `false`. |
| `proxyConfiguration` | object | Proxy for the run. The **proxy country decides which bookmakers appear** — Malta (default) gives the widest international list; UK, Germany or US return that country's licensed bookmakers. |

Example input:

```json
{
    "startUrls": [
        { "url": "https://www.oddsportal.com/football/england/premier-league/" },
        { "url": "https://www.oddsportal.com/football/spain/laliga-2024-2025/results/" }
    ],
    "maxItems": 200,
    "scrapeMatchMarkets": false,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "MT"
    }
}
```

### 📊 Sample output data

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
[
    {
        "matchId": 8877479,
        "eventId": "jubPoemo",
        "url": "https://www.oddsportal.com/football/h2h/brighton-2XrRecc3/chelsea-4fGZN2oK/#jubPoemo",
        "sport": "Football",
        "country": "England",
        "league": "Premier League 2025/2026",
        "homeTeam": "Brighton",
        "awayTeam": "Chelsea",
        "startTime": "2026-04-21T19:00:00.000Z",
        "status": "Finished",
        "isFinished": true,
        "result": "3:0",
        "partialResult": "1:0, 2:0",
        "winner": "home",
        "venue": "Amex Stadium",
        "venueTown": "Brighton",
        "bookmakerCount": 8,
        "odds": {
            "home": { "average": 2.3, "highest": 2.45, "highestBookmaker": "bet365", "bookmakerCount": 8 },
            "draw": { "average": 3.45, "highest": 3.6, "highestBookmaker": "1xBet", "bookmakerCount": 8 },
            "away": { "average": 3.12, "highest": 3.15, "highestBookmaker": "Betfair Exchange", "bookmakerCount": 8 }
        },
        "bookmakerOdds": [
            { "bookmakerId": 163, "bookmaker": "bet365", "payout": 96.2, "home": 2.45, "draw": 3.5, "away": 3.1 },
            { "bookmakerId": 502, "bookmaker": "1xBet", "payout": 94.7, "home": 2.25, "draw": 3.6, "away": 3.15 }
        ]
    }
]
```

With `scrapeMatchMarkets` enabled, each match additionally carries a `markets` array:

```json
{
    "markets": [
        {
            "market": "Over/Under",
            "marketId": 2,
            "scope": "Full Time",
            "handicap": 2.5,
            "bookmakers": [
                {
                    "bookmakerId": 163,
                    "bookmaker": "bet365",
                    "closingOdds": { "over": 1.37, "under": 2.85 },
                    "openingOdds": { "over": 1.3, "under": 3.1 },
                    "openingTime": { "over": "2026-04-11T16:14:55.000Z", "under": "2026-04-11T16:14:55.000Z" }
                }
            ]
        }
    ]
}
```

### 📋 Data fields

| Field | Description |
|---|---|
| `matchId`, `eventId` | Numeric and short identifiers for the match |
| `url` | Link to the match page on OddsPortal |
| `sport`, `country`, `league`, `leagueUrl` | Competition the match belongs to |
| `homeTeam`, `awayTeam`, `homeTeamUrl`, `awayTeamUrl` | Teams and their pages |
| `startTime`, `startTimestamp` | Kick-off in ISO 8601 and Unix seconds |
| `status`, `isFinished` | Scheduled, Finished, Postponed, etc. |
| `result`, `partialResult`, `winner` | Final score, period scores, and `home` / `draw` / `away` |
| `venue`, `venueTown`, `venueCountry` | Where the match is played |
| `bookmakerCount` | How many bookmakers priced the match |
| `odds` | Average odds, best odds and best-odds bookmaker per outcome |
| `bookmakerOdds` | One row per bookmaker with its price for each outcome and its payout % |
| `markets` | Every betting market and scope, with opening and closing odds per bookmaker (only when `scrapeMatchMarkets` is on) |

### 💰 How much does it cost to scrape OddsPortal?

The scraper uses **pay per event** pricing, so you only pay for the data you actually get:

| Event | Price | What it covers |
|---|---|---|
| Actor start | $0.005 | Charged once per run |
| Match with odds | $0.003 | One fixture or result with per-bookmaker match-winner odds |
| Full market book | $0.02 | Every betting market for a match, with opening and closing odds (only when `scrapeMatchMarkets` is on) |

A typical league sweep of **380 finished matches with closing odds costs about $1.15**. The same 380 matches with every betting market included costs around $8.75. Apify's free tier includes $5 of monthly usage, enough to try the scraper on several full seasons.

### ⚙️ Tips and advanced options

- **Leave `scrapeMatchMarkets` off** unless you need markets beyond the match winner — it is roughly 30× more requests per match and is billed separately.
- **Season URLs are the cheapest way to build history.** Open any league's results page, use the season dropdown to get its URL, and add those URLs to `startUrls`.
- **Bookmaker coverage depends on the proxy country.** Malta and Australia return the widest international list. A UK proxy returns UK-licensed books, a German proxy German ones, and so on. Datacenter proxies return only a small US selection, so residential is recommended.
- **Older seasons have fewer bookmakers.** Results go back a long way, but multi-bookmaker odds realistically start around 2008–2010.
- **Schedule it.** Run daily against upcoming-fixtures URLs to build your own odds-movement history over time.

### ❓ FAQ

**Which sports are supported?**
All of them: football, tennis, basketball, hockey, American football, baseball, handball, rugby, volleyball, cricket, darts, boxing, MMA, esports and more. Any league page on OddsPortal works.

**How far back does the historical data go?**
Results for major leagues go back 20+ seasons. Add one season URL per season you want.

**Can I get tick-by-tick odds movement?**
The scraper returns **opening odds with timestamps and closing odds** for every bookmaker, which is what closing-line-value analysis needs. Intermediate ticks between open and close are not publicly available.

**Why do I see different bookmakers than on the website?**
OddsPortal shows different bookmakers depending on where you connect from. Change `apifyProxyCountry` in the proxy settings to target a specific market.

**Is scraping OddsPortal legal?**
The scraper only collects publicly available data and stores no personal information. That said, OddsPortal's `robots.txt` asks crawlers not to access these pages, and its Terms of Service apply to you as the operator of the run. You are responsible for making sure your use complies with applicable law and terms — consult a lawyer if you are unsure.

**Something is broken or missing.**
Open an issue on the Actor's **Issues** tab and it will be looked at. Custom variants and bulk extractions can also be arranged.

Start extracting OddsPortal odds today! 🚀

# Actor input Schema

## `startUrls` (type: `array`):

OddsPortal league pages to scrape. A plain league URL returns upcoming fixtures with odds; add `/results/` to the URL to get finished matches with scores and closing odds. Season-specific URLs such as `https://www.oddsportal.com/football/england/premier-league-2024-2025/results/` work too.

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

Maximum number of matches to return across all start URLs.

## `scrapeMatchMarkets` (type: `boolean`):

Also collect every betting market for each match (Over/Under, Asian Handicap, Correct Score, BTTS, HT/FT and more) across full time, 1st half and 2nd half, including opening and closing odds per bookmaker. Much slower and billed separately - leave off if you only need match winner odds.

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

Proxy used for the run. The proxy country decides which bookmakers are returned: Malta (the default) gives the widest international selection, while UK, Germany or US return that country's licensed bookmakers instead.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.oddsportal.com/football/england/premier-league/"
    }
  ],
  "maxItems": 50,
  "scrapeMatchMarkets": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "MT"
  }
}
```

# 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 = {
    "startUrls": [
        {
            "url": "https://www.oddsportal.com/football/england/premier-league/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("piotrv1001/oddsportal-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 = { "startUrls": [{ "url": "https://www.oddsportal.com/football/england/premier-league/" }] }

# Run the Actor and wait for it to finish
run = client.actor("piotrv1001/oddsportal-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 '{
  "startUrls": [
    {
      "url": "https://www.oddsportal.com/football/england/premier-league/"
    }
  ]
}' |
apify call piotrv1001/oddsportal-scraper --silent --output-dataset

```

## MCP server setup

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