Tennis Scores, Stats & Rankings Scraper avatar

Tennis Scores, Stats & Rankings Scraper

Pricing

from $2.50 / 1,000 tennis matches

Go to Apify Store
Tennis Scores, Stats & Rankings Scraper

Tennis Scores, Stats & Rankings Scraper

Tennis results, fixtures and live scores for ATP, WTA, Challenger and ITF with set-by-set scores, optional match stats (aces, double faults, serve %, break points), surface and seeds, plus ATP/WTA singles and doubles rankings in one clean schema.

Pricing

from $2.50 / 1,000 tennis matches

Rating

0.0

(0)

Developer

Juddroid

Juddroid

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Share

Tennis results, fixtures, live scores, match stats and ATP/WTA rankings in one clean, ready-to-model dataset, from $2.50 per 1,000 matches.

What does Tennis Scores, Stats & Rankings Scraper do?

It collects tennis match data for the ATP Tour, the WTA Tour (including WTA 125 events), the Grand Slams, the ATP Challenger Tour and the ITF World Tennis Tour. Pick results, fixtures, live scores or rankings (or several at once), choose the tours and dates, and every match comes back in the same schema: tournament, category, surface, round, start time, players with country, seed and ranking, set-by-set score with tiebreak points, the winner, and the source links. Switch on match stats to add aces, double faults, first-serve percentage, break points saved and converted, winners, unforced errors and match and set durations. Rankings mode returns the ATP and WTA singles and doubles ranking lists with points, movement and tournaments played.

Why use it

  • One schema for every tour. ATP, WTA, Challenger and ITF matches have the same fields, so a Grand Slam final and an M15 first round go into the same table, model or database without per-source code.
  • Cheap per match, nothing charged for noise. $2.50 per 1,000 matches and $0.50 per 1,000 ranking rows. Filtered-out matches, status messages and the optional match stats cost nothing extra.
  • Built for models. Set scores are numbers ({ "p1": 7, "p2": 6, "tiebreak": { "p1": 7, "p2": 4 } }), stats come as { pct, won, total }, statuses are normalized (finished, retired, walkover, cancelled, live, scheduled), times are UTC ISO.
  • Robust sources with fallbacks. ATP/WTA come from ESPN's public scoreboard JSON and switch to the Flashscore data feed for any day ESPN fails. Rankings fall back between the official WTA API, Flashscore and ESPN. A failed source produces a free status row that says what is missing instead of a silent gap.
  • Monitoring that only charges for news. Only new results remembers delivered results between runs, so a schedule every 30 minutes returns (and charges) only matches that finished since the last run.
  • Always returns something useful. If the dates you ask for have no completed matches (off-season, rest days), the Actor returns the most recent completed match day and tells you so.

Source coverage

DataATPWTAChallengerITFWhere it comes from
ResultsAny date, years backAny date, including WTA 125Last 7 daysLast 7 daysESPN public scoreboard (ATP/WTA), Flashscore public data feed (Challenger/ITF, and ATP/WTA when ESPN fails)
FixturesAs soon as the order of play is outSameNext 7 daysNext 7 daysSame as results
Live scores (with the current game score)YesYesYesYesESPN + Flashscore
Round, seed, entry (Q/WC/LL), courtYesYesQualifying flag onlyQualifying flag onlyESPN
Surface and indoor flagMatches in the last/next 7 daysSameYesYesFlashscore
Match stats and durationsLast 7 daysLast 7 daysLast 7 days, where publishedWhere publishedFlashscore
Player's current singles rankingTop 150Top 150NoNoESPN
Singles rankingsAny depth, dated, with tournaments playedAny depth, dated, with tournaments playedNoNoFlashscore (ATP, names checked against ESPN), official WTA API (WTA); ESPN top 150 as a fallback
Doubles rankingsAny depthAny depthNoNoFlashscore (ATP), official WTA API (WTA)
Betting oddsNot includedNot includedNot includedNot includedNot freely available in these sources

What data you get

Three row types: match (charged), ranking (charged) and status (free).

Match rows (type: "match")

FieldDescription
matchId, sourceID at the source (espn or flashscore). sourceIds holds both IDs when the match was found in both
tour, gender, matchTypeatp, wta, challenger, itf or mixed (Grand Slam mixed doubles); men/women/mixed; singles/doubles
tournament{ id, name, category, surface, indoor, location, startDate, endDate }. Category is Grand Slam, ATP Tour, WTA Tour, WTA 125, ATP Challenger, ITF Men or ITF Women
round, courtFor example Quarterfinal, Qualifying 1st Round, Stadium Court
startAt, startTimeConfirmedUTC start time; false when the time is still "TBD"
status, statusDetailscheduled, live, finished, retired, walkover or cancelled, plus the source's wording (for example 2nd Set)
player1, player2{ id, name, country, countryName, seed, entry, ranking }. Doubles teams also have members[]
winner, winnerSideWinner's name and 1 or 2
score{ sets: [{ p1, p2, tiebreak?, durationMinutes? }], setsWon: { p1, p2 }, summary, currentGame? } from player1's point of view, e.g. 6-7(7-9) 7-6(7-2) 6-3
resultNoteThe source's one-line result, e.g. (1) Alexander Zverev (GER) bt (9) Alex de Minaur (AUS) 6-4 6-4
durationMinutes, statsWith Include match stats: match duration and { player1: {...}, player2: {...} } with aces, doubleFaults, firstServePercentage, firstServePointsWon, secondServePointsWon, breakPointsSaved, breakPointsConverted, firstReturnPointsWon, secondReturnPointsWon, winners, unforcedErrors, netPointsWon, servicePointsWon, returnPointsWon, totalPointsWon, serviceGamesWon, returnGamesWon, totalGamesWon and more where published
url, flashscoreUrl, scrapedAtSource page links and the scrape time

