Skip to content

About

Football (soccer) odds, results & xG API/dataset: opening and closing odds from 40+ bookmakers, 1,000+ competitions, full seasons back to 2005. Docs, examples and schemas for the Apify Actor.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Football Odds Scraper: Historical & Closing Lines, 40+ Books

▶ Run it on Apify · API docs · Input schema · Output schema · Changelog

Sample output: Premier League 2024/25 with fair 1X2 odds, line movement, over/under and Asian handicap consensus

Get every football (soccer) match from 1,000+ competitions — top leagues, lower divisions, cups, women's and youth football — with opening and closing odds from up to 42 bookmakers for 1X2, over/under, both teams to score and Asian handicap, a no-vig market consensus, line movement, full scores (half-time, extra time, penalties), xG statistics and goal events. One clean row per match, ready for a spreadsheet, a database or a model.

Two modes:

  • Recent matches — every competition, from 7 days back to 7 days ahead (upcoming matches with current prices)
  • Full seasons — complete seasons of any league you choose, with odds history back to the mid-2000s

Most football scrapers give you scores. Most odds scrapers give you today's prices from a handful of books. This Actor gives you both, with the opening price and the closing line of every bookmaker — the data you need to build and backtest betting models.

Quick start

Create a free Apify account, copy your API token from Console → Settings → Integrations and export it:

export APIFY_TOKEN="<your Apify API token>"

Python

pip install -U apify-client   # version 3 or newer
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

# maxMatches keeps this demo small — remove it to get everything.
run = client.actor("sports-odds-lab/football-odds-results").call(run_input={
    "mode": "seasons",
    "leagues": ["England: Premier League"],
    "seasons": ["2024-2025"],
    "maxMatches": 5,
})
items = client.dataset(run.default_dataset_id).list_items().items

for m in items:
    c = m.get("consensus") or {}
    print(m["startTime"][:10], m["homeTeam"], m["score"], m["awayTeam"], "| fair home odds:", c.get("fairHomeOdds"))

Full script: examples/quickstart.py.

JavaScript / Node.js

npm install apify-client
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

