Sofascore Tennis Scraper — ATP & WTA Set Scores avatar

Sofascore Tennis Scraper — ATP & WTA Set Scores

Pricing

from $2.50 / 1,000 tennis matches

Go to Apify Store
Sofascore Tennis Scraper — ATP & WTA Set Scores

Sofascore Tennis Scraper — ATP & WTA Set Scores

Scrape ATP, WTA, Challenger and ITF tennis from Sofascore. Every match returns the set-by-set score with tiebreaks, both players with country, live ranking and seed, plus surface, round, tier, duration and winner. Live, finished and upcoming draws. No API key or login — runs on the free plan.

Pricing

from $2.50 / 1,000 tennis matches

Rating

0.0

(0)

Developer

Elena Vance

Elena Vance

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Scrape tennis matches from Sofascore with the set-by-set score, both players, seeds, live rankings, surface, round and result. ATP, WTA, Challenger, WTA 125, ITF, UTR, Davis Cup and the Billie Jean King Cup. Singles and doubles. No Sofascore API key, no login.

Results are stored in an Apify dataset you can export as JSON, CSV, Excel, XML or HTML.

What you get

A real run, { "tours": ["atp", "wta"], "dateFrom": "2026-08-26" } — 165 matches from the four ATP/WTA draws played that day:

Player 1Player 2ScoreRoundSurfaceDuration
Seongchan HongNikoloz Basilashvili [19]6-3 7-6(1)Qualification Round 1Hardcourt outdoor110 min
Jack Secord [WC]Tristan Schoolkate3-6 2-6Qualification Round 1Hardcourt outdoor86 min
Kristina Penickova [WC]Harriet Dart [29]7-5 0-6 3-6Qualification Round 2Hardcourt outdoor124 min
Michael Antonius [WC]Henry Searle6-1 6-2Qualification Round 1Hardcourt outdoor67 min

Every row also carries the per-set breakdown as structured data (games, tiebreak points and duration per set), both players' IDs, countries and ATP/WTA rankings at match time, the tournament tier and ranking points, the venue, and a direct link to the match — see Output for the full shape.


Why this is cheap to run

Two reasons: the tour filter, and no proxy.

The tour filter is the price of the run

A single day of tennis carries around 150 tournaments — but only about six of them are ATP or WTA. The other 96% is the ITF and UTR development circuit, which most buyers never want and would otherwise pay to download and throw away.

Measured on a real date (2026-08-29, 147 tournaments in total):

Tours selectedMatch typeTournaments fetched
["atp", "wta"] (default)singles4
["atp", "wta"]all6
+ challengersingles11
+ itf-men, itf-womensingles40
every tourall147

Leaving the default alone makes a run roughly 20x cheaper than scraping the whole calendar. Choosing "Singles" also skips the separate doubles draws, which are about a quarter of a day's tournaments again.

No premium plan and no residential proxy

This Actor talks to sofascore.com/api/v1 directly — no headless browser. Sofascore screens requests on their TLS handshake, which this Actor clears with a browser-grade HTTP client rather than by paying for egress.

Sofascore does refuse a share of datacenter IPs, Apify's own runners included, so a run on the platform normally reaches Sofascore through a proxy. What matters is which proxy — the Actor escalates cheapest-first and stops at the first tier that works:

  1. Direct — free. This is what a run from your own machine usually uses.
  2. Datacenter proxyincluded in every Apify plan, the free tier included. Up to 12 IPs are rotated here. Across five platform runs the most any single run needed was 4, and every run got through on this tier.
  3. Residential proxy — the metered one, reached only if all 12 free IPs above were refused.

So there is no residential-proxy add-on requirement and no egress bill to absorb. Across eight platform runs, every one was served by a free datacenter IP.

Two modes

ModeInputWhat it fetches
Live (liveOnly: true)none neededEvery tennis match in progress right now, on the tours you chose. One fast call. Live rows carry the running set score and the current game point.
Daily schedule (default)dateFrom / dateToMatches for each date in range. Works out which tournaments played that day, keeps the ones on your tours, ranks them by Sofascore's own follower count and fetches the top maxTournamentsPerDate — or pass tournamentIds to skip discovery entirely.

Both past and future dates work. A forward-dated run returns the published draw: players, seeds, rankings and round, with the score fields empty.

What makes this different

  • The set score, assembled for you. scoreString is the line a human reads — 6-3 7-6(1) — with the loser's tiebreak points in brackets, plus a structured sets array carrying games, tiebreak points and duration per set.
  • A tour filter that is a real cost control, not a convenience. See the table above.
  • Seeds survive as seeds. WC, Q, LL and A are 30% of all seeds in a Grand Slam draw. They are kept verbatim in seed, with seedNumber offered separately for the numeric ones — nothing is silently dropped by an integer cast.
  • Retirements and walkovers are labelled. Sofascore files both under status finished, so a naive results filter quietly mixes in matches that were never played. resultType names them (completed / retired / walkover) and isCompleted is false for both.
  • Live state is not left on finished rows. Sofascore leaves the last game's point on a match that ended hours ago; this Actor drops it, so a historical row never carries a live-looking game score. Same for the tiebreak fields, which carry stray game points (40) on sets that never had a tiebreak — only a genuine 7-6 set reports one.
  • A $0.00005 start fee, against up to $0.05 on comparable tennis Actors. On a small run that gap is most of the bill.
  • Failures are never billed. Rows are charged only once stored; a tournament that cannot be read is reported in the run summary and costs nothing, and unusable input returns an unbilled diagnostic row instead of failing the run.