Ranking rows (type: "ranking")

FieldDescription
tour, rankingsTypeatp or wta; singles or doubles
rank, previousRank, movementMovement is positive when the player moved up
player, playerId, country, countryNamePlayer name and the source's player ID
points, tournamentsPlayedRanking points and the number of counted tournaments
rankingDate, sourceThe ranking week (YYYY-MM-DD) and the source list (flashscore, wtatennis or espn)

Status rows (type: "status", never charged) carry level (info or error) and a message, for example "No live matches right now", an off-season fallback notice or a source error.

How to use

  1. Open the Actor and pick What to scrape: results, fixtures, live, rankings or a combination.
  2. Pick the Tours. ATP and WTA include the Grand Slams.
  3. Optionally set From date / To date (YYYY-MM-DD, yesterday, today, -3, +2). Empty dates mean yesterday for results and today plus two days for fixtures.
  4. Optionally narrow it down by Tournament name or Player names, and switch on Include doubles or Include match stats.
  5. Click Start. Matches appear in the Matches view and rankings in the Rankings view; export them as JSON, CSV or Excel, or read them through the API.

Example input: last three days of ATP and Challenger results with stats for two players, plus the ATP top 100.

{
"mode": ["results", "rankings"],
"tours": ["atp", "challenger"],
"dateFrom": "-3",
"dateTo": "yesterday",
"players": ["Sinner", "Alexander Zverev"],
"includeMatchStats": true,
"rankingsType": "singles",
"maxRankingRows": 100
}

Monitoring input for a schedule every 30 minutes (returns only results that are new since the previous run):

{
"mode": ["results"],
"tours": ["atp", "wta"],
"dateFrom": "-1",
"dateTo": "today",
"onlyNewResults": true,
"stateStoreName": "tennis-results-monitor"
}

Output example

A completed ATP match with stats (stats trimmed):

{
"type": "match",
"matchId": "184954",
"source": "espn",
"tour": "atp",
"gender": "men",
"matchType": "singles",
"tournament": {
"id": "315-2026",
"name": "Rolex Shanghai Masters",
"category": "ATP Tour",
"surface": "hard",
"indoor": false,
"location": "Shanghai, China PR",
"startDate": "2026-10-05",
"endDate": "2026-10-18"
},
"round": "Quarterfinal",
"court": "Stadium Court",
"startAt": "2026-10-15T10:10:00.000Z",
"startTimeConfirmed": true,
"status": "finished",
"statusDetail": "Final",
"player1": { "id": "2375", "name": "Alexander Zverev", "country": "GER", "countryName": "Germany", "seed": 1, "entry": null, "ranking": 2 },
"player2": { "id": "2651", "name": "Alex de Minaur", "country": "AUS", "countryName": "Australia", "seed": 9, "entry": null, "ranking": 9 },
"winner": "Alexander Zverev",
"winnerSide": 1,
"score": {
"sets": [
{ "p1": 6, "p2": 4, "durationMinutes": 37 },
{ "p1": 6, "p2": 4, "durationMinutes": 41 }
],
"setsWon": { "p1": 2, "p2": 0 },
"summary": "6-4 6-4"
},
"resultNote": "(1) Alexander Zverev (GER) bt (9) Alex de Minaur (AUS) 6-4 6-4",
"durationMinutes": 78,
"stats": {
"player1": {
"aces": 10,
"doubleFaults": 1,
"firstServePercentage": 80,
"firstServePointsWon": { "pct": 80, "won": 35, "total": 44 },
"breakPointsSaved": { "pct": 100, "won": 5, "total": 5 },
"breakPointsConverted": { "pct": 100, "won": 2, "total": 2 },
"winners": 24,
"unforcedErrors": 15
},
"player2": {
"aces": 6,
"doubleFaults": 2,
"firstServePercentage": 63,
"firstServePointsWon": { "pct": 81, "won": 25, "total": 31 }
}
},
"url": "https://www.espn.com/tennis/scoreboard/tournament/_/eventId/315-2026/competitionType/1",
"sourceIds": { "espn": "184954", "flashscore": "ERN0r0Qp" },
"scrapedAt": "2026-10-16T12:56:49.062Z",
"flashscoreUrl": "https://www.flashscore.com/match/tennis/zverev-alexander-dGbUhw9m/de-minaur-alex-EZgZ9Xfh/?mid=ERN0r0Qp"
}