// maxMatches keeps this demo small — remove it to get everything.
const run = await client.actor('sports-odds-lab/football-odds-results').call({
  mode: 'seasons',
  leagues: ['England: Premier League'],
  seasons: ['2024-2025'],
  maxMatches: 5,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

for (const m of items) {
  console.log(m.startTime.slice(0, 10), m.homeTeam, m.score, m.awayTeam, '| fair home odds:', m.consensus?.fairHomeOdds);
}

Save it as quickstart.mjs (ES modules) — full script: examples/quickstart.mjs.

cURL

curl -s -X POST "https://api.apify.com/v2/acts/sports-odds-lab~football-odds-results/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d @examples/input.json

run-sync-get-dataset-items waits for the run (up to 5 minutes). For long runs start the Actor asynchronously and poll it — see the Apify API docs.

AI agents (MCP)

Expose the Actor as a tool to any MCP client (Claude, Cursor, VS Code…) through the Apify MCP server:

{
  "mcpServers": {
    "football-odds": {
      "url": "https://mcp.apify.com?tools=sports-odds-lab/football-odds-results"
    }
  }
}

Sign in with your Apify account when the client asks; the agent then calls the Actor with the same input fields as above.

What you get for each match

  • Match: kick-off time (UTC), country, competition and stage, home and away team, Flashscore IDs and link, women's / youth flags
  • Result: status (finished, after extra time, after penalties, awarded, live, scheduled, postponed…), final score, half-time and second-half score, score after 90 minutes, after extra time and the penalty shoot-out, 1X2 result (H/D/A, settled on 90 minutes), winner, red cards
  • Odds per bookmaker — opening price and latest price for every outcome; once a match has started the latest price is the closing line:
    • 1X2 (home / draw / away) with the bookmaker margin
    • Over/Under goals — the lines you choose (e.g. 1.5, 2.5, 3.5) or every line offered, quarter lines included
    • Both teams to score (yes / no)
    • Asian handicap — the main line or all lines
    • Double chance (optional)
  • Market consensus (median across bookmakers, margin removed) for every market:
    • fair odds and win / over / BTTS probabilities at the open and at the close
    • line movement in percentage points
    • best available odds
    • the Asian handicap main line at the open and at the close
    • median 1X2 margin
  • Statistics (finished and live matches): expected goals (xG), xG on target, expected assists, possession, shots, shots on target, big chances, corners, passes, crosses, fouls, cards, saves and more
  • Events: every goal with minute, scorer, assist and the score after the goal; penalties scored and missed, own goals, yellow cards, second yellows and red cards

Historical odds: full seasons back to 2005

Pick leagues and seasons and get every match of the season — all stages, including play-offs and championship/relegation groups — with the opening and closing odds each bookmaker published at the time.

Season Bookmakers per match (examples)
2005/06 6–8 (Premier League)
2009/10 – 2012/13 5–11 (Premier League, Ekstraklasa, Brazil Serie A, League Two, Eliteserien)
2015/16 – 2019/20 9–11 (Premier League, Ekstraklasa, J1 League, Argentina)
2022/23 14
2024/25 and later 30+ listings (about 18–35 brands)

Over/under and Asian handicap odds go back as far as 1X2; both-teams-to-score odds from about 2015. Scores and goal events cover every season; expected goals (xG) the recent seasons of major leagues.

A full season of a top league (380 matches, four markets, statistics and events) takes about 6 minutes. For many leagues and seasons, raise the run timeout (the default is 6 hours).

Coverage

Measured on a full day of 313 matches (all levels, including amateur and youth football):

Segment Matches with odds Bookmaker brands per priced match (median)
Men's senior football 78% 25
Women's football 94% 25
Youth and reserve teams 70% 11
Top divisions and national cups (in the sample: MLS, Brazil Serie B, Colombia Primera A, Copa Chile, Emperor's Cup) 100% 35 (40–42 listings)

Over/under 2.5 and both-teams-to-score prices come with 99% of priced matches. A busy weekend day has 1,500+ matches.

Bookmakers include bet365, 1xBet, Betano, Betfred, Betway, bwin, BetMGM, Betclic, DraftKings, Fanatics, Interwetten, Ladbrokes, Midnite, Skybet, Sportingbet, Stake, STS, Superbet, Unibet, Winamax and more — up to 42 listings, depending on the match. Brands that appear under several licences (Betano .br / .ca / .de / .dk, BetMGM .uk / .us…) are counted once in the consensus, so they cannot outvote the rest.

Use cases

  • Build and backtest football models — train on closing-line probabilities, the most efficient price the market produces, for 1X2, totals and handicaps
  • Closing Line Value (CLV) — compare the price you bet with the consensus close to measure whether you beat the market
  • Line movement and steam — find matches where the market moved sharply between open and close
  • Lower leagues and women's football — the markets where historical odds are hardest to find
  • Your own odds history — schedule the Actor daily and keep appending to a dataset; after a few weeks you own a multi-bookmaker history nobody sells for these competitions

Using the Apify Console (no code)

  1. Pick the days (up to 7 back and 7 ahead) and statuses. Optionally narrow it down by country or competition.
  2. Choose the markets and over/under lines.
  3. Click Start. 30 matches take under a minute; a full midweek day takes about 4 minutes, a busy weekend day about 20.
  4. Download the results as JSON, CSV or Excel, or read them through the Apify API.

Tip — build a history automatically: create a Schedule that runs every morning with daysBack: 1, daysAhead: 0, statuses: ["finished"]. Each run adds yesterday's matches with their closing lines.

Running it every few minutes? Turn on Only new or changed matches (incremental: true). Finished, live and cancelled matches that were already delivered with the same score and status are skipped, so a schedule every 5–10 minutes returns (and charges for) only what is new — a repeat run with nothing new finishes in seconds. Upcoming matches are always refreshed, because their odds keep moving. The memory is kept in a key-value store named football-odds-incremental in your account; give it a different incrementalName to run several schedules side by side or to start fresh.

Ready-made examples

One click, preconfigured — open, press Start, adjust if you like:

Input example — recent matches

{
  "daysBack": 1,
  "daysAhead": 0,
  "statuses": ["finished"],
  "competitions": ["England: Premier League", "Spain: LaLiga", "Europe: Champions League"],
  "markets": ["1x2", "overUnder", "btts", "asianHandicap"],
  "overUnderLines": ["1.5", "2.5", "3.5"],
  "includeStats": true,
  "includeEvents": true
}

Input example — full seasons (history)

{
  "mode": "seasons",
  "leagues": ["England: Premier League", "Spain: LaLiga", "Germany: Bundesliga", "Italy: Serie A", "France: Ligue 1"],
  "seasons": ["2024-2025", "2023-2024", "2022-2023"],
  "markets": ["1x2", "overUnder", "btts", "asianHandicap"]
}

Seasons follow the league's own format: 2024-2025 for autumn–spring leagues, 2024 for calendar-year leagues (MLS, Brazil, Scandinavia). Leave seasons empty and set lastSeasons to get the current season plus the ones before it. A league can also be given as its Flashscore URL.

Country and competition names follow Flashscore: England, Spain, Europe (UEFA competitions), World (friendlies); England: Premier League, Germany: Bundesliga, Brazil: Serie A Betano. Stages are matched automatically — Argentina: Liga Profesional also returns its Apertura and Clausura.

Output example (shortened)

{
  "matchId": "KlfMo4PO",
  "startTime": "2026-09-22T22:30:00Z",
  "country": "Brazil",
  "competition": "Serie B",
  "homeTeam": "Criciuma",
  "awayTeam": "Operario-PR",
  "status": "finished",
  "score": "0-2",
  "halfTimeScore": "0-1",
  "result": "A",
  "consensus": {
    "bookmakerCount": 41,
    "books1x2": 35,
    "probHomeOpening": 0.5242,
    "probHomeLast": 0.4715,
    "fairHomeOdds": 2.121,
    "fairDrawOdds": 3.385,
    "fairAwayOdds": 4.289,
    "moveHomePts": -5.27,
    "probOver25Last": 0.4079,
    "probBttsYesLast": 0.4613,
    "ahLine": -0.5,
    "ahLineOpening": -0.75,
    "margin1x2Pct": 7.76
  },
  "odds": {
    "1x2": [{"bookmaker": "bet365", "opening1": 1.68, "openingX": 3.3, "opening2": 4.75, "last1": 1.96, "lastX": 3.2, "last2": 4.0, "marginPct": 7.27}],
    "overUnder": [{"bookmaker": "bet365", "line": 2.5, "openingOver": 2.3, "openingUnder": 1.6, "lastOver": 2.3, "lastUnder": 1.6}],
    "btts": [{"bookmaker": "bet365", "openingYes": 2.2, "openingNo": 1.62, "lastYes": 2.0, "lastNo": 1.73}],
    "asianHandicap": [{"bookmaker": "bet365", "line": -0.5, "openingHome": 1.75, "openingAway": 2.05, "lastHome": 2.0, "lastAway": 1.8}]
  },
  "stats": {
    "expectedGoals": {"home": 1.34, "away": 0.33},
    "ballPossession": {"home": 67, "away": 33},
    "totalShots": {"home": 26, "away": 5},
    "passes": {"home": {"pct": 84, "successful": 413, "total": 489}, "away": {"pct": 67, "successful": 176, "total": 262}}
  },
  "events": [
    {"period": "1st Half", "minute": 38, "side": "away", "type": "goal", "player": "Caio Dantas", "assist": "Mikael Doka", "scoreAfter": "0-1"},
    {"period": "2nd Half", "minute": 90, "addedTime": 6, "side": "away", "type": "goal", "player": "Maxwell", "assist": "Boschilia", "scoreAfter": "0-2"}
  ]
}

Pricing

The Actor is pay-per-result: you pay for the rows it saves, platform usage included, nothing else. The current price per 1,000 results is on the Actor page; Apify's free plan includes monthly platform credit, so you can try real data before paying. Every match comes with the odds of all bookmakers and markets you selected, the consensus, the statistics and the events, at no extra cost. Nothing is charged for matches you filter out: Skip matches without odds is on by default, so you only pay for priced matches. Set a spending limit on a run for a hard cap — the Actor stops as soon as the limit is reached.

FAQ

What is the "closing line"? The last price before kick-off. For finished and live matches the last… fields are the closing odds; for scheduled matches they are the current prices.

Which result do the 1X2 odds settle on? 90 minutes plus stoppage time — that is the result field (H/D/A). Extra time and penalties are reported separately (extraTimeScore, penaltiesScore, winner).

How is the consensus calculated? For each bookmaker the margin is removed proportionally, then the median is taken across bookmaker brands. The median keeps one stale or mispriced book from skewing the result.

What is the Asian handicap main line? The line whose consensus is closest to 50/50. ahLine is the main line at the close, ahLineOpening at the open — a moved line is a strong market signal.

How far back can I go? In Recent matches mode 7 days back and 7 ahead. In Full seasons mode any season Flashscore lists — odds go back to the mid-2000s for major leagues (fewer bookmakers in older seasons, see the table above).

Can I poll it every few minutes without paying for the same matches again? Yes — turn on Only new or changed matches (incremental: true). Matches whose score and status did not change since an earlier run with the same settings are skipped, and only the new ones are charged.

Which time zone? All timestamps are UTC.

Is Pinnacle or Betfair Exchange included? No — the source does not list them. The consensus of 20–35 bookmaker brands is a solid reference, and the Actor reports the best available price as well.

Where does the data come from? From publicly available match and odds information shown on Flashscore. This Actor is not affiliated with Flashscore or any bookmaker.

Related

  • 🎾 Tennis Odds & Scores API — every ATP, WTA, Challenger and ITF match: live scores, results, rankings and odds from up to 42 bookmakers back to 2009
  • 🏀 NBA, NFL, MLB & NHL Odds API — moneyline, spread and total odds — opening and closing — from up to 42 bookmakers, no-vig consensus and box-score stats; full seasons back to 2009
  • 📊 Polymarket & Kalshi API — prediction-market odds, volume, price history and resolutions of both platforms in one table, with the full Kalshi archive
  • ⏱️ Flashscore Scraper API (24 sports) — live scores, results and odds of football, basketball, hockey, tennis, volleyball, handball, esports, MMA, cricket, darts and more
  • 🏟️ ESPN Box Scores & Player Stats API — box scores and player stats for the NFL, NBA, MLB, NHL, college sports and soccer leagues — one row per player per game, or one row per game
  • 💼 ATS Jobs API (Greenhouse, Lever, Ashby, Workday…) — open jobs straight from company career sites on 11 applicant tracking systems — by company name or URL, or search a directory of 15,000+ companies
  • 📣 Google Ads Transparency API — every ad an advertiser or domain has run on Google — creative, format, regions and first and last shown dates

All tools: apify.com/sports-odds-lab · GitHub: github.com/minmaxerdev

License

Documentation and example code in this repository are MIT-licensed. The Actor itself runs on Apify under Apify's terms; the data comes from publicly available sources and the Actor is not affiliated with them (see the FAQ).

About

Football (soccer) odds, results & xG API/dataset: opening and closing odds from 40+ bookmakers, 1,000+ competitions, full seasons back to 2005. Docs, examples and schemas for the Apify Actor.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors