Tennis Scraper — Flashscore, SofaScore & TennisExplorer Data
Pricing
from $5.00 / 1,000 results
Tennis Scraper — Flashscore, SofaScore & TennisExplorer Data
Scrape tennis from Flashscore, SofaScore and TennisExplorer in one Actor — fixtures, live and finished matches, per-match statistics, point-by-point, odds with opening price and line movement, player profiles, head-to-head and ATP/WTA rankings. Pick a source and mode, or paste any URL.
Pricing
from $5.00 / 1,000 results
Rating
5.0
(2)
Developer
Muhamed Didovic
Maintained by CommunityActor stats
0
Bookmarked
67
Total users
20
Monthly active users
3 days ago
Last modified
Categories
Share
Tennis Scraper — Flashscore, SofaScore & TennisExplorer in One Actor
Turn three of the biggest tennis sites into one clean, structured dataset. Flashscore returns a whole day of matches in a single request. SofaScore carries the depth — 50+ per-match statistics, point-by-point, live scores, player bios and ATP/WTA rank history. TennisExplorer adds the thing neither of them sells: per-bookmaker odds history across four markets. Pick a source, pick a mode, or paste any URL. Switch on includePredictionMarkets to add Polymarket and Kalshi match-winner prices next to the bookmakers' odds. Built for betting models, tennis analytics, and sports media that need more than final scores.
Sources
| Source | Best at | Cost per day of fixtures |
|---|---|---|
| Flashscore | Breadth — every tournament, every match, scores and set-by-set | 1 request |
| SofaScore | Depth — statistics, point-by-point, odds line movement, rankings, player bios | ~88 requests (bounded by sofaMaxTournaments) |
| TennisExplorer | Per-bookmaker odds history: opening price, every timestamped move, 4 markets | 1 request per day |
Set source to flashscore, sofascore, tennisexplorer, or all.
Not every source has every mode:
| Mode | TennisExplorer | Flashscore | SofaScore |
|---|---|---|---|
fixtures, results | yes | yes | yes |
matchDetails | yes | yes | yes |
players | yes | no | yes |
rankings | yes | read from TennisExplorer | yes |
searchPlayers | yes | no | yes |
h2h | yes | no | no |
A run that picks one source with a mode it does not have fails right away, and the message names the sources that do have it. Rankings are the exception: a Flashscore run in rankings mode reads the table from TennisExplorer, current or historical, and its status message says so. With source: all, a source without the mode is skipped and its share of maxItems goes to the others.
How it works

