ATP & WTA Match Dataset - Sackmann CSV Format avatar

ATP & WTA Match Dataset - Sackmann CSV Format

Pricing

Pay per event

Go to Apify Store
ATP & WTA Match Dataset - Sackmann CSV Format

ATP & WTA 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

Pay per event

Rating

0.0

(0)

Developer

CrawlPlant

CrawlPlant

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

an hour ago

Last modified

Categories

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_elo and loser_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.
  • 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.
  • AI agents: structured match history as JSON or CSV.

Quick start

  1. Click Try for free with the default input (the first 1,000 matches of the 2025 ATP season).
  2. Set Years and Tours, and Max results above the season size (ATP about 4,300 matches, WTA about 3,800).
  3. 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's
atp_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).
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 }

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 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

OptionDefaultDescription
years[2025]Seasons, from 1990; empty = the From / To days
toursatpatp, wta, challenger-men, challenger-women, itf-men, itf-women; empty = ATP and WTA
dateFrom / dateTothis season / todayWhen years is empty: 2026-01-01, -7, today
maxItems1000Maximum 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) and tourney_id use Flashscore's ids (strings); 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 / Billie Jean King Cup, A other tour level (WTA 1000 included), C Challenger, S ITF.
  • Qualifying rounds are in the same rows (round Q1-Q3); draw_size is 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, then scrapedAt, source, store.

Pricing

Pay per result: platform usage is included.

EventNo discount (Free plan)Bronze (Starter)Silver (Scale)Gold (Business)
Match (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 planMatchesCost
Default run: 1,000 matches of the 2025 ATP season1,000~$1.00
The full 2025 ATP season with qualifying4,285~$4.30
The 1990 ATP season3,580~$3.58
Last 7 days, ATP and WTA (week to 2026-10-02)193~$0.19

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 order
const csv = await client.dataset(run.defaultDatasetId).downloadItems('csv');

Python:

import pandas as pd
from apify_client import ApifyClient
client = 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?".

More tennis data

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.

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.

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.