Aurelix

Tools › Developer tools

Tennis Betting Odds Scraper

Get tennis results and upcoming matches with opening and closing odds from 10-15 bookmakers, scores, round, surface and implied probabilities for $3.00 per 1,000 matches, no login.

For bettors, modellers and odds analysts. ATP, WTA, Challenger and ITF singles and doubles, stable match IDs across runs, and a free only-new mode for hourly or daily feeds.

$3.00 per 1,000 matches ($2.50 on paid Apify plans)

At a glance

What the Tennis Betting Odds Scraper does

Source
TennisExplorer public match lists and match pages, 400-700 matches a day; BetExplorer season results for past tournaments
Modes
Finished results (days back or a date range), upcoming matches, or past tournament seasons (history)
Filters
Tour level, singles/doubles, tournaments, players, only priced matches
Output
47 fields per match; JSON, CSV, Excel, API
Automate
Only new since last run, Slack/webhook digest, schedules, MCP

Who it is for

  • Bettors and tipsters measuring closing-line value: compare the price you took with the closing average
  • Modellers backtesting Elo or serve/return models against market-implied probabilities
  • Odds and trading analysts tracking line movement from opening to close across 10-15 bookmakers
  • Media, apps and newsletters publishing daily results and tomorrow's order of play with prices

Output

What you get

  • match_id (stable across runs), date and start_time (UTC), status, tournament, category, match_type, round, surface
  • Both players: short and full name, seed, singles ranking; winner, sets, score (e.g. 7-6(3) 6-4), set_scores
  • Average opening and closing odds, best closing odds, implied_prob_p1 / p2 (margin removed), overround
  • bookmaker_odds: opening and closing price per bookmaker with the time each was set
  • History mode rows use the same fields: match_id bx-<BetExplorer id>, odds_p1 / odds_p2 = BetExplorer's average closing odds, closing odds per bookmaker in bookmaker_odds (no opening odds), status also 'canceled'

Example

Input and output

Input

{
  "mode": "results",
  "dateFrom": "2026-10-01",
  "dateTo": "2026-10-31",
  "categories": [
    "atp",
    "wta"
  ],
  "matchType": "singles",
  "onlyWithOdds": true,
  "maxResults": 5000
}

One output record

{
  "match_id": "te-3368391",
  "source_match_id": "3368391",
  "match_url": "https://www.tennisexplorer.com/match-detail/?id=3368391",
  "title": "Fils A. vs Machac T.",
  "date": "2026-11-04",
  "start_time": "2026-11-04T20:20:00Z",
  "tournament": "Paris",
  "tournament_url": "https://www.tennisexplorer.com/paris/2026/atp-men/",
  "tournament_country": "FR",
  "category": "atp",
  "gender": "men",
  "match_type": "singles",
  "round": "2. round",
  "surface": "indoors",
  "status": "finished",
  "player1": "Fils A.",
  "player1_full_name": "Fils Arthur",
  "player1_url": "https://www.tennisexplorer.com/player/fils/",
  "player1_seed": "6",
  "player1_ranking": 7,
  "player2": "Machac T.",
  "player2_full_name": "Machac Tomas",
  "player2_url": "https://www.tennisexplorer.com/player/machac/",
  "player2_seed": null,
  "player2_ranking": 69,
  "winner": "player1",
  "winner_name": "Fils A.",
  "sets_p1": 2,
  "sets_p2": 0,
  "score": "6-3 7-6(4)",
  "set_scores": [
    {
      "p1": 6,
      "p2": 3,
      "tiebreak": null
    },
    {
      "p1": 7,
      "p2": 6,
      "tiebreak": 4
    }
  ],
  "odds_p1": 1.55,
  "odds_p2": 2.43,
  "implied_prob_p1": 0.6098,
  "implied_prob_p2": 0.3902,
  "overround": 0.0559,
  "opening_avg_p1": 1.429,
  "opening_avg_p2": 2.74,
  "closing_avg_p1": 1.553,
  "closing_avg_p2": 2.427,
  "closing_best_p1": 1.59,
  "closing_best_p2": 2.5,
  "bookmakers_count": 15,
  "bookmaker_odds": [
    {
      "bookmaker": "10Bet",
      "opening_p1": 1.42,
      "opening_p2": 2.7,
      "opening_at": "2026-11-02T18:37:00Z",
      "closing_p1": 1.53,
      "closing_p2": 2.4,
      "closing_at": "2026-11-04T14:23:00Z",
      "changes": 20
    },
    {
      "bookmaker": "1xBet",
      "opening_p1": 1.43,
      "opening_p2": 2.92,
      "opening_at": "2026-11-02T18:26:00Z",
      "closing_p1": 1.59,
      "closing_p2": 2.4,
      "closing_at": "2026-11-04T20:07:00Z",
      "changes": 30
    },
    {
      "bookmaker": "bet-at-home",
      "opening_p1": 1.4,
      "opening_p2": 2.85,
      "opening_at": "2026-11-02T18:38:00Z",
      "closing_p1": 1.55,
      "closing_p2": 2.45,
      "closing_at": "2026-11-04T19:52:00Z",
      "changes": 30
    },
    "… 12 more"
  ],
  "odds_source": "bookmakers",
  "source_url": "https://www.tennisexplorer.com/match-detail/?id=3368391",
  "scraped_at": "2026-11-05T00:02:04Z"
}