Input

FieldTypeDefaultNotes
toursarray["atp","wta"]atp, wta, challenger, wta-125, itf-men, itf-women, utr-men, utr-women, davis-cup, billie-jean-king-cup, united-cup, exhibition, international. The main cost control.
matchTypestringsinglessingles, doubles or all.
liveOnlybooleanfalseLive snapshot instead of a date range.
dateFrom / dateTostringtodayYYYY-MM-DD, inclusive, max 31 days per run.
tournamentIdsarraySofascore unique-tournament IDs; skips discovery. The tour filter is not applied to these.
maxTournamentsPerDateinteger30Cap on tournaments fetched per date, after the tour filter.
maxDiscoveryPagesinteger2A whole tennis day fits in 2 pages.
maxItemsinteger500Hard cap on stored matches.
proxyConfigurationobjectoffLeave off; escalation is automatic.

Grand Slams are ATP and WTA events — they are already included in the default. There is no separate grand-slam tour, even though Sofascore's own category list shows one; that entry is a UI filter with a negative ID and matches no tournament. Filter on tier == "grand-slam" in the output instead.

Output

One row per match:

{
"eventId": 16931831,
"matchUrl": "https://www.sofascore.com/tennis/match/pablo-llamas-ruiz-lloyd-harris#id:16931831",
"startTimeIso": "2026-08-28T15:00:00+00:00",
"tour": "ATP", "tourSlug": "atp",
"tournamentId": 2449, "tournamentName": "US Open, Men",
"eventName": "US Open, New York, USA, Qualifying",
"tier": "grand-slam", // grand-slam | p1000 | p500 | p250 | lower
"surface": "Hardcourt outdoor",
"rankingPoints": 2000,
"matchType": "singles", "gender": "M",
"round": { "name": "Qualification Final", "slug": "qualification-final", "number": 250 },
"venue": { "court": "Court 14", "city": "New York", "country": "USA" },
"status": { "code": 100, "description": "Ended", "type": "finished" },
"resultType": "completed", // completed | retired | walkover | canceled | live | scheduled
"isCompleted": true,
"winner": 1, "winnerName": "Lloyd Harris",
"player1": {
"id": 157808, "name": "Lloyd Harris", "shortName": "L. Harris",
"country": "South Africa", "countryCode": "ZAF",
"ranking": 175, "seed": null, "seedNumber": null,
"setsWon": 2, "isWinner": true, "partners": []
},
"player2": { "…": "same shape; `partners` holds both players of a doubles pair" },
"setsWonPlayer1": 2, "setsWonPlayer2": 0,
"scoreString": "7-6(3) 6-3",
"sets": [
{ "set": 1, "player1": 7, "player2": 6,
"player1TieBreak": 7, "player2TieBreak": 3, "durationSeconds": 3752 },
{ "set": 2, "player1": 6, "player2": 3,
"player1TieBreak": null, "player2TieBreak": null, "durationSeconds": 2310 }
],
"matchDurationSeconds": 6062,
"currentPoint": null, // live matches only: { player1, player2, set }
"firstToServe": 1
}

What this Actor does not return

  • Point-by-point rallies and per-match serve/return statistics. This Actor is the match and its score. Sofascore publishes deeper per-match statistics through a different endpoint.
  • Who is serving right now. Sofascore publishes firstToServe — who served the opening game — and no current-server field, so none is invented.
  • A doubles pair's ranking. The payload carries no pair-level rank and none is synthesised. Individual players' singles rankings are present.
  • ATP/WTA ranking tables. Each match carries both players' rankings inline; for the full tables see the related Actor below.
  • A "match tiebreak" flag. A deciding-set match tiebreak is reported by Sofascore in the games field itself, so it appears as e.g. 4-10 rather than in brackets.

Example runs

// Yesterday's ATP and WTA results
{ "tours": ["atp", "wta"], "dateFrom": "2026-08-26" }
// Everything live right now, every tour, singles and doubles
{ "tours": ["atp", "wta", "challenger", "itf-men", "itf-women"],
"matchType": "all", "liveOnly": true }
// The upcoming US Open draw, both singles events
{ "tournamentIds": [2449, 2601], "dateFrom": "2026-09-01", "dateTo": "2026-09-03" }
// A month of Challenger results for a model
{ "tours": ["challenger"], "dateFrom": "2026-08-01", "dateTo": "2026-08-31",
"maxItems": 5000 }