A Challenger fixture (names are abbreviated as published for Challenger and ITF):

{
"type": "match",
"matchId": "GI66xd7s",
"source": "flashscore",
"tour": "challenger",
"tournament": { "id": "pKRztbdD", "name": "Olbia", "category": "ATP Challenger", "surface": "hard", "indoor": false, "location": "Olbia, Italy" },
"startAt": "2026-10-16T13:00:00.000Z",
"status": "scheduled",
"player1": { "id": "pGBaKGOn", "name": "Fearnley J.", "countryName": "United Kingdom" },
"player2": { "id": "hMR2isnm", "name": "Mrva M.", "countryName": "Czech Republic" },
"url": "https://www.flashscore.com/match/tennis/fearnley-jacob-pGBaKGOn/mrva-maxim-hMR2isnm/?mid=GI66xd7s"
}

A ranking row:

{
"type": "ranking",
"tour": "wta",
"rankingsType": "singles",
"rank": 3,
"previousRank": 5,
"movement": 2,
"player": "Mirra Andreeva",
"playerId": "331809",
"country": "RUS",
"points": 6371,
"tournamentsPlayed": 20,
"rankingDate": "2026-10-12",
"source": "wtatennis"
}

Pricing

Pay per event, no subscription:

EventPrice
match: one match row (result, fixture or live)$0.0025 ($2.50 per 1,000)
ranking-row: one ranking place$0.0005 ($0.50 per 1,000)

Worked examples:

  • Daily ATP + WTA singles results (about 20 to 60 matches a day in season): about $0.05 to $0.15 a day, $1.50 to $4.50 a month.
  • A full week of everything (ATP, WTA, Challenger and ITF, singles and doubles, about 1,900 matches in our test week): about $4.85.
  • Top 100 ATP and WTA singles rankings once a week: 200 rows = $0.10 a week.
  • The default example run (yesterday's ATP/WTA results plus the top 20 of both rankings, 21 matches + 40 ranking rows in our test): about $0.07.

Not charged: status rows, matches removed by your tour, date, player or tournament filters, results skipped by Only new results, and match stats or durations (they are part of the match row). Max match rows and the run's maximum charge setting cap your spend; the Actor stops cleanly when the limit is reached.

Integrations and scheduling

  • Schedules: run it every few minutes for live scores, every 30 to 60 minutes with Only new results for result feeds, or weekly on Monday for rankings.
  • Webhooks: trigger your pipeline, a Slack message or a model retrain when a run succeeds.
  • API and SDKs: start runs and read the dataset from any language; use ?view=overview for the flat match table and ?view=rankings for rankings.
  • Integrations: send rows to Google Sheets, Airtable, BigQuery, S3, Zapier or Make with Apify integrations.
  • AI agents and MCP: the Actor works as a tool through the Apify MCP server, so an assistant can answer "how did Swiatek do this week?" with fresh data.

FAQ and limitations

How fresh are live scores? Each run is a snapshot taken at run time, including the current game score. Schedule it every 1 to 5 minutes for a live feed. Live mode can return zero matches when nothing is being played; you then get a free status row.

Why do Challenger and ITF matches have abbreviated names and no round or seed? Those tours come from Flashscore's data feed, which publishes names as "Surname I." and does not include rounds or seeds in its daily list. ATP and WTA matches use full names, rounds and seeds from ESPN.

How far back can I go? ATP and WTA results go back years (31 days per run). Challenger and ITF matches, match stats and the surface are available for the last 7 and next 7 days only, so schedule the Actor if you want to build a history.

Which ranking list is used? ATP rankings come from Flashscore's dated list (names and country codes checked against ESPN), WTA rankings from the official WTA rankings API. rankingDate is the ranking week. The per-match player.ranking is ESPN's current list (top 150), which can differ by a few places from the dated official list while a tournament is running.

Are odds or head-to-head records included? Odds are not included because they are not freely available in these sources. For head-to-head records, filter results by both players' names over the dates you need.

Are times local? No. All dates and times are UTC, and the date filters use UTC days.

What happens when a source is down? ESPN days that fail are filled from Flashscore; rankings fall back to another list; anything still missing is explained in a free status row. If a source starts blocking requests, the Actor stops asking it for the rest of the run instead of hammering it.

Responsible use. The Actor collects factual sports data only: names, dates, scores, statistics and ranking numbers from publicly available, unauthenticated feeds. It does not collect logos, photos, flags, editorial articles or any data behind a login, and it keeps request rates low. It is not affiliated with or endorsed by the ATP, WTA, ITF, ESPN or Flashscore. You are responsible for using the data in line with the sources' terms and the law that applies to you, for example when you republish data commercially. Use the data for analysis and entertainment; it is not betting advice.