ATP & WTA Tennis Match Dataset - Sackmann CSV Format
Pricing
from $0.70 / 1,000 matches
ATP & WTA Tennis Match Dataset - Sackmann CSV Format
Whole seasons of ATP and WTA singles results in the columns of Jeff Sackmann's tennis_atp / tennis_wta CSV files, from 1990 to this week: winner and loser, rank, seed, entry, hand, height, age, score, round, minutes, serve statistics, plus pre-match Elo. Updated every hour. Export as CSV.
Pricing
from $0.70 / 1,000 matches
Rating
0.0
(0)
Developer
CrawlPlant
Maintained by CommunityActor stats
0
Bookmarked
16
Total users
1
Monthly active users
13 hours ago
Last modified
Share
Independent tool, not affiliated with, endorsed by or connected to Jeff Sackmann, Tennis Abstract, Flashscore, the ATP, the WTA or the ITF. It reads the public match data that flashscore.com shows to every visitor and the official ATP and WTA ranking lists and player profiles.
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, updated every hour. 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 (Q, WC, LL, PR), hand, height,
country and age, the score (7-6(5) 6-4, RET, W/O), best of, round, minutes and the serve statistics
(w_ace ... l_bpFaced), plus each player's Elo before the match. Export the dataset as CSV.
Why this one
- Current. This week's matches are in the dataset within the hour: no waiting for a yearly update.
- Same columns, same order.
tourney_id,tourney_name,surface,draw_size,tourney_level,tourney_date,match_num,winner_*,loser_*,score,best_of,round,minutes,w_*/l_*serve columns,winner_rank,winner_rank_points,loser_rank,loser_rank_points. - Seeds and entries from the official draws, hand and height from the official ATP and WTA player profiles, ranks from the official weekly lists.
- Elo included. Four extra columns close each row:
match_id,tour,winner_eloandloser_elo(pre-match Elo, overall). - ATP, WTA, Challenger and ITF.
tours: ["challenger-men"]gives his qual_chall files,["itf-men"]his futures. - Any range. Whole seasons, or the last 7 days to keep your own copy current.
- Tomorrow's matches, in his columns.
sackmannFile: "upcoming"lists today's and tomorrow's scheduled singles with both players' rank, seed, Elo and the Elo win probability, in the same tournament and player columns. - A daily feed of new results.
sackmannFile: "new-results"returns only the matches that finished since your last run, each one once, usually complete with statistics and Elo: schedule it and append the rows to your file. - See it live. The size of the database, the ranking weeks behind the rank columns and the Elo leaders of both tours: crawlplant.com/tennis-match-dataset.
What can you use it for?
- Prediction and betting models trained on the same columns as the best-known open tennis dataset, kept current.
- Research and journalism: season-by-season results with rankings, seeds and serve statistics.
- Replacing a stale copy: refresh your atp_matches / wta_matches tables weekly with one scheduled task.
- Daily predictions: score tomorrow's matches with your model from rank, seed, hand, height and Elo, then append the results as they come in.
- AI agents: structured match history as JSON or CSV.
Quick start
- Click Try for free with the default input (the first 1,000 matches of the 2025 ATP season).
- Set Years and Tours, and Max results above the season size (ATP about 4,300 matches, WTA about 3,800).
- Export the dataset as CSV: the columns come in his order.
Copy to your AI assistant
Paste this into ChatGPT, Claude or any agent so it knows how to use the Actor:
crawlplant/tennis-match-dataset on Apify: ATP / WTA / Challenger / ITF singles results in the columns of Jeff Sackmann'satp_matches_YYYY.csv (tourney_id, tourney_name, surface, draw_size, tourney_level, tourney_date, match_num, winner_id,winner_seed, winner_entry, winner_name, winner_hand, winner_ht, winner_ioc, winner_age, loser_*, score, best_of, round,minutes, w_ace ... l_bpFaced, winner_rank, winner_rank_points, loser_rank, loser_rank_points) + match_id, tour,winner_elo, loser_elo. From 1990, updated hourly. Input: years (e.g. [2024, 2025]), tours (atp, wta, challenger-men,challenger-women, itf-men, itf-women), dateFrom / dateTo (when years is empty), maxItems (default 1000),sackmannFile (matches = played matches; upcoming = today's and tomorrow's scheduled singles with p1_ / p2_ columns, Eloand p1_win_probability; new-results = only the matches finished since the last run, each once).Price: $1.00 per 1,000 matches on the Free plan.
Ready-to-use examples
1. A full ATP season
{ "years": [2025], "tours": ["atp"], "maxItems": 5000 }
2. Three WTA seasons
{ "years": [2023, 2024, 2025], "tours": ["wta"], "maxItems": 15000 }
3. This season so far, both tours
{ "years": [], "tours": ["atp", "wta"], "maxItems": 10000 }
4. The last 7 days, to keep your copy current
{ "years": [], "dateFrom": "-7", "dateTo": "today", "tours": ["atp", "wta"], "maxItems": 5000 }
5. Challenger season (his qual_chall file)
{ "years": [2025], "tours": ["challenger-men"], "maxItems": 20000 }
6. The 1990s, ATP
{ "years": [1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999], "tours": ["atp"], "maxItems": 40000 }
7. Today's and tomorrow's ATP and WTA matches with Elo win probabilities ($0.30 at most)
{ "sackmannFile": "upcoming", "tours": ["atp", "wta"], "maxItems": 300 }
8. Only the ATP and WTA results that are new since your last run: schedule it daily (about $0.10 a day, $1.00 at most; the first run returns today and the 10 days before)
{ "sackmannFile": "new-results", "tours": ["atp", "wta"], "maxItems": 1000 }
How to…
Replace Jeff Sackmann's tennis_atp and tennis_wta CSV files
Run one season per tour (example 1, then "tours": ["wta"]) and export as CSV. Code that reads his files by column name
works unchanged; keep the rows whose round doesn't start with "Q" for his main-draw-only files.
Keep a match dataset up to date every week
Save example 4 as a task and schedule it weekly: each run returns the last 7 days, and match_id lets you upsert
without duplicates.
Get tomorrow's matches and a daily results feed
Run example 7 each morning for the day's schedule: one row per match with p1_ / p2_ columns (id, seed, entry, name,
hand, height, country, age, rank, points), both players' Elo before the match, overall and on the surface, and
p1_win_probability. Run example 8 daily to collect what finished: each match comes once, usually complete with its
statistics and Elo the next day. Run it at least weekly for a gapless file.
Get ATP and WTA results with rankings for a model
Every row carries both players' rank and ranking points from the official list of that week, the seeds and entries of
the draw, and pre-match Elo (winner_elo, loser_elo).
Input options
| Option | Default | Description |
|---|---|---|
sackmannFile | matches | matches (played), upcoming (today and tomorrow), new-results (finished since your last run) |
years | [2025] | Seasons, from 1990; empty = the From / To days |
tours | atp | atp, wta, challenger-men, challenger-women, itf-men, itf-women; empty = ATP and WTA |
dateFrom / dateTo | this season / today | When years is empty: 2026-01-01, -7, today |
maxItems | 1000 | Maximum matches in total |
Example output
The 2025 Hong Kong final, a real row:
{"tourney_id": "2024-C8wqzbIc","tourney_name": "Hong Kong","surface": "Hard","draw_size": 16,"tourney_level": "A","tourney_date": 20241230,"match_num": 15,"winner_id": "nLLdS9q0","winner_seed": null,"winner_entry": null,"winner_name": "Alexandre Muller","winner_hand": "R","winner_ht": 183,"winner_ioc": "FRA","winner_age": 27.9,"loser_id": "YNkOjUIB","loser_seed": null,"loser_entry": "WC","loser_name": "Kei Nishikori","loser_hand": "R","loser_ht": 178,"loser_ioc": "JPN","loser_age": 35,"score": "2-6 6-1 6-3","best_of": 3,"round": "F","minutes": 104,"w_ace": 2, "w_df": 1, "w_svpt": 77, "w_1stIn": 60, "w_1stWon": 44, "w_2ndWon": 7, "w_SvGms": 12, "w_bpSaved": 4, "w_bpFaced": 6,"l_ace": 4, "l_df": 1, "l_svpt": 75, "l_1stIn": 48, "l_1stWon": 28, "l_2ndWon": 14, "l_SvGms": 12, "l_bpSaved": 4, "l_bpFaced": 8,"winner_rank": 67,"winner_rank_points": 778,"loser_rank": 106,"loser_rank_points": 578,"match_id": "C032DjD6","tour": "atp","winner_elo": 2110,"loser_elo": 2259}
Output fields
His columns, with these conventions:
- Player ids (
winner_id,loser_id) andtourney_iduse Flashscore's ids (strings);match_idis Flashscore's match id. tourney_dateis 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 / Billie Jean King Cup, A other tour level (WTA 1000 included), C Challenger, S ITF.- Qualifying rounds are in the same rows (
roundQ1-Q3);draw_sizeis counted from the main-draw matches played. - Serve columns: ATP and WTA matches from 2012; earlier seasons have results, ranks, seeds, hand, height and age.
- Extra columns:
match_id,tour,winner_elo,loser_elo, thenscrapedAt,source,store. - New results (
new-results) have the same columns as played matches. - Upcoming matches (
upcoming) usep1_/p2_in place of winner and loser (as Flashscore lists the players):tourney_id,tourney_name,surface,draw_size,tourney_level,tourney_date,match_id,tour,round,start_time, thenp1_id,p1_seed,p1_entry,p1_name,p1_hand,p1_ht,p1_ioc,p1_age,p1_rank,p1_rank_pointsand the same forp2_, thenp1_elo,p2_elo,p1_elo_surface,p2_elo_surfaceandp1_win_probability(Elo, overall and on the surface blended).
How much does an ATP and WTA match dataset cost?
Pay per result: platform usage is included.
| Event | No discount (Free plan) | Bronze (Starter) | Silver (Scale) | Gold (Business) |
|---|---|---|---|---|
| Match: played, new result or upcoming (per 1,000) | $1.00 | $0.90 | $0.80 | $0.70 |
| Actor start (per run) | $0.00005 | $0.00005 | $0.00005 | $0.00005 |
| Example on the Free plan | Matches | Cost |
|---|---|---|
| Default run: 1,000 matches of the 2025 ATP season | 1,000 | ~$1.00 |
| The full 2025 ATP season with qualifying | 4,285 | ~$4.30 |
| The 1990 ATP season | 3,580 | ~$3.58 |
| Last 7 days, ATP and WTA (week to 2026-10-02) | 193 | ~$0.19 |
| Today's and tomorrow's matches, ATP and WTA (example 7) | up to 300 | $0.30 at most |
| A day of new results, ATP and WTA (example 8) | about 100 | ~$0.10 |
Set a maximum cost per run in the run options to stop a large run at your budget.
Reliability
- Rows come from our tennis database (more than 900,000 matches, updated every hour, ranks and player profiles from the official ATP and WTA sources): a season comes back in seconds, nothing is scraped during your run.
- Each run writes a summary to the key-value store (
OUTPUT) with the rows saved and any warnings.
Run it through the API
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('crawlplant/tennis-match-dataset').call({ years: [2025], tours: ['atp'], maxItems: 5000 });// the dataset as CSV, columns in Sackmann's orderconst csv = await client.dataset(run.defaultDatasetId).downloadItems('csv');
Python:
import pandas as pdfrom apify_client import ApifyClientclient = ApifyClient("YOUR_TOKEN")run = client.actor("crawlplant/tennis-match-dataset").call(run_input={"years": [2025], "tours": ["wta"], "maxItems": 5000})df = pd.DataFrame(client.dataset(run["defaultDatasetId"]).list_items().items)
Use with AI agents
The Actor works as a tool in the Apify MCP server for Claude, ChatGPT, Cursor and others:
https://mcp.apify.com?tools=crawlplant/tennis-match-dataset
Try "which players won the most tiebreaks on clay this season?".
Use it when you need whole seasons of singles results in Jeff Sackmann's CSV columns, from 1990 to this week, or a weekly refresh of your own copy.
Not for bookmaker odds or live scores (use the Flashscore Tennis Scraper).
More tennis data
- Flashscore Tennis Scraper: odds from about 20 bookmakers, head-to-head, form, live scores, rankings, player statistics and Elo lists.
- Tennis Match History: every match of one player's career.
- Tennis Point-by-Point Data: every game and point of matches back to 2012.
FAQ
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, ITF from 2011. Serve statistics from 2012.
Is it legal?
The data is public sporting results and official rankings, read without logging in. How you use and publish them is your responsibility, so check the sources' terms for your use case.
Questions, a missing field or a source you need? Open an issue on this Actor: we reply within a day. If it saved you time, a short review helps others find it.
Privacy
The data is about professional players' public sporting results and profiles (names, countries, ages, hand, height). Each run sends the developer anonymous feature-usage statistics (the options used); your Apify account id is replaced by a one-way hash.