OddsPortal Odds Scraper: Bookmaker Odds & Pulled Lines
Pricing
from $38.00 / 1,000 results
OddsPortal Odds Scraper: Bookmaker Odds & Pulled Lines
OddsPortal odds for football, tennis, basketball and more: 1X2, over/under, Asian handicap, BTTS per bookmaker, historic results and live snapshots. Flags pulled (struck-through) prices.

What does OddsPortal Odds Scraper: Bookmaker Odds & Pulled Lines do?
OddsPortal Odds Scraper collects bookmaker odds from OddsPortal and returns one row per match with the odds of every bookmaker for each market you choose. It supports football, tennis, basketball, baseball, American football, ice hockey, handball and volleyball, in three modes: upcoming matches by league or date, historic results of a season, and a live snapshot. Supported markets are 1X2, home/away, both teams to score, double chance, draw no bet, over/under and Asian handicap, and prices that a bookmaker has pulled (struck through on the site) are recorded in blocked_outcomes.
Why use OddsPortal Odds Scraper: Bookmaker Odds & Pulled Lines?
- Every bookmaker's price per match and market in one row, ready for comparison and modelling.
- Pulled lines are kept and flagged with blocked_outcomes, because a bookmaker withdrawing a market is a signal.
- Two passes: match links are collected first, so failed matches can be retried without repeating the run.
- Historic seasons with page limits, upcoming by league or date, and live snapshots.
- Kickoff times in UTC and a clean, stable schema.
What makes this different
Most odds scrapers return one average price per match. This Actor returns each bookmaker's odds for each market, keeps the lines a bookmaker pulled (blocked_outcomes) rather than dropping them, and lets you retry only failed links.
Who can use the OddsPortal Odds Scraper and how?
- Bettors and modellers: compare every bookmaker's price for a market and find the best odds.
- Quant and data teams: build historic odds datasets per bookmaker for model training and backtests.
- Arbitrage and value-bet builders: feed odds from many bookmakers into your own detection logic.
- Line-movement and signal researchers: use blocked_outcomes to see when a bookmaker pulled a market.
- Sports analysts and content creators: pull closing odds for a season to write about favourites and upsets.
- Academics: study bookmaker margins and market efficiency across leagues.
How it works

- Your input — choose a sport, a mode and leagues or a date, plus the markets you want.
- The Actor collects it — the Actor collects the match links first and then reads each match page.
- Your output — you get one row per match with every bookmaker's odds for every market.
What data can you extract?
The dataset has 14 fields per row:
| Field | Type | Description |
|---|---|---|
match_id | string | OddsPortal event id, derived from the match URL. |
sport | string | Sport. |
league | string | League and season. |
home_team | string | Home team or player. |
away_team | string | Away team or player. |
kickoff_utc | string | Kickoff time (ISO 8601, UTC). |
status | string | upcoming, live or finished. |
score | string | Score such as 1:2, null when not started. |
markets | array | Market blocks: market, line (totals and handicap), bookmakers with odds and blocked_outcomes. |
match_url | string | Link to the match on OddsPortal. |
source | string | Data source. |
scraped_at | string | Collection time (ISO 8601). |
actor_version | string | Output schema version. |
fetch_path | string | Which route served the row: always browser for this Actor. |
How to use OddsPortal Odds Scraper: Bookmaker Odds & Pulled Lines

- Open the Actor and go to the Input tab.
- Choose a Sport and Mode, enter Leagues (for example
england-premier-league) or a Date, pick the Markets, and set Max matches. - Optionally set filters and a Max results limit.
- Click Start. A default run finishes in under a minute.
- Open the Output tab, then download the dataset or connect it to your tools.
Input Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
sport | string | No | "football" | Sport to read. |
mode | string | No | "upcoming" | Upcoming matches, finished matches of a season, or a live snapshot. |
leagues | array | No | [] | League slugs such as england-premier-league or spain-laliga (country-league). Required for historic mode. Leave empty in upcoming mode to use the date below. |
date | string | No | — | Day to read as YYYYMMDD. Used in upcoming mode when no league is given. |
season | string | No | "current" | Season as YYYY-YYYY (for example 2024-2025), a year, or current. |
markets | array | No | ["1x2"] | Markets to read: 1x2, home_away, btts, double_chance, draw_no_bet, over_under, asian_handicap. Markets a match does not offer are skipped. |
matchUrls | array | No | [] | OddsPortal match links to read directly, for example the ones in FAILED_LINKS from an earlier run. Skips the league and date lookup. |
maxItems | integer | No | 3 | Maximum number of matches. Default is 3 for a quick test; set 0 for no limit. |
maxPages | integer | No | 3 | Maximum number of result pages to read per league and season (50 matches per page). |
maxLinesPerMarket | integer | No | 3 | For over/under and asian handicap: how many lines (for example 2.5 goals) to read per match, starting with the most balanced ones. |
maxConcurrency | integer | No | 2 | Match pages read in parallel. Keep it low to stay polite to the site. |
deltaMode | boolean | No | false | Skip and do not bill matches an earlier run with the same delta key already delivered. |
deltaStateKey | string | No | "default" | Name of the tracked stream. Use a different key per league or watchlist. |
proxyConfiguration | object | No | {"useApifyProxy":false} | Residential proxies are recommended: the site rejects most datacenter addresses. |
Output Data