From a real run of this tool; long text and lists shortened here.

How to use it

Three steps

  1. Pick 'Results' (finished matches: days back or a date range), 'Upcoming' (today plus N days) or 'History' (past seasons: paste BetExplorer results pages in 'BetExplorer seasons'); match pages with per-bookmaker odds are on by default.
  2. Optionally narrow it to ATP/WTA/Challenger/ITF levels, singles or doubles, tournaments or players, and turn on 'Only new since last run' for a feed.
  3. Click Start, then download JSON, CSV or Excel, or schedule it hourly or daily and send new matches to Slack, Google Sheets, Zapier, Make or n8n.

API

Call it from Python

from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("aurelix/tennis-odds-scraper").call(run_input={'mode': 'results',
 'dateFrom': '2026-10-01',
 'dateTo': '2026-10-31',
 'categories': ['atp', 'wta'],
 'matchType': 'singles',
 'onlyWithOdds': True,
 'maxResults': 5000})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

pip install apify-client. The same input works from the Apify console, a schedule, Make, n8n, Zapier or an AI agent through the Apify MCP server.

Pricing

Pay per result

Per 1,000 matches, free plan$3.00
Per 1,000 matches, paid plans$2.50
Start fee per run$0.005

Live prices from the Apify Store; no subscription and no platform usage billed on top. See the Store page.

Honest limits

What it does not do

  • One source: TennisExplorer. Matches, bookmakers and odds are as it shows them; Home/Away (match winner) odds only, no handicaps, totals or in-play odds.
  • No live scores; matches in progress are skipped until they finish.
  • Round, surface, full names and rankings need match pages (on by default); rankings are current, not as of the match date.
  • UTC days; a date range covers at most 92 days per run; about 3 match pages per second (1,000 matches in 5-8 minutes).
  • History mode: closing odds only (no opening odds or odds history); no surface or rankings; seasons by BetExplorer page, at most 100 per run; times of bookmaker prices are read as the site's Prague time and converted to UTC.

FAQ

Questions buyers ask

How much does the Tennis Betting Odds Scraper cost?

$3.00 per 1,000 matches ($2.50 on paid Apify plans), billed through your Apify account; you pay only for results. Apify's free plan includes $5 of credit a month, enough for about 1,666 matches.

Which bookmakers are included?

Those TennisExplorer lists for the match, typically 10 to 15 at ATP/WTA and Challenger level (bet365, Pinnacle, Betfair, William Hill, Unibet, bwin and more). Many ITF and UTR matches have few or none; 'Only matches with odds' skips those.

What exactly are opening and closing odds?

Per bookmaker, opening is the oldest price in its change history on the match page and closing its last price before the start (current price for upcoming matches), each with its UTC time.

