ActorStack.dev

How to scrape ATP, WTA, Challenger and ITF match results

A walkthrough of extracting tennis data: one entity type per run, the day boundary that has to be pinned, and the two enrichments that cost an extra request each.

By Oswaldo Carabano8 min read

Short answer

Tennis match results are extracted one entity type per run — results, schedule, players or rankings — because those four have genuinely different fields. A day of results is one request and typically returns 150 to 600 matches across ATP and WTA singles and doubles, with history back to 1995. Every request is pinned to UTC, because the source decides which matches belong to which day from a timezone cookie and the same date returned 227 matches in one timezone against 269 in another. Match detail and betting odds are both off by default, each costing an extra request per match.

Key points

  • One entity type per run, so the downloaded file has one clean shape rather than the union of four schemas.
  • One request covers one whole day of results and typically returns 150 to 600 matches with all four tours selected.
  • Leaving all four tours selected is the cheapest option, because it is a single request per day rather than one per tour.
  • Dates accept relative forms — `today`, `yesterday`, `-7d`, `+3d` — which is what makes a scheduled daily run a fixed input.
  • `includeMatchDetail` costs one extra request per match, so on a 400-match day it multiplies the request count by 400.
On this page8 sections

Tennis results are a good dataset and a slightly awkward one: four tours, two formats, matches that stop halfway, and a calendar day that depends on who is asking. Most of this guide is about the last two.

One entity type per run

Results, schedule, players and rankings are separate runs. They have genuinely different fields — a ranking row has a position and points, a match row has two players and a scoreline — and mixing them would give every row the union of four schemas with most columns empty.

entityTypeRowsTypical size
resultsFinished matches for a date range150–600 per day
scheduleUpcoming and in-progress matches~200 per day
playersProfiles, optionally with history1 per player
rankingsATP or WTA tables50 per page

Step 1 — set the date range

dateFrom and dateTo take YYYY-MM-DD or a relative form: today, yesterday, -7d, +3d. The relative forms are what make a scheduled daily run a fixed input rather than something that has to be templated.

Days are cut at 00:00 UTC, always. That is not a default you can change, and there is a reason — the same date returned 227 matches once and 269 the next time.

Step 2 — choose the tours

ATP singles, ATP doubles, WTA singles and WTA doubles. Leaving all four selected is the cheapest option, because it is a single request per day rather than one per tour — the site returns them together.

Step 3 — decide about detail and odds

includeOdds is also off by default, for a different reason: scores are facts and odds are somebody's licensed product.

Step 4 — run it

input.json
{
  "entityType": "results",
  "dateFrom": "2026-08-01",
  "dateTo": "2026-08-07",
  "tours": ["atp-single", "atp-double", "wta-single", "wta-double"],
  "includeMatchDetail": false,
  "maxItems": 5000
}

maxItems is a hard cap on delivered rows and defaults to 10,000. For a backfill it has to be raised, and there is a pricing reason to raise it generously rather than in steps — what a season costs.

Reading the output

Every row carries status, which is completed, retired or walkover. The source labels none of those — it is derived, and about 4.6% of matches are affected.

Player names come from the underlying attribute rather than the visible label, which matters on the 17.4% of rows that are doubles — why the visible name is truncated. The full field reference covers the rest.

What a run costs

$0.0015 per row for the first 10,000 rows of a run and $0.0003 after that, plus a $0.0024 surcharge per match when detail is enabled. A week of results is about $4. Failed requests are never charged; they go to the ERRORS record instead.

Four mistakes that waste a run

Leaving `maxItems` at 10,000 for a backfill. It is a hard cap, and it stops the run exactly where the cheaper price tier was about to start.

Enabling match detail for a whole season. One extra request per match, on 148,000 matches, is a different kind of run.

Running one tour at a time. All four in one request costs one request; four runs cost four.

Treating an unfinished match as a completed one. Roughly one match in twenty is not completed, and the scoreline alone does not say so.

Frequently asked questions

Can I get results and rankings in one run?
No, and that is deliberate. Results, schedules, player profiles and rankings have genuinely different fields, so the Actor returns one type per run. Mixing them would give every row the union of four schemas with most columns empty.
How many matches does one day return?
Typically 150 to 600 for finished results with all four tours selected, and around 200 for a schedule. One request covers one whole day, so a season is 365 requests and about 148,000 matches.
Do I need match detail?
Only for round, surface, full player names, both rankings and head-to-head. It costs one extra request per match, so on a 400-match day it turns one request into 401. It is off by default for that reason.
How far back can I go?
To 1995, with the same input shape — a backfill is just a wider date range. The whole archive is roughly 2.4 million matches and a single season is about 148,000.

Sources

Every URL below was requested and returned a page on the date shown.

  1. Operator claimchecked 9 Sept 2026
    TennisExplorer Scraper — Actor README and input schemaActorStack / Apify Store
  2. Site declarationchecked 9 Sept 2026
    tennisexplorer.com/robots.txtTennisExplorer
  3. Operator claimchecked 9 Sept 2026
    WTA singles rankingsWomen's Tennis Association
  4. Operator claimchecked 9 Sept 2026
    International Tennis FederationITF
A shelf of office binders with dated labels along their spines.
TennisExplorerGuide

Backfilling history

History goes back to 1995 with the same input. What a season actually costs, why the price has two tiers, and the settings that decide how long it takes.

6 min
A desk with stacked legal reference books, loose documents and a newspaper.
TennisExplorerExplainer

Why odds are off

The same results page carries match scores and bookmaker odds, and the two sit in different positions. Why one is on by default and the other is not.

5 min
A laptop screen showing a plain text-mode terminal with a command prompt.
TennisExplorerExplainer

The tennis API question

The tours publish rankings and draws for readers, not as APIs. Commercial feeds are licensed per use. What is left is reading a results site, and what that does and does not entitle you to.

7 min