markets is a list of market blocks. Each block has a market, a line for over/under and Asian handicap, and bookmakers with bookmaker_name and odds keyed by outcome (1, X, 2, over, under, yes, no). blocked_outcomes appears only when a bookmaker has pulled an outcome. kickoff_utc is in UTC; score is null until a match has started.

A real dataset item:
{"match_id": "xtmHKGT0","sport": "Football","league": "Premier League","home_team": "Arsenal","away_team": "Leeds","kickoff_utc": "2026-10-10T11:30:00.000Z","status": "upcoming","score": null,"markets": [{"market": "1x2","bookmakers": [{"bookmaker_name": "888sport","odds": {"1": 1.36,"2": 7.5,"X": 4.6}},{"bookmaker_name": "bet-at-home","odds": {"1": 1.4,"2": 7.25,"X": 4.6}},{"bookmaker_name": "bet365","odds": {"1": 1.38,"2": 7.5,"X": 4.5}},{"bookmaker_name": "Betfury","odds": {"1": 1.38,"2": 7.6,"X": 4.7}},{"bookmaker_name": "BetInAsia","odds": {"1": 1.38,"2": 8.4,"X": 5.2}},{"bookmaker_name": "Bets.io","odds": {"1": 1.37,"2": 7.2,"X": 4.7}},{"bookmaker_name": "Betsson","odds": {"1": 1.38,"2": 8.7,"X": 4.7}},{"bookmaker_name": "GGBET","odds": {"1": 1.44,"2": 7.5,"X": 4.88}},{"bookmaker_name": "Rainbet","odds": {"1": 1.39,"2": 7.8,"X": 4.8}},{"bookmaker_name": "Roobet","odds": {"1": 1.38,"2": 7.6,"X": 4.7}},{"bookmaker_name": "Stake.com","odds": {"1": 1.4,"2": 7.2,"X": 4.8}}]}],"match_url": "https://www.oddsportal.com/football/h2h/arsenal-hA1Zm19f/leeds-tUxUbLR2/#xtmHKGT0","source": "oddsportal","scraped_at": "2026-09-25T21:29:00.960Z","actor_version": "1.0.0","fetch_path": "browser"}
How to read and use the results
Each row is one match with every bookmaker's odds per market.
- Pick the market block you need in `markets`.
- Compare bookmakers by their odds for the same outcome to find the best price.
- Work out margin from the odds of one bookmaker (the sum of 1 divided by each odds).
- Watch blocked_outcomes. It appears only when a bookmaker pulled an outcome.
- Use kickoff_utc for time zones; it is always UTC.
- Retry only failures by pasting FAILED_LINKS into Match links.
Usage Examples
Upcoming Premier League 1X2 odds
{"sport": "football","mode": "upcoming","leagues": ["england-premier-league"],"markets": ["1x2"],"maxItems": 10}
A finished season with totals and handicap
{"sport": "football","mode": "historic","leagues": ["england-premier-league"],"season": "2024-2025","markets": ["1x2", "over_under"],"maxItems": 50,"maxPages": 2}
Live football snapshot
{"sport": "football","mode": "live","markets": ["1x2"],"maxItems": 20}
Only matches not delivered before
{"sport": "football","mode": "upcoming","leagues": ["england-premier-league", "spain-laliga"],"markets": ["1x2"],"maxItems": 0,"deltaMode": true,"deltaStateKey": "top-leagues"}
Tips for Best Results
- Start with one market and a small Max matches to check the output, then widen.
- Over/under and Asian handicap read the most balanced lines first; raise Max lines per market for more.
- Space live snapshots at least 60 seconds apart. Repeated runs closer than that risk being flagged.
- Copy links from FAILED_LINKS into Match links to retry only the failed matches.
- Use residential proxies for larger runs.
- Default is 5 results for a fast test. Set the max to 0 to return everything available.
Reliability by mode
| Mode | Status | Needs login or key? | Notes |
|---|---|---|---|
| Upcoming by league | ✅ | No (residential proxy recommended) | League listing plus match pages. |
| Upcoming by date | 🟡 | No | Large dates list many matches; use Max matches. |
| Historic seasons | ✅ | No | 50 matches per result page; set Max result pages. |
| Live snapshot | 🟡 | No | Single snapshot; live scores can be missing. |
| 1X2, home/away, BTTS, double chance, draw no bet | ✅ | No | One block per match. |
| Over/under and Asian handicap | 🟡 | No | Reads the most balanced lines first; raise Max lines per market. |
| Pulled-price flags (blocked_outcomes) | 🟡 | No | Only present when a bookmaker has pulled a price at collection time. |
| Datacenter IPs without a proxy | ❌ | - | The site rejects them; use residential proxies on the platform. |
✅ works as described, 🟡 works with caveats, ❌ not supported.
Only new records (delta mode)
Turn on Only new matches (delta mode) and set a Delta key. Matches an earlier run already delivered are skipped before any browser time is spent on them, and are not billed. Use one key per league or watchlist.
Known Limitations
- For personal research use. OddsPortal's terms of use restrict automated access to the site, so use the Actor at your own risk, keep volumes low and respect their rules. The Actor reads publicly rendered pages only and does not log in.
- On the Apify platform, use residential proxies: the site rejects most datacenter addresses for profile and match pages.
- A wrong league or season combination can return zero results without an error from the site; the Actor logs 0 results for that league and season so you know the combination may be invalid.
- Scores are shown for started matches only, and live scores can be missing.
- Bookmaker lists differ by match and region.
- Pulled-price detection reads the struck-through styling on the site; it only appears when a bookmaker has pulled a price at collection time.
- The site can change its layout; the Actor logs a clear error for pages it cannot read.
Integrations
Run it from the Apify API, on a schedule, or from a webhook. Send results straight to Google Sheets, Make, Zapier, Slack or your own database with Apify's built-in integrations.
Export Formats
Download the dataset as JSON, CSV, Excel, XML, HTML table or RSS from the Output tab or the API.
Frequently Asked Questions
Where does the data come from?
OddsPortal's publicly rendered match and league pages. It is scraped with a real browser, not an official API. No login is used.
Does it need an account or API key?
No. It reads public pages only.
How do I get all matches of a season?
Use historic mode with the league and season, and raise Max result pages. Each page holds 50 matches.
What does blocked_outcomes mean?
OddsPortal strikes through a price when a bookmaker pulls a market. The Actor records which outcomes were struck through instead of skipping them. The field is omitted when nothing was pulled.
Can I retry only failed matches?
Yes. Failed matches are saved in FAILED_LINKS; paste them into Match links.
Am I charged for failed results?
No. You are only charged for matches that are written to the dataset.
How do I get odds from many bookmakers for one match?
Choose the sport and league (or paste the match link), pick the market such as 1x2 or over_under, and run. Each row lists every bookmaker with its odds.
Do I need an account or login?
No. The Actor reads public pages only and never logs in.
Am I charged for failed runs or empty results?
You are only charged for results that are actually written to the dataset.
Can I run it on a schedule?
Yes. Create a Task with your input and add a schedule in Apify Console. With monitor mode on, each scheduled run returns only what changed since the previous one.
Changelog
- 2026-09-26: Added delta mode, deep-match pricing tier and the fetch_path field. Fixed unknown-season detection and league checks that returned the wrong league.
- 2026-09-25: First release: seven markets, upcoming, historic and live modes, blocked_outcomes flag.
Enterprise and custom work
Need higher volumes, a custom output schema, dedicated scheduling or a no-breaking-changes commitment for a production pipeline? Open an issue on the Actor page and describe your use case. Bulk terms and custom builds are available.
Support
Questions or a missing field? Open an issue from the Issues tab on this Actor's page and it will be looked at.
Legal / Responsible Use
For personal research use. OddsPortal's terms of use restrict automated access to the site, and you are responsible for complying with them and with applicable law. The Actor reads publicly rendered pages only, never bypasses a login or paywall, and is not affiliated with OddsPortal. This is not betting advice.