Tennis Results & Odds Scraper
Pricing
from $1.05 / 1,000 results
Tennis Results & Odds Scraper
Scrape Tennis Explorer for ATP and WTA results and upcoming matches, singles and doubles: dates, tournament, players, set scores and listed decimal odds. Pick a date range for finished results; upcoming matches come from the public schedule. No login.
Pricing
from $1.05 / 1,000 results
Rating
0.0
(0)
Developer
Axiom Works
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
14 days ago
Last modified
Categories
Share
Tennis Explorer Scraper
Returns: one row per tennis match with date, tournament, player1, player2, setScores, sets1, sets2, winner, oddsPlayer1, oddsPlayer2 (plus rankings and player profiles).
Input: {"mode": "results", "tour": "atp-single", "dateFrom": "2026-09-28", "dateTo": "2026-09-28", "playerFilter": ["hurkacz"], "maxItems": 20}
Best for: tennis betting models and odds history, results databases by tour and day, tracking one player or tournament.
{"id": "match-3334240", "date": "2026-09-28", "tournament": "Chengdu", "player1": "Hurkacz H.", "player2": "Shapovalov D.", "setScores": ["6-7(8)", "6-3", "6-3"], "winner": "player1", "oddsPlayer1": 1.61, "oddsPlayer2": 2.29}
What does Tennis Explorer Scraper do?
Tennis Explorer Scraper collects public tennis data from Tennis Explorer and returns it as clean, structured records. It covers four kinds of data: finished match results for a day or a range of days, upcoming matches with decimal odds, the ATP and WTA singles rankings, and player profile details. You choose the mode, the tour and, where it applies, the dates or player links, and the Actor does the paging and parsing for you.
The Actor reads the same public pages you can open in a browser. It does not log in, it does not solve CAPTCHAs, and it keeps to a polite request rate of about one request per second. Results and upcoming pages list every match of a day on a single page, so a single day of ATP singles usually costs one request, even when it contains several hundred matches. When no filters are supplied, parsing stops once enough matches are available for the remaining maxItems budget. Filtered runs inspect the full table so later matching records are still included. Each page request has a bounded retry window of about 65 seconds, and missing pages return without retries.
Typical uses:
Build a historical results table of ATP or WTA matches, with set scores and bookmaker odds.
Feed a betting model or a sports analytics notebook with match odds and outcomes.
Track the current ranking and points of the top players and compare them from week to week.
Collect player profile facts such as age, height, playing hand and career-high ranking.
Monitor the daily schedule of upcoming matches together with the listed odds.
This Actor is an independent tool. It is not affiliated with or endorsed by Tennis Explorer.
What data can you get?
Every record has an id, a sourceUrl and a recordType of match, ranking or player. The other fields depend on the type. Fields that do not apply to a record type, or that the page does not show, are null.
| Field | Type | Record type | Description |
|---|---|---|---|
| id | string | all | Stable record ID (match ID, ranking tour with player slug, or player slug) |
| sourceUrl | string | all | Page the record was read from |
| recordType | string | all | match, ranking or player |
| matchId | string | match | Tennis Explorer match identifier |
| matchUrl | string | match | Link to the match detail page |
| tour | string | match | atp-single, wta-single, atp-double or wta-double |
| date | string | match | Match date in ISO format |
| time | string | match | Start time as shown on the page |
| tournament | string | match | Tournament name |
| tournamentUrl | string | match | Tournament page link, when the page provides one |
| player1, player2 | string | match | Players or doubles teams as shown, for example "Hurkacz H." |
| player1Url, player2Url | string | match | Profile links of the players or teams |
| player1Seed, player2Seed | number | match | Seed in brackets, when shown |
| sets1, sets2 | number | match | Sets won by each side (results mode) |
| setScores | array | match | Games per set such as "6-7(8)", "6-3"; tiebreak points of the set loser in brackets |
| oddsPlayer1, oddsPlayer2 | number | match | Decimal odds, when the page lists them |
| winner, winnerName | string | match | player1 or player2 and that player's name, for finished matches with a decided set count; null otherwise |
| resultType | string | match | completed, retired (fewer set scores than sets won) or walkover (no set scores), derived from the result row; null for upcoming matches |
| round, surface | string | match | Round (for example semifinal) and court surface from the match detail page. Only filled when includeMatchDetails is true |
| player1Rank, player2Rank | integer | match | Singles ranking of each player on the match page. Only with includeMatchDetails |
| player1HeightCm, player2HeightCm, player1Plays, player2Plays | integer, string | match | Height in cm and playing hand from the match page. Only with includeMatchDetails |
| rankingTour | string | ranking | atp-men or wta-women |
| rank | number | ranking | Position in the ranking |
| player | string | ranking, player | Player name |
| playerUrl | string | ranking, player | Player profile link |
| country | string | ranking, player | Country shown on the page |
| points | number | ranking | Ranking points |
| age | number | player | Age in years |
| dateOfBirth | string | player | ISO date of birth |
| height, weight | string | player | As shown, for example "196 cm" |
| plays | string | player | Playing hand |
| sex | string | player | As listed on the profile |
| currentRankSingles, highestRankSingles | number | player | Current and career-high singles rank |
| currentRankDoubles, highestRankDoubles | number | player | Current and career-high doubles rank |
The time field is null when the site shows no start time (--:--), which is common for Futures matches. Odds are not available for every match. Low-tier events and unplayed or retired matches often have no odds, and oddsPlayer1 and oddsPlayer2 are then null. Some tournament headers on the site, such as Futures groups, do not link to a tournament page, so tournamentUrl is null for those matches.
How to use
- Open the Actor in Apify Console and pick a mode.
- For results or upcoming matches, choose a tour and, optionally, a date range.
- For rankings, choose the ATP or WTA tour.
- For player profiles, paste one or more player links.
- Set
maxItemsto the number of records you want, then start the run. - Download the dataset as JSON, CSV, Excel or HTML, or read it through the API.
The modes work like this:
Results: one page per day and tour. The Actor walks from dateFrom to dateTo (inclusive, at most 62 days) and stops as soon as maxItems records are saved. If you give no date, it uses yesterday.
Upcoming: the schedule page for the tour. Without dates it reads today's schedule; with dates it reads each day in the range. Upcoming records have no scores, and odds are shown when the site has them.
Filters and details: playerFilter and tournamentFilter are case-insensitive substring matches applied to each parsed match, so a filtered run still reads one page per day; maxItems counts matches that pass the filter. With includeMatchDetails set to true, the Actor opens each kept match's detail page, which adds round, surface, rankings, height and playing hand and makes the run slower.
Rankings: the singles ranking of the ATP (men) or WTA (women) tour, about 50 players per page, until maxItems is reached or the list ends. Doubles tours map to the same singles ranking.
Players: one request per profile link. Only tennisexplorer.com/player/ links are accepted.
If a date has no matches, or a player link does not exist, the Actor logs a warning and finishes without creating placeholder records. If a mode needs input that is missing or malformed (for example a date that is not in YYYY-MM-DD format), the run fails with a clear message.
Input
| Field | Type | Description |
|---|---|---|
| mode | string | results, upcoming, rankings or players. Default results |
| tour | string | atp-single, wta-single, atp-double or wta-double. Default atp-single |
| dateFrom | string | First day, YYYY-MM-DD (results and upcoming) |
| dateTo | string | Last day, YYYY-MM-DD, inclusive. Defaults to dateFrom |
| playerUrls | array | Player profile links for players mode |
| playerFilter | array | Keep only matches where a player's name or profile slug contains one of these strings, e.g. hurkacz (results and upcoming) |
| tournamentFilter | array | Keep only matches whose tournament name contains one of these strings, e.g. Chengdu (results and upcoming) |
| includeMatchDetails | boolean | Default false. Opens each match's detail page to add round, surface, rankings, height and playing hand. One extra request per match |
| maxItems | integer | Maximum records to output, 1-10000. Default 50 |
| proxyConfiguration | object | Apify Proxy settings. Off by default; enable it if requests get blocked |
Example input for one day of ATP singles results:
{"mode": "results","tour": "atp-single","dateFrom": "2026-09-28","dateTo": "2026-09-28","maxItems": 50}
Example input for player profiles:
{"mode": "players","playerUrls": ["https://www.tennisexplorer.com/player/hurkacz/","https://www.tennisexplorer.com/player/medvedev-e0d2d/"],"maxItems": 10}
Output
A match record from results mode looks like this:
{"id": "match-3334240","sourceUrl": "https://www.tennisexplorer.com/results/?type=atp-single&year=2026&month=09&day=28","recordType": "match","matchId": "3334240","matchUrl": "https://www.tennisexplorer.com/match-detail/?id=3334240","tour": "atp-single","date": "2026-09-28","time": "13:25","tournament": "Chengdu","tournamentUrl": "https://www.tennisexplorer.com/chengdu/2026/atp-men/","player1": "Hurkacz H.","player2": "Shapovalov D.","player1Url": "https://www.tennisexplorer.com/player/hurkacz/","player2Url": "https://www.tennisexplorer.com/player/shapovalov/","player1Seed": 5,"player2Seed": 7,"sets1": 2,"sets2": 1,"setScores": ["6-7(8)", "6-3", "6-3"],"oddsPlayer1": 1.61,"oddsPlayer2": 2.29}
A ranking record:
{"id": "wta-women-rybakina","sourceUrl": "https://www.tennisexplorer.com/ranking/wta-women/?page=1","recordType": "ranking","rankingTour": "wta-women","rank": 1,"player": "Rybakina Elena","playerUrl": "https://www.tennisexplorer.com/player/rybakina/","country": "Kazakhstan","points": 9901}
A player record:
{"id": "player-hurkacz","sourceUrl": "https://www.tennisexplorer.com/player/hurkacz/","recordType": "player","player": "Hurkacz Hubert","country": "Poland","age": 29,"dateOfBirth": "1997-02-11","height": "196 cm","weight": "81 kg","plays": "right","currentRankSingles": 41,"highestRankSingles": 6}
Set scores list the games of the first side, then the second side, in the order the sets were played. When a set went to a tiebreak, the tiebreak points of the set loser are added in brackets. The dataset has an overview view with the most useful columns, and you can export the full records in any format Apify supports.
How much does it cost?
The Actor is charged per result: each record saved to the dataset counts as one result. The exact price is shown on the Pricing tab of the Actor page in Apify Console, together with your plan's discounts. Because maxItems is honoured exactly, you can cap the cost of a run by capping the number of records. Platform usage such as compute is billed according to your Apify plan.
Use with AI agents (MCP)
You can call this Actor from any MCP-compatible AI agent through the Apify MCP server. Add this to your MCP client configuration:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=axiomworks/tennis-explorer-scraper"}}}
Example prompts:
"Get all ATP singles results from 2026-09-28 with set scores and odds, limit to 30 matches."
"List the top 50 players in the WTA ranking with their points."
"Fetch the profile of https://www.tennisexplorer.com/player/hurkacz/ and tell me his highest singles rank."
"Show today's upcoming ATP doubles matches with odds."
Integrations and API
Run the Actor from code with the Apify API client or plain HTTP. Replace <YOUR_API_TOKEN> with your own token.
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_API_TOKEN>")run = client.actor("axiomworks/tennis-explorer-scraper").call(run_input={"mode": "rankings","tour": "atp-single","maxItems": 50,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["rank"], item["player"], item["points"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });const run = await client.actor('axiomworks/tennis-explorer-scraper').call({mode: 'results',tour: 'atp-single',dateFrom: '2026-09-28',maxItems: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();items.forEach((i) => process.stdout.write(`${i.id}\n`));
cURL:
curl -X POST "https://api.apify.com/v2/acts/axiomworks~tennis-explorer-scraper/run-sync-get-dataset-items" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"mode":"players","playerUrls":["https://www.tennisexplorer.com/player/hurkacz/"],"maxItems":5}'
You can also connect the dataset to Google Sheets, Make, Zapier, n8n or webhooks, schedule the Actor to run daily, and compare runs over time.
FAQ
How many matches can I get per day? ATP singles often has several hundred matches on a busy day, including lower-tier events. All of them are on one page, so a single day is quick to collect.
Why are some odds empty?
The site shows odds only for some matches. Where it shows none, the odds fields are null.
Why is sets1 empty for some matches?
When a match is unplayed, abandoned or not yet decided, the page shows no sets won, so the value is null. Upcoming matches never have set scores.
Which timezone are times in? Times are copied as shown on the page. The Actor does not convert them.
Do I need a proxy? Not normally. The site answers ordinary requests. If you see blocks, enable Apify Proxy in the input, and the Actor retries failed requests with backoff on a fresh session.
Can I get doubles? Yes, pick atp-double or wta-double as the tour for results and upcoming matches. Doubles teams are shown as the site displays them, and rankings are the singles ranking.
How often can I run it? As often as you like, but results for past days do not change, so scheduling a daily run for the previous day is usually enough.
Is it legal to scrape Tennis Explorer?
The Actor only reads publicly visible pages that need no login. Scraping public data is generally lawful in many places, but rules differ by country and by use. Facts such as scores and rankings are treated differently from creative content, and personal data in player profiles is subject to data protection laws such as GDPR. Check the site's terms of use and your local law, use the data responsibly, and take legal advice if you plan commercial redistribution.
Feedback
If a field is missing, a page layout changes, or you need another view of the data, open an issue from the Actor page in Apify Console. Bug reports with the run link and input help the most.