Tennis Point-by-Point Data - Every Game & Point
Pricing
Pay per event
Tennis Point-by-Point Data - Every Game & Point
Point-by-point data of ATP, WTA, Challenger and ITF matches: every game with its server, the points in order, breaks, and break, set and match points, plus the score, round and serve / return statistics. Any day back to 2012, any match, tournament or player. Works as an MCP tool for AI agents.
Pricing
Pay per event
Rating
0.0
(0)
Developer
CrawlPlant
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
an hour ago
Last modified
Share
Independent tool, not affiliated with, endorsed by or connected to Flashscore, Livesport, the ATP, the WTA or the ITF. It reads the public match data that flashscore.com shows to every visitor.
Every game and every point of a tennis match, for ATP, WTA, Challenger and ITF matches back to 2012: who served, the
score after each point (15:0, 30:0, 40:15...), who won the game, whether serve was broken, and how many break,
set and match points it had, tiebreaks point by point included. Ask for a day, a list of matches, a whole
tournament edition or a player's matches. Each row is one match with its score, round, duration, both players' Elo before
the match and serve / return statistics.
Why this one
- Any day, not just today. Matches from the last week are read live; anything older comes from our tennis database, which keeps point-by-point for more than 400,000 matches and is updated every hour.
- Whole tournaments in one run. Wimbledon 2024: 239 matches with qualifying, 237 of them point by point.
- Pressure points counted for you. Each game says how many break, set and match points it had, and whether serve was broken: no parsing of score strings.
- Tiebreaks point by point, in the same list as the games.
- Statistics in the same row: aces, double faults, 1st serve %, points won on 1st and 2nd serve, break points saved and converted, for the match and each set.
- Search the way you think: by day, by match URL, by tournament page, or by player name ("Alcaraz") with an opponent filter.
- See it live. How many matches the database has point by point and today's ATP and WTA singles, from the same database your runs read: crawlplant.com/tennis-point-by-point.
What can you use it for?
- Momentum and pressure models: break points saved, serve holds under pressure, comebacks within a set.
- In-play betting research: how often a player holds after being 0:30 down, or wins a tiebreak after a mini-break.
- Match visualisations and apps: game-by-game charts of any match.
- Coaching and analysis: a player's serve games in finals or against one rival.
Quick start
- Click Try for free with the default input (20 of yesterday's finished ATP and WTA matches).
- Pick a Mode: a day range, match URLs, tournament pages or players.
- Download as JSON (the
pointByPointlist keeps its structure) or open the table view.
Copy to your AI assistant
Paste this into ChatGPT, Claude or any agent so it knows how to use the Actor:
crawlplant/tennis-point-by-point on Apify: every game and point of tennis matches (ATP, WTA, Challenger, ITF, from 2012).Input: mode (matches = days dateFrom..dateTo like "yesterday", "2024-07-14", "-3"; matchIds = Flashscore match ids or URLs;tournaments = tournamentUrls + years; players = playerUrls names), tours (default atp, wta), matchType, status (defaultfinished), tournaments / players (name contains filters), includeStatistics, maxItems (default 20).Row: one match (date, tournament, round, player1Name, player2Name, score, winnerName, durationMinutes, Elo, statistics)with pointByPoint: [{ set, game, server, winner, breakOfServe, points: ["15:0", ...], breakPoints, setPoints, matchPoints,gamesPlayer1, gamesPlayer2, tiebreak }]. Price: $1.00 per 1,000 matches + $2.00 per 1,000 with point-by-point (Free plan).
Ready-to-use examples
1. Yesterday's ATP and WTA matches
{ "mode": "matches", "dateFrom": "yesterday", "tours": ["atp", "wta"], "maxItems": 200 }
2. One match by its URL
{ "mode": "matchIds", "matchIds": ["https://www.flashscore.com/match/Sf0bExdB/"] }
3. A whole tournament edition
{ "mode": "tournaments", "tournamentUrls": ["https://www.flashscore.com/tennis/atp-singles/wimbledon/"], "years": [2024], "maxItems": 300 }
4. Every meeting of two rivals, point by point
{ "mode": "players", "playerUrls": ["Carlos Alcaraz"], "players": ["Djokovic"] }
5. A week of WTA matches
{ "mode": "matches", "dateFrom": "-7", "dateTo": "yesterday", "tours": ["wta"], "maxItems": 1000 }
6. Matches in play right now, points so far
{ "mode": "matches", "dateFrom": "today", "status": "live", "tours": [] }
7. A past Grand Slam fortnight
{ "mode": "matches", "dateFrom": "2025-05-25", "dateTo": "2025-06-08", "tournaments": ["French Open"], "maxItems": 1000 }
How to…
Download point-by-point data of a tennis match
Paste the match URL from flashscore.com (example 2): the 8 characters after /match/ also work.
Get point-by-point for a whole tournament
Use the tournament's Flashscore page and the year (example 3). Qualifying matches come with the main draw;
tournamentStage is Qualification for them.
Find break points saved, set points and match points
Each game has breakPoints, setPoints and matchPoints (how many the game had) and breakOfServe (the server lost
it). In the 2024 Wimbledon final Alcaraz broke Djokovic in the first game at his fifth break point (breakPoints: 5),
and the last game is the tiebreak with matchPoints: 1.
Input options
| Option | Default | Description |
|---|---|---|
mode | matches | matches (days), matchIds, tournaments, players |
dateFrom / dateTo | yesterday / same day | matches mode: today, yesterday, 2024-07-14, -3 |
matchIds | [] | matchIds mode: match ids or URLs |
tournamentUrls / years | [] / latest | tournaments mode: Flashscore tournament pages and editions |
playerUrls | [] | players mode: names or Flashscore player URLs |
tours | atp, wta | Also challenger-men, challenger-women, itf-men, itf-women, teams, other; empty = all |
matchType | singles | singles, doubles, all |
status | finished | finished, live, all |
tournaments, players | [] | Tournament / player name contains |
includeStatistics | true | Serve and return statistics (included in the match price) |
maxItems | 20 | Maximum matches in total |
Example output
The 2024 Wimbledon final (shortened: the first game and the tiebreak of 29 games, no statistics or player objects):
{"recordType": "match","matchId": "Sf0bExdB","url": "https://www.flashscore.com/match/Sf0bExdB/","date": "2024-07-14","tour": "atp","tournament": "Wimbledon","round": "Final","surface": "grass","player1Name": "Alcaraz C.","player2Name": "Djokovic N.","player1Elo": 2538,"player2Elo": 2564,"winnerName": "Alcaraz C.","score": "6-2 6-2 7-6(4)","durationMinutes": 147,"pointByPoint": [{ "set": 1, "game": 1, "server": "player2", "winner": "player1", "breakOfServe": true, "gamesPlayer1": 1, "gamesPlayer2": 0,"points": ["15:0", "15:15", "30:15", "30:30", "30:40", "40:40", "A:40", "40:40", "40:A", "40:40", "A:40", "40:40", "40:A","40:40", "A:40", "40:40", "A:40", "40:40", "A:40"], "breakPoints": 5, "setPoints": 0, "matchPoints": 0 },{ "set": 3, "game": 13, "tiebreak": true, "server": "player2", "winner": "player1", "breakOfServe": false,"gamesPlayer1": 7, "gamesPlayer2": 6, "points": ["0:1", "1:1", "2:1", "3:1", "3:2", "3:3", "4:3", "5:3", "5:4", "6:4", "7:4"],"breakPoints": 0, "setPoints": 0, "matchPoints": 1 }],"source": "live"}
Output fields
| Field | Description |
|---|---|
matchId, url, date, startTime | Flashscore's match id and page, day (UTC) and start time |
tour, tournament, tournamentStage, round, surface | Where and when in the draw |
player1Name, player2Name, player1, player2 | Both sides with Flashscore ids, URLs and countries |
score, sets, winnerName, durationMinutes | Result and length |
player1Elo, player2Elo, player1EloWinProbability | Elo before the match |
statistics | Serve and return statistics for the match and each set |
pointByPoint[] | One entry per game: set, game, server, winner, breakOfServe, gamesPlayer1 / gamesPlayer2 after it, points (the game score after each point, player1:player2), breakPoints, setPoints, matchPoints; a tiebreak has tiebreak: true and the tiebreak score after each point |
scrapedAt, source | When the run read it; cache = our tennis database, live = read from Flashscore in the run |
Pricing
Pay per result: platform usage is included. A match row, plus point-by-point when the match has it.
| Event | No discount (Free plan) | Bronze (Starter) | Silver (Scale) | Gold (Business) |
|---|---|---|---|---|
| Match (per 1,000) | $1.00 | $0.90 | $0.80 | $0.70 |
| Point-by-point, per match that has it (per 1,000) | $2.00 | $1.80 | $1.60 | $1.40 |
| Actor start (per run) | $0.00005 | $0.00005 | $0.00005 | $0.00005 |
| Example on the Free plan | Matches | Cost |
|---|---|---|
| Default run: 20 of yesterday's matches | 20 | ~$0.06 |
| One match | 1 | ~$0.003 |
| Wimbledon 2024, every match with qualifying | 239 | ~$0.71 |
| A week of WTA tour matches (2026-09-24 to 2026-10-01) | 88 | ~$0.26 |
| Roland Garros 2025, men's and women's singles | 254 | ~$0.76 |
Set a maximum cost per run in the run options to stop a large run at your budget.
Reliability
- Matches older than a week come from our tennis database (updated every hour), so a big historical run doesn't depend on thousands of live requests.
- Each live request that fails is retried; a match whose point-by-point still can't be read keeps every other field and is not charged for point-by-point.
- The run stops starting new requests shortly before its time limit and saves what it has.
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-point-by-point').call({ mode: 'matchIds', matchIds: ['Sf0bExdB'] });const [match] = (await client.dataset(run.defaultDatasetId).listItems()).items;console.log(match.pointByPoint.filter((g) => g.breakOfServe).map((g) => `set ${g.set} game ${g.game}`));
Python:
from apify_client import ApifyClientclient = ApifyClient("YOUR_TOKEN")run = client.actor("crawlplant/tennis-point-by-point").call(run_input={"dateFrom": "yesterday", "maxItems": 100})for m in client.dataset(run["defaultDatasetId"]).iterate_items():breaks = sum(g["breakOfServe"] for g in m.get("pointByPoint", []))print(m["player1Name"], m["player2Name"], m["score"], breaks, "breaks")
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-point-by-point
Try "how many break points did Alcaraz save in the 2024 Wimbledon final?".
More tennis data
- Flashscore Tennis Scraper: odds from about 20 bookmakers, head-to-head, form, rankings, player statistics and Elo lists.
- Tennis Match History: every match of a player's career.
- ATP & WTA Match Dataset: whole seasons in Jeff Sackmann's CSV columns.
FAQ
How far back does point-by-point go?
To 2012 for ATP and WTA matches; Flashscore has none before that. Recent seasons cover almost every tour-level match.
Is it live during a match?
Yes: status: "live" (example 6) returns the games and points played so far.
Is it legal?
The data is public sporting results read without logging in, at a polite pace. How you use and publish them is your responsibility, so check the source's terms for your use case.
Privacy
The data is about professional players' public sporting results. Each run sends the developer anonymous feature-usage statistics (the options used, never the matches you asked for); your Apify account id is replaced by a one-way hash.