✨ Why use this scraper?
- Line movement nobody else sells — match details capture every bookmaker's opening price, every timestamped odds change with its delta, the current price and trend, across Home/Away, Over/Under, Asian Handicap and Correct Score markets.
- Prediction-market prices next to bookmaker odds: with
includePredictionMarketson, each singles match gets its open Polymarket and Kalshi match-winner prices, the bookmakers' win probability with their margin removed, and the gap between the two. - Three sites, one schema — Flashscore, SofaScore and TennisExplorer normalise into the same rows, so you can compare or merge them without writing glue code.
- Seven modes in one actor — fixtures, results, match details, player profiles, head-to-head, rankings and player search. No need to buy and wire up five different scrapers.
- No proxy needed — all three sources answer from a plain datacenter IP, so there is no residential bandwidth cost to pass on.
- Paste any URL — every tennisexplorer.com page type is auto-classified: match links, player pages,
/mutual/head-to-heads, ranking tables, day listings. Mix them freely in one run. - Date ranges, both tours, singles and doubles — scrape a whole week of results in one run, filtered to ATP/WTA, singles/doubles, or everything.
- Historical depth — weekly ranking snapshots going back years, per-season win/loss balances by surface, career titles and injury history per player.
- Clean, model-ready rows — ISO dates, numeric odds, tiebreak points split from games, one billed row per match/player/ranking entry. No padding rows, ever.
🎯 Use cases
| Who | What they do with it |
|---|---|
| Betting modelers & syndicates | Backtest markets with opening→closing line movement per bookmaker; track steam moves; join odds to results by matchId. |
| Tennis analytics teams | Build win-probability and surface-adjusted models from per-season balances, H2H records and set-level scores. |
| Sports media & content sites | Auto-generate match previews (H2H, form, odds) and recaps (scores, movers in the rankings). |
| Fantasy & prediction apps | Daily fixtures with odds as the slate; results feed for scoring; player bios for profiles. |
| Data products & researchers | Historical ranking snapshots and results archives as time series, exported to JSON/CSV/Excel. |
📥 Supported inputs
| Input | Example |
|---|---|
| Fixtures / day listings | https://www.tennisexplorer.com/matches/, /next/?year=2026&month=08&day=14 |
| Results by day | https://www.tennisexplorer.com/results/?type=atp-single&year=2026&month=08&day=11 |
| Match detail URLs or bare ids | https://www.tennisexplorer.com/match-detail/?id=3290771 or 3290771 |
| Player profiles (slug or URL) | djokovic or https://www.tennisexplorer.com/player/djokovic/ |
| Head-to-head pairs | djokovic vs alcaraz-5ab70, or https://www.tennisexplorer.com/mutual/djokovic/alcaraz-5ab70/ |
| Rankings (with history) | https://www.tennisexplorer.com/ranking/atp-men/?page=2&date=2026-07-27 |
| Player search | any name fragment, e.g. alcaraz |
| Flashscore day of matches | source: flashscore with mode: fixtures or results and dateFrom / dateTo |
| Flashscore match ids | Sl6fXwZh, the matchId of a Flashscore row (the code in flashscore.com/match/Sl6fXwZh/) |
| SofaScore day of matches | source: sofascore with mode: fixtures or results, dateFrom / dateTo and sofaMaxTournaments |
| SofaScore match ids | 17269451, the matchId of a SofaScore row |
| SofaScore player ids | 206570 or alcaraz-carlos/275923, where the number is the playerId of a rankings or search row |
| SofaScore rankings | rankingTour: atp-men or wta-women, the current top 500 |
| SofaScore player search | any name fragment, e.g. alcaraz |
Not supported: pages behind a TennisExplorer login, live-score push updates (each run is a snapshot), and URLs from other domains. Flashscore and SofaScore take ids and mode fields, not URLs, and SofaScore rankings are the current table only (rankingDate applies to TennisExplorer).
🔄 How a run works
- Choose a mode (or paste URLs — URLs win when both are present).
- The actor expands your input into page fetches: date ranges become day pages, ranking runs walk
?page=N, ids become detail URLs. - Pages are fetched in parallel with browser-grade TLS (impit) and a three-stack fallback race for resilience.
- Each page is parsed and normalised: paired match rows, odds tables with nested history, player boxes, ranking tables.
- Rows are pushed to the dataset — one row per match, player, head-to-head pair, or ranking entry — up to your
maxItems.
⚙️ Input parameters
| Field | Type | Default | Notes |
|---|---|---|---|
source | select | tennisexplorer | tennisexplorer · flashscore · sofascore · all. See the mode table under Sources |
mode | select | fixtures | fixtures · results · matchDetails · players · h2h · rankings · searchPlayers |
startUrls | array | [] | Any tennisexplorer.com URLs; overrides mode when present |
tourType | select | all | all · atp-single · wta-single · atp-double · wta-double |
dateFrom / dateTo | string | today / same day | YYYY-MM-DD; inclusive range, capped at 62 days |
matchIds | array | [] | Required in matchDetails mode. The matchId from fixtures or results rows of the same source, or TennisExplorer /match-detail/ URLs |
includeOddsHistory | boolean | true | Full timestamped movement per bookmaker on matchDetails rows |
includeRecentForm | boolean | true | Last matches + mutual meetings on matchDetails rows |
includePredictionMarkets | boolean | false | Adds Polymarket & Kalshi match-winner prices to singles match rows |
playerSlugs | array | [] | Required in players mode. TennisExplorer slugs or player URLs; for SofaScore, the numeric playerId from rankings or search rows |
h2hPairs | array | [] | Required in h2h mode. a vs b, a,b or /mutual/ URLs |
searchQuery | string | — | Required in searchPlayers mode. Part of a player's name |
rankingTour | select | atp-men | atp-men · wta-women |
rankingDate | string | latest | Historical Monday snapshot, YYYY-MM-DD |
maxItems | integer | 200 | Hard cap on billed rows — your spend guard |
maxConcurrency | integer | 10 | Parallel page fetches |
sofaMaxTournaments | integer | 20 | SofaScore only, 1 to 200. Caps how many tournaments a day of fixtures or results reads, at one request each |
proxy | object | none | All three sources work over a direct connection; configure only if you want one |
A field marked "Required" fails the run when it is empty in that mode, before any request is made. With source tennisexplorer or all, startUrls replace the mode, so a run that has them is not checked.
📊 Output overview
Every mode writes one row per entity to the default dataset. Match rows (fixtures/results) carry both sides with players, seeds, per-set scores (tiebreaks split out), the two odds, the winner and a matchId you can feed straight into matchDetails. Match-detail rows add both players' bios, the structured final score, surface win/loss comparison, recent form, and the odds block: for each bookmaker and each of the four markets, the current price, trend, opening price and (optionally) the full timestamped history. Player rows carry the bio, current/highest rankings, per-season and per-surface balances, titles and injuries. Ranking rows are one player each, stamped with the snapshot date. Every row includes sourceUrl and scrapedAt. With includePredictionMarkets on, match and match-detail rows also carry a predictionMarkets block, described below.
That paragraph describes TennisExplorer rows. Flashscore and SofaScore rows carry a source field and a leaner shape. A Flashscore match row has the tournament with its tour and discipline, an ISO startTime, both sides with players, sets won, games per set and tiebreak points, and the winner. Its match-detail row is the statistics list for one match. A SofaScore match row adds the round, the court surface, and each side's ranking and seed. Its match-detail row adds the statistics per set, point-by-point for every game, and the odds with their opening price. SofaScore also returns player, ranking and search rows. Samples of both are below, and the full field lists are under Key output fields.
📦 Output sample
A trimmed, real match-detail row (Montreal quarterfinal, scraped 2026-08-12):
{"type": "matchDetail","matchId": "3290771","matchUrl": "https://www.tennisexplorer.com/match-detail/?id=3290771","title": "Jodar - Fils","date": "2026-08-11","time": "20:20","tournament": "Montreal","round": "quarterfinal","surface": "hard","tour": "atp","discipline": "singles","home": { "name": "Jodar Rafael", "slug": "jodar", "ranking": 15, "birthdate": "2006-09-17", "plays": "right" },"away": { "name": "Fils Arthur", "slug": "fils", "ranking": 24, "birthdate": "2004-06-12", "plays": "right" },"result": {"raw": "2 : 0(7-65, 6-3)","setsHome": 2,"setsAway": 0,"sets": [{ "home": 7, "away": 6, "awayTiebreak": 5 },{ "home": 6, "away": 3 }]},"surfaceComparison": {"hard": { "home": { "wins": 21, "losses": 9 }, "away": { "wins": 30, "losses": 15 } },"clay": { "home": { "wins": 19, "losses": 4 }, "away": { "wins": 9, "losses": 2 } }},"odds": {"homeAway": [{"bookmaker": "10Bet","line": null,"side1": {"odds": 1.65,"trend": "down","opening": 1.9,"history": [{ "at": "11.08. 20:04", "odds": 1.65, "delta": -0.02 },{ "at": "09.08. 08:37", "odds": 1.9, "delta": null }]},"side2": { "odds": 2.2, "trend": "up", "opening": 1.85 }}],"overUnder": [{ "bookmaker": "10Bet", "line": "2.5", "side1": { "odds": 2.2 }, "side2": { "odds": 1.61 } }],"asianHandicap": [],"correctScore": []},"recentForm": {"home": [{"tournament": "Montreal","date": "2026-08-11","matchup": "Jodar - Fils","outcome": "win","score": "2:0","matchUrl": "https://www.tennisexplorer.com/match-detail/?id=3290771"}]},"sourceUrl": "https://www.tennisexplorer.com/match-detail/?id=3290771","scrapedAt": "2026-08-12T21:31:04.660Z"}
(overUnder had 92 rows, asianHandicap 125 and correctScore 40 on this match — trimmed here. Arrays are [], never missing.)
A match-detail row with includePredictionMarkets on (Guangzhou Challenger, scraped 2026-09-19, trimmed to the new block):
{"type": "matchDetail","matchId": "3326599","title": "Sharipov - Bar Biryukov","tournament": "Guangzhou 2 challenger","home": {"name": "Sharipov Marat (2002)"},"away": {"name": "Bar Biryukov Petr"},"predictionMarkets": {"bookmaker": {"homeNoVig": 0.7621,"awayNoVig": 0.2379,"overround": 1.0736,"openingHomeNoVig": 0.7303,"bookmakers": 9,"source": "bookmakers"},"polymarket": {"url": "https://polymarket.com/event/atp-sharipo-biryuko-2026-09-19","homeOutcome": "Marat Sharipov","awayOutcome": "Petr Bar Biryukov","homePrice": 0.785,"awayPrice": 0.215,"homeBid": 0.78,"homeAsk": 0.79,"spread": 0.01,"volumeUsd": 533.65,"liquidityUsd": 37281.41,"homeEdge": 0.0229,"matchConfidence": 0.9,"matchMethod": "names"},"kalshi": {"eventTicker": "KXATPCHALLENGERMATCH-26SEP19SHABAR","homePlayer": "Marat Sharipov","awayPlayer": "Petr Bar Biryukov","homeBid": 0.78,"homeAsk": 0.79,"spread": 0.01,"homeMid": 0.785,"awayMid": 0.215,"volumeContracts": 688.99,"homeEdge": 0.0229,"matchConfidence": 0.9,"matchMethod": "names"}}}
Both venues price Sharipov at 0.785, 2.3 points above the no-vig average of nine bookmakers (homeEdge: 0.0229).
A Flashscore match row (Shanghai, round of 32, scraped 2026-10-12 with source: flashscore, mode: results):
{"type": "match","source": "flashscore","matchId": "0Osyvtzp","matchUrl": "https://www.flashscore.com/match/0Osyvtzp/","status": "finished","statusRaw": "3","tournament": "ATP - SINGLES: Shanghai (China), hard","tournamentUrl": "https://www.flashscore.com/tennis/atp-singles/shanghai/","tournamentId": "3473162","tour": "atp","discipline": "singles","startTime": "2026-10-11T10:10:00.000Z","home": {"players": [{ "name": "Bublik A.", "slug": "bublik-alexander", "playerId": "t0WN9vR6", "country": "Kazakhstan" }],"setsWon": 2,"setScores": [6, 6, 7],"tiebreakScores": [7, null, 7]},"away": {"players": [{ "name": "Nakashima B.", "slug": "nakashima-brandon", "playerId": "ETGnbrpH", "country": "USA" }],"setsWon": 1,"setScores": [7, 3, 6],"tiebreakScores": [9, null, 5]},"winner": "home","sourceUrl": "flashscore:day:2026-10-11","scrapedAt": "2026-10-12T09:05:54.545Z"}
The same match as a SofaScore match-detail row (source: sofascore, mode: matchDetails, matchIds: ["17295053"]), trimmed:
{"type": "matchDetail","source": "sofascore","matchId": "17295053","matchUrl": "https://www.sofascore.com/brandon-nakashima-alexander-bublik/FupbsBlUb","status": "finished","statusRaw": "Ended","tournament": "Shanghai","tournamentId": "2519","groundType": "Hardcourt outdoor","round": "Round of 32","startTime": "2026-10-11T09:55:00.000Z","home": {"players": [{ "name": "Alexander Bublik", "slug": "bublik-alexander", "playerId": "163480", "country": "Kazakhstan", "ranking": 22 }],"pairId": null,"pairSlug": null,"pairName": null,"ranking": 22,"seed": "19","setsWon": 2,"setScores": [6, 6, 7],"tiebreakScores": [7, null, 7]},"away": {"players": [{ "name": "Brandon Nakashima", "slug": "nakashima-brandon", "playerId": "235576", "country": "USA", "ranking": 19 }],"pairId": null,"pairSlug": null,"pairName": null,"ranking": 19,"seed": "16","setsWon": 1,"setScores": [7, 3, 6],"tiebreakScores": [9, null, 5]},"winner": "home","statistics": [{ "period": "ALL", "group": "Service", "name": "Aces", "home": "22", "away": "12" },{ "period": "ALL", "group": "Service", "name": "First serve", "home": "73/97 (75%)", "away": "69/104 (66%)" }],"pointByPoint": [{"set": 1,"games": [{"game": 1,"points": [{ "homePoint": "15", "awayPoint": "0", "pointDescription": 2, "homePointType": 1, "awayPointType": 5 },{ "homePoint": "15", "awayPoint": "15", "pointDescription": 0, "homePointType": 5, "awayPointType": 1 }],"score": { "homeScore": 0, "awayScore": 1, "serving": 2, "scoring": 2 }}]}],"odds": [{ "market": "Full time", "choice": "1", "opening": "11/10", "current": "6/5", "movement": 1 },{ "market": "Full time", "choice": "2", "opening": "73/100", "current": "67/100", "movement": -1 }],"sourceUrl": "https://www.sofascore.com/brandon-nakashima-alexander-bublik/FupbsBlUb","scrapedAt": "2026-10-12T09:06:10.440Z"}
(statistics had 69 lines across the match and each of the three sets, pointByPoint had all 35 games, and odds had 6 lines on this match.)
🗂 Key output fields
Match rows (type: "match" — fixtures & results)
| Field | Meaning |
|---|---|
matchId, matchUrl | Feed these into matchDetails for the deep record |
status | scheduled · live · finished · cancelled (Flashscore and SofaScore rows only: the match was called off and has no score) |
tournament, tour, discipline | e.g. Montreal, atp, singles |
home / away | players[] (name, url, slug — two entries for doubles), seed, setsWon, setScores[] ({games, tiebreak?}), odds, h2hWins (fixtures) |
winner | home · away · null |
date, time | Day (mode runs) and local match time |
Match-detail rows (type: "matchDetail") — adds round, surface, discipline, per-player bios (ranking, birthdate, heightCm, weightKg, plays, turnedPro), structured result.sets, surfaceComparison, recentForm (home/away/mutual), and odds with homeAway / overUnder / asianHandicap / correctScore — each row per bookmaker with line, side1/side2 = {odds, trend, opening, history[]}. On doubles, home / away are each team's first player, homePartner / awayPartner the second (both null on singles), ranking is the doubles ranking, and recentForm holds each pair's matches.
Prediction markets (predictionMarkets, only with includePredictionMarkets): on match and matchDetail rows, null when neither venue has an open market for the match.
| Field | Meaning |
|---|---|
bookmaker | Bookmakers' win probabilities with their margin removed (homeNoVig, awayNoVig), overround, openingHomeNoVig, and source: listing (the odds on a fixtures row), bookmakers (average over every bookmaker on a TennisExplorer match detail, counted in bookmakers) or sofascore. null when the row carries no odds |
polymarket | url, title, homeOutcome / awayOutcome, homePrice / awayPrice (0 to 1, so 0.62 means 62%), homeBid / homeAsk, homeLastTrade, spread, volumeUsd, volume24hUsd, liquidityUsd, acceptingOrders, startTime |
kalshi | eventTicker, homePlayer / awayPlayer, homeMid / awayMid (0 to 1), and homeBid / homeAsk / spread for the home player built from both players' markets. Each player's own quotes are kept too (homeYesBid, homeYesAsk, homeLast and the away equivalents), plus volumeContracts, openInterestContracts, startTime |
homeEdge | Per venue: the venue's home-player probability minus bookmaker.homeNoVig. Positive means the market rates the home player higher than the bookmakers do. null without bookmaker odds, or when the venue's book is wider than 10 cents |
matchConfidence, matchMethod | How the market was paired with the row: player names plus scheduled date (names+date) or names alone (names). When two markets fit equally well, neither is attached |
Player rows (type: "player") — name, country, heightCm, weightKg, age, birthdate, plays, rankSingles/rankDoubles ({current, highest}), careerBalance + seasonBalance[] (wins/losses total and per surface), titles[], titleCounts[], injuries[], recentTournaments[].
H2H rows (type: "h2h") — players[], official record (e.g. 5 : 6), bio comparison, mutualMatches[] with year, tournament, surface, round, winner/loser and set scores.
Ranking rows (type: "rankingEntry") — tour, snapshotDate, rank, move, player, country, points.
Search rows (type: "playerSearchResult") — query, tour, rank, player (with the slug you need for the other modes).
Flashscore and SofaScore rows. The field lists above describe TennisExplorer rows. Rows from the other two sources carry source: "flashscore" or source: "sofascore" and these fields, plus sourceUrl and scrapedAt:
Row type | Source | Fields |
|---|---|---|
match | Flashscore | matchId, matchUrl, status, statusRaw (Flashscore's own code: 1 scheduled, 3 finished, 5 cancelled, 8 retired, 9 walkover, 54 awarded after a disqualification, 17 to 21 the set in play, where 17 is set 1), tournament, tournamentUrl, tournamentId, tour, discipline, startTime (ISO, UTC), home / away (each with players[] of name, slug, playerId, country, two entries for doubles, where the second player's slug is null unless the same day's feed has it, plus setsWon, setScores[], the games per set as numbers, and tiebreakScores[], the tiebreak points of the same sets with null where a set had no tiebreak), winner (set on walkovers and retirements too, null until the match has a result) |
matchDetail | Flashscore | matchId, matchUrl, statistics[] (period, group, name, home, away), availableFeeds[] (other feeds Flashscore lists for the match, may be empty) |
match | SofaScore | matchId, matchUrl, status, statusRaw, tournament, tournamentId, groundType, round, startTime (ISO, UTC), home / away (each with players[] of name, slug, playerId, country and ranking, the player's singles ranking or null when SofaScore has none, two entries for doubles, plus pairId, pairSlug and pairName, SofaScore's id, slug and name for a doubles pair ("Zhang Z / Zhou Y") and null on a singles side, the side's ranking, which is null for a doubles pair, seed, setsWon, setScores[] and tiebreakScores[], the tiebreak points of the same sets with null where a set had no tiebreak), winner |
matchDetail | SofaScore | Every SofaScore match field, plus statistics[] (period, group, name, home, away), pointByPoint[] (sets, then games, then points) and odds[] (market, choice, opening and current as fractional odds such as 11/25, movement: -1 the price fell, 1 it rose) |
player | SofaScore | playerId, name, slug, country, ranking, height (metres), weight (kg), plays, turnedPro, prizeCurrent, prizeTotal, birthCity, residenceCity |
rankingEntry | SofaScore | tour (atp or wta), rank, previousRank, points, playerName, playerSlug, playerId, country, tournamentsPlayed (ATP only) |
playerSearchResult | SofaScore | playerId, name, slug, country, ranking |
❓ FAQ
How do I get odds history for a match I found in fixtures?
Take the matchId from the fixtures row and run matchDetails with it. Chaining fixtures → matchDetails each morning gives you a daily line-movement archive.
What do odds-history timestamps look like?
As the site prints them: "11.08. 20:04" (day.month. hour:minute, no year). The opening price is extracted for you, so open→close deltas don't require parsing the history at all.
Can I get last year's rankings?
Yes — set rankingDate to any Monday (e.g. 2025-06-02). TennisExplorer keeps weekly snapshots going back years; the row's snapshotDate confirms which week you got.
Does it cover doubles and Challenger/ITF events?
Doubles: yes — use tourType: atp-double/wta-double; each side then carries two players. Coverage mirrors the site, which includes Challengers, ITF and exhibition events alongside the main tours.
Which matches get Polymarket and Kalshi prices? Singles matches with an open match-winner market when the run starts. Most prediction-market tennis is ITF and Challenger, plus Davis Cup and the main tours. Doubles are skipped, and markets close once a match settles, so results runs rarely match. In testing, 35 to 45 percent of a day's fixture rows matched at least one venue.
Why is a Kalshi homeMid sometimes null?
Kalshi lists each match as two yes/no markets, one per player, and on smaller events each book alone is thin. The actor combines both into one book for the home player and publishes a midpoint only when that book is 10 cents wide or tighter. The raw quotes are always in the row.
Do I need a proxy? No. Flashscore, SofaScore and TennisExplorer all answer over a direct connection, which keeps your cost at compute + results only. If you prefer a proxy anyway, configure one in the input and it's honoured.
Why did a run return fewer rows than maxItems?
maxItems is a cap, not a target — a quiet Tuesday simply has fewer matches. Failed pages never produce placeholder rows; gaps are reported in the run's status message instead. The same goes for a match id, player slug or head-to-head pair the site doesn't know: it is skipped, named in the log, and not charged.
Why did my run fail?
The status message says which of three things happened. The mode needs an input field and it was empty (for example players with no playerSlugs). The source does not have the mode (for example flashscore with h2h). Or the source did not answer: each SofaScore request is tried four times, and if it still fails and the run has no rows, the run ends as failed with the HTTP status in the message. The first two stop before any request is made, and none of the three pushes a row, so no row is billed. A search that matches nobody is not a failure. It ends as a successful run with no rows.
💬 Support
Found a bug or missing a field? Open an issue on the actor's Issues tab in Apify Console — issues are answered within 1–2 business days. Feature requests are welcome: if TennisExplorer shows it, it can usually be added.
🛠 Additional services
Need a custom pipeline (scheduled line-movement archive, merged multi-source tennis feed, direct-to-database delivery) or a scraper for another sports/odds site? Contact me through the actor page — custom builds and SLAs available.
🔎 Explore more scrapers
More actors by the same developer: memo23 on Apify Store — flight prices, job boards, review platforms, real-estate portals and more, all pay-per-result.
🤖 For AI Agents & LLM Apps
This actor is MCP-friendly: modes map cleanly to tool calls (fixtures → "what's on today", matchDetails → "odds history for match X", h2h → "how do these two compare"). Outputs are stable, typed JSON with no HTML fragments, safe to feed straight into an LLM context or a function-calling loop. Use searchPlayers first to resolve names → slugs, then chain players/h2h. A call with an empty required field, or with a source that lacks the mode, fails in a few seconds with a message that names the field or the sources to use, so an agent can correct the call and retry. Keep maxItems low per call to control cost; every row is self-contained.
⚠️ Disclaimer
This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by TennisExplorer (tennisexplorer.com) or any of its operators, nor by the ATP, WTA, ITF or any tournament, nor by any bookmaker whose odds appear in the data, nor by Polymarket or Kalshi. All trademarks mentioned are the property of their respective owners.
The scraper accesses only publicly available pages — no authenticated endpoints, no paywalled content, and no live-score push feeds. Odds data is informational; nothing in this actor's output constitutes betting advice. Users are responsible for ensuring their use complies with TennisExplorer's Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), local gambling regulations, and any contractual obligations of their own organisation.
Prediction-market prices are read from Polymarket's and Kalshi's public APIs at run time. Users are responsible for complying with those platforms' terms, including Polymarket's data-licensing terms for institutional users.
SEO Keywords
tennis scraper, flashscore scraper, flashscore api, sofascore scraper, sofascore api, tennisexplorer scraper, tennis data api, tennis live scores scraper, atp rankings scraper, wta rankings scraper, tennis match statistics, tennis point by point data, tennis odds scraper, odds line movement, tennis betting data, tennis results api, atp scraper, wta scraper, tennis fixtures scraper, head to head tennis, tennisexplorer scraper, tennis explorer api, tennis odds scraper, tennis line movement data, opening closing odds tennis, tennis results scraper, tennis fixtures api, atp rankings scraper, wta rankings history, tennis head to head data, tennis player stats scraper, tennis betting data, odds history per bookmaker, tennis match details api, scrape tennisexplorer, tennis data for betting models, tennis backtesting dataset, apify tennis scraper, sofascore alternative tennis, flashscore alternative tennis, oddsportal alternative, polymarket tennis, polymarket tennis api, kalshi tennis, kalshi tennis odds, tennis prediction markets, prediction market vs bookmaker odds