New · updated every hour

ATP and WTA seasons in Sackmann's columns, current to the hour.

Whole seasons of ATP and WTA singles results in the columns of Jeff Sackmann's atp_matches_YYYY.csv and wta_matches_YYYY.csv, from 1990 to this week. Code and notebooks that read his files by column name keep working: winner and loser with rank and ranking points of that week, seed, entry, hand, height, country and age, the score, round, minutes, serve statistics and each player's Elo before the match.

Independent tool, not affiliated with Jeff Sackmann, Tennis Abstract, Flashscore, Livesport, the ATP, the WTA or the ITF.

sample row · atp_matchesHong Kong · F · 20241230

Alexandre Muller beat Kei Nishikori 2-6 6-1 6-3 104 min

winner_rank · loser_rank
67 v 106
rank_points
778 v 578
hand · ht
R 183 v R 178
ioc · age
FRA 27.9 v JPN 35
loser_entry
WC
tourney_level · best_of
A · 3
w_ace · l_ace
2 v 4
bpSaved / bpFaced
4/6 v 4/8
winner_elo · loser_elo
2110 v 2259 before the match, overall
since 1990every ATP and WTA season
his columnsin his order, ready for CSV
ranksof that week, from the official lists
seedsand Q, WC, LL, PR from the official draws
Eloboth players, before the match
Live data

Straight from the tennis database.

What your runs read: decades of matches, the official ranking lists of every week, and the Elo leaders of both tours. Matches update every hour.

What you get

Same columns, same order.

One row per played singles match, in the columns of his files, then four extra columns: match_id, tour, winner_elo and loser_elo. Export the dataset as CSV and the columns come in his order.

Tournament

  • tourney_id
  • tourney_name
  • surface
  • draw_size
  • tourney_level
  • tourney_date
  • match_num

Match

  • score 7-6(5) 6-4, RET, W/O
  • best_of
  • round Q1 … F
  • minutes

Extra columns

  • match_id
  • tour
  • winner_elo
  • loser_elo

Winner and loser

  • winner_id
  • winner_seed
  • winner_entry
  • winner_name
  • winner_hand
  • winner_ht
  • winner_ioc
  • winner_age
  • winner_rank
  • winner_rank_points
  • and the same loser_*

Serve statistics

  • w_ace
  • w_df
  • w_svpt
  • w_1stIn
  • w_1stWon
  • w_2ndWon
  • w_SvGms
  • w_bpSaved
  • w_bpFaced
  • and the same l_*, ATP and WTA from 2012

Ways to run it

years

Whole seasons

One season or ten, from 1990. An ATP season is about 4,300 matches, a WTA season about 3,800.

dateFrom · dateTo

The last 7 days

Schedule it weekly and upsert by match_id to keep your own copy current, without duplicates.

tours

Challenger and ITF

challenger-men gives his qual_chall files, itf-men his futures.

CSV export

Drop-in files

Code that reads his files by column name works unchanged.

Use cases

The best-known tennis dataset layout, kept current.

bettors & modellers

Prediction models

Train on the same columns as the best-known open tennis dataset, with this week's matches in it.

researchers & journalists

Research

Season-by-season results with rankings, seeds and serve statistics.

data teams

Replace a stale copy

Refresh your atp_matches and wta_matches tables weekly with one scheduled task.

AI agents

Structured history

"Which players won the most tiebreaks on clay this season?" The agent gets the rows as JSON or CSV.

How to run

From a season to a CSV in seconds.

  1. 01

    Open it on Apify

    Sign in with a free Apify account. No card needed to try.

  2. 02

    Pick seasons and tours

    Set years and tours, and maxItems above the season size.

  3. 03

    Export as CSV

    The columns come in his order. JSON, Excel and the API work too, or schedule it to keep your copy current.

More inputs to try

  • { "years": [2023, 2024, 2025], "tours": ["wta"], "maxItems": 15000 }three WTA seasons
  • { "years": [], "tours": ["atp", "wta"], "maxItems": 10000 }this season so far, both tours
  • { "years": [2025], "tours": ["challenger-men"], "maxItems": 20000 }a Challenger season (his qual_chall file)
  • { "years": [1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999], "tours": ["atp"], "maxItems": 40000 }the 1990s, ATP
{
  "years": [2025],
  "tours": ["atp"],
  "maxItems": 5000
}

The full 2025 ATP season with qualifying: 4,285 matches, ready to export as CSV.

Reliability

Runs that don't break.

The same factory promises as every CrawlPlant Actor. How the factory works

Updated every hour

This week's matches are in the dataset within the hour: no waiting for a yearly update.

A season in seconds

Rows come from our tennis database of more than 900,000 matches; nothing is scraped during your run.

Official sources

Ranks from the official weekly lists, seeds and entries from the official draws, hand and height from the official player profiles.

Checked every 3 hours

Canary checks test the tennis database and watch its freshness around the clock.

A summary every run

Each run writes a summary with the rows saved and any warnings.

Pricing

Pricing

$1.00per 1,000 matches

Down to $0.70 per 1,000 on Apify's Gold plan. Ranks, seeds, serve statistics and Elo are all in the row, and platform usage is included.

  • The full 2025 ATP season with qualifying, 4,285 matches: about $4.30
  • The 1990 ATP season, 3,580 matches: about $3.58
  • A week of ATP and WTA matches, 193 rows: about $0.19
  • No subscription. The free plan is enough to try it
Events and prices per 1,000, on Apify's Free and Gold plans
eventFreeGold
match one row in his columns, plus Elo$1.00$0.70
FAQ

About this Actor.

General questions are on the home page. Need odds, live scores or head-to-heads too? See Flashscore Tennis. Something else? piotr@crawlplant.com

Is this Jeff Sackmann's data?

No. It's an independent dataset in the same column layout, built from Flashscore results and the official ATP and WTA ranking lists, draws and player profiles. His repositories are a great resource; this Actor gives you the same shape, current to the hour.

How far back does it go?

ATP and WTA from 1990, Challenger from 2008 and ITF from 2011. Serve statistics start in 2012; earlier seasons have results, ranks, seeds, hand, height and age.

Which ids and codes does it use?

Player ids and tourney_id are Flashscore's ids (strings), and match_id is Flashscore's match id. tourney_date is the Monday of the main-draw week (YYYYMMDD, as in his files). tourney_level: G Grand Slam, M Masters 1000, F tour finals, D Davis Cup and Billie Jean King Cup, A other tour level, C Challenger, S ITF.

Are qualifying matches included?

Yes, in the same rows with round Q1 to Q3. For his main-draw-only files, keep the rows whose round doesn't start with "Q".

Can an AI agent use it?

Yes. Add https://mcp.apify.com?tools=crawlplant/tennis-match-dataset to any MCP client and the agent can pull whole seasons on its own, to answer questions like "which players won the most tiebreaks on clay this season?".