Tennis Results & Odds Scraper avatar

Tennis Results & Odds Scraper

Pricing

from $1.05 / 1,000 results

Go to Apify Store
Tennis Results & Odds Scraper

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

Axiom Works

Maintained by Community

Actor 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.

FieldTypeRecord typeDescription
idstringallStable record ID (match ID, ranking tour with player slug, or player slug)
sourceUrlstringallPage the record was read from
recordTypestringallmatch, ranking or player
matchIdstringmatchTennis Explorer match identifier
matchUrlstringmatchLink to the match detail page
tourstringmatchatp-single, wta-single, atp-double or wta-double
datestringmatchMatch date in ISO format
timestringmatchStart time as shown on the page
tournamentstringmatchTournament name
tournamentUrlstringmatchTournament page link, when the page provides one
player1, player2stringmatchPlayers or doubles teams as shown, for example "Hurkacz H."
player1Url, player2UrlstringmatchProfile links of the players or teams
player1Seed, player2SeednumbermatchSeed in brackets, when shown
sets1, sets2numbermatchSets won by each side (results mode)
setScoresarraymatchGames per set such as "6-7(8)", "6-3"; tiebreak points of the set loser in brackets
oddsPlayer1, oddsPlayer2numbermatchDecimal odds, when the page lists them
winner, winnerNamestringmatchplayer1 or player2 and that player's name, for finished matches with a decided set count; null otherwise
resultTypestringmatchcompleted, retired (fewer set scores than sets won) or walkover (no set scores), derived from the result row; null for upcoming matches
round, surfacestringmatchRound (for example semifinal) and court surface from the match detail page. Only filled when includeMatchDetails is true
player1Rank, player2RankintegermatchSingles ranking of each player on the match page. Only with includeMatchDetails
player1HeightCm, player2HeightCm, player1Plays, player2Playsinteger, stringmatchHeight in cm and playing hand from the match page. Only with includeMatchDetails
rankingTourstringrankingatp-men or wta-women
ranknumberrankingPosition in the ranking
playerstringranking, playerPlayer name
playerUrlstringranking, playerPlayer profile link
countrystringranking, playerCountry shown on the page
pointsnumberrankingRanking points
agenumberplayerAge in years
dateOfBirthstringplayerISO date of birth
height, weightstringplayerAs shown, for example "196 cm"
playsstringplayerPlaying hand
sexstringplayerAs listed on the profile
currentRankSingles, highestRankSinglesnumberplayerCurrent and career-high singles rank
currentRankDoubles, highestRankDoublesnumberplayerCurrent 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

  1. Open the Actor in Apify Console and pick a mode.
  2. For results or upcoming matches, choose a tour and, optionally, a date range.
  3. For rankings, choose the ATP or WTA tour.
  4. For player profiles, paste one or more player links.
  5. Set maxItems to the number of records you want, then start the run.
  6. 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

FieldTypeDescription
modestringresults, upcoming, rankings or players. Default results
tourstringatp-single, wta-single, atp-double or wta-double. Default atp-single
dateFromstringFirst day, YYYY-MM-DD (results and upcoming)
dateTostringLast day, YYYY-MM-DD, inclusive. Defaults to dateFrom
playerUrlsarrayPlayer profile links for players mode
playerFilterarrayKeep only matches where a player's name or profile slug contains one of these strings, e.g. hurkacz (results and upcoming)
tournamentFilterarrayKeep only matches whose tournament name contains one of these strings, e.g. Chengdu (results and upcoming)
includeMatchDetailsbooleanDefault false. Opens each match's detail page to add round, surface, rankings, height and playing hand. One extra request per match
maxItemsintegerMaximum records to output, 1-10000. Default 50
proxyConfigurationobjectApify 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 ApifyClient
client = 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.

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.