How do I get a live-ish feed?

Turn on 'Only new since last run' and schedule Results mode (days back 1) hourly: each run returns only matches finished since the last one. Add a Slack or webhook URL for a digest.

Can I get historical closing odds for past tournaments?

Yes, in History mode. Paste the tournament's BetExplorer results page for the year you want, e.g. /tennis/atp-singles/paris-2023/results/ (find it on betexplorer.com under Tennis > tour > tournament > Results > year). Each match comes with BetExplorer's average closing odds; with match pages on, also the closing odds of each listed bookmaker, full names and set scores. Opening odds are not shown there.

Is this legal?

It reads only public data any logged-out visitor can see: TennisExplorer's public match lists and match pages and, in History mode, BetExplorer's public season results, match pages and odds tables, on paths each site's robots.txt allows, at a polite pace with a declared bot user-agent. It never logs in, never solves CAPTCHAs and never visits bookmaker websites. Match results and odds are facts about public sporting events; no personal data beyond players' public names, seeds and rankings. To have a record removed, open an issue on this Actor's Issues tab; if TennisExplorer or BetExplorer formally asks us to stop, this Actor will stop. You are responsible for using the data lawfully, incl. gambling and data-reuse laws where you are; this is not legal advice.

Can I use it from an AI assistant?

Yes. Every input is described for agents: mode, days or dates, levels, players. It works through Apify's MCP server and API.

What happens if TennisExplorer slows down or a day does not load?

After 6 match pages in a row fail, the run stops opening match pages and returns the remaining matches from the day list only: score, players and the day-list price, without round, surface, rankings or per-bookmaker odds. After 3 day lists in a row fail, the run stops. Matches already read are kept, the status message says how many came without a match page and which days did not load, and you pay only for matches written to the dataset.

What am I charged for a run that returns nothing?

Only the small per-run start fee. Matches are charged one by one as they are written; a run with no matching matches, or a repeat run in only-new mode with nothing new, writes nothing and pays no match charges.

How does 'Only new since last run' decide what is new?

It keeps a memory of returned matches per mode and filter set (or per 'State key' if you name one). In Results mode each finished match is returned once. In Upcoming mode each scheduled match is returned once, so later odds moves on that match are not sent again; run Results mode later for the closing odds. Skipped matches are not charged, and matches unseen for 120 days drop out of the memory.

Why are round, surface, full names or rankings empty on some rows?

They come from the match page. They are empty when 'Bookmaker odds' (match pages) is switched off, or when that match page did not load. Rankings are singles rankings only, and they are the players' current rankings, not as of the match date.

What do odds_p1, closing_avg_p1 and odds_source mean?

odds_p1 / odds_p2 are the prices shown on the day list. closing_avg and opening_avg are the means of each bookmaker's last and first price; closing_best is the highest closing price across bookmakers. implied_prob_p1 / p2 come from the closing averages when the match page was read, otherwise from the day-list prices, with the margin (overround) removed. odds_source is 'bookmakers', 'list', or empty when no price was shown.

How far back can one run go?

Results mode reads today and up to 92 days back, or a date range of at most 92 days. A longer range is refused with a clear message; split it into several runs. A 'To date' in the future is cut to today.

Which day does a match belong to, and are times UTC?

Yes. Pages are read with the site's public time-zone setting at UTC, so date is the UTC day of the list and start_time is UTC. Odds history times are converted from the site's Prague time to UTC.

How does the players filter match names?

On the last word of what you type (the surname), ignoring case and accents, against both players. 'Jannik Sinner' and 'Sinner' both match any player named Sinner on the list.

How many matches does a day have, and how long does a run take?

A busy day lists 400 to 700 matches across all levels, about 60-100 of them at ATP/WTA level. With match pages on, a run reads about 3 pages per second: 1,000 matches took 326 seconds in our test run. With match pages off it reads one page per day.

Guides

Tutorials using this tool

Related

Related tools

Try the Tennis Betting Odds Scraper

Open it on the Apify Store, paste the example input above and click Start. Results download as CSV, Excel or JSON.