Flashscore Tennis Scraper - Live Scores, Point-by-Point, Odds
Pricing
$1.00 / 1,000 tennis row delivereds
Flashscore Tennis Scraper - Live Scores, Point-by-Point, Odds
Scrape ATP, WTA, Challenger and ITF tennis from Flashscore: results, fixtures and live scores with set by set scores and tiebreaks. Switch modes for point-by-point of every game, match statistics, head to head history or bookmaker odds. Both doubles players identified. No proxy needed.
Pricing
$1.00 / 1,000 tennis row delivereds
Rating
0.0
(0)
Developer
Sourabh Kumar
Maintained by CommunityActor stats
0
Bookmarked
30
Total users
19
Monthly active users
18 days ago
Last modified
Categories
Share
Flashscore tennis scraper: scores, point-by-point, statistics, h2h & odds
Pull tennis results and fixtures from Flashscore with set by set scores and tiebreaks. Switch modes for every point of a match, match statistics, head to head history, or bookmaker odds with the opening price and how far it has moved.
$1 per 1,000 results. No per-run fee. Every mode, one flat price.
Covers ATP, WTA, Challenger, ITF men and women, juniors, and team events like the Davis Cup.
Why this scraper?
- π΅ $1 per 1,000 rows with no per-run fee, so a run that returns nothing costs you nothing.
- πΎ Five modes in one actor. Scores, point-by-point, statistics, head to head and odds usually mean five separate scrapers, each billing you separately.
- π― Every point of a match, in play order, with break points, set points and match points flagged, plus who served and who won each game.
- π₯ Both doubles players, fully identified with their own ID, nationality and photo, so a mixed nationality pair is not flattened into one country.
- π΄ Live game score and who is serving on in play matches, not just the set scores.
- β οΈ Walkovers, withdrawals and retirements are flagged separately, so a 6-0 6-0 that never happened does not pollute your results.
- π Odds carry the opening price and the movement, not just today's number, so you can see which way a line drifted.
- π Read any country's bookmakers from one run. Great Britain returns up to 20, Brazil the widest Latin American set. No proxy setup, no VPN.
- β‘ Fast and cheap to run. Plain HTTP with no browser, so a full day of results lands in seconds.
- π― Filter before you pay. Narrow by tournament URL, tour, draw, surface, status or specific days, and matches with nothing published are skipped and never billed.
What data can you extract?
| ποΈ Tournament and surface | π Tournament URL | π Start time (UTC) | π Set by set scores |
| π₯ Winner | π’ Tiebreak points | π΄ Live game score | πΎ Who is serving |
| π Player nationality | π Player IDs and slugs | π₯ Both doubles players | πΌοΈ Player photos |
| β οΈ Walkovers, withdrawals, retirements | π― Aces and double faults | πΎ Break points won and saved | π₯ Winners and unforced errors |
| π― Every point in play order | π© Break, set and match points | π Server and winner per game | π Tiebreaks point by point |
| π€ Head to head record | π Recent form both sides | π° Bookmaker odds | π Opening price and drift |
Scraping modes
πΎ Matches (default)
Fixtures and results for a date range, with set by set scores, tiebreaks, winner, nationality and tournament detail. Live matches also carry the current game score and the server.
{ "mode": "matches", "dateFrom": "2026-08-12", "dateTo": "2026-08-13", "tours": ["ATP", "WTA"], "drawType": "singles", "maxItems": 200 }
Point it at a tournament instead of a date range by pasting its Flashscore address:
{ "mode": "matches", "startUrls": ["https://www.flashscore.com/tennis/atp-singles/cincinnati/"], "maxItems": 200 }
Or pick individual days, which do not have to be next to each other:
{ "mode": "matches", "dayOffsets": ["0", "1"], "maxItems": 200 }
π― Point-by-point
Every point of a match in the order it was played, grouped into sets and games. Each game carries who served, who won it and whether it was a break. Each point carries the running score and whether it was a break point, a set point or a match point. Tiebreaks come through point by point, including the deciding set match tiebreak that doubles uses.
{ "mode": "pointByPoint", "dayOffsets": ["-1"], "tours": ["ATP", "WTA"], "maxItems": 50 }
Live matches are included and carry the game being played right now, so you can follow a match point by point while it happens.
π Statistics
Twenty statistics per match and per set: aces, double faults, first serve percentage, break points saved and converted, winners, unforced errors, service and return points won.
{ "mode": "statistics", "tours": ["ATP", "WTA"], "statuses": ["finished"], "maxItems": 50 }
π€ Head to head
Past meetings between the two players plus recent form for each side. Trim how much history you keep with h2hMaxPerSection.
{ "mode": "h2h", "tours": ["ATP"], "h2hMaxPerSection": 10, "maxItems": 25 }
π° Odds
Bookmaker prices for each match, with the opening price, the current price and the direction it moved. Pick the market with oddsCountry.
{ "mode": "odds", "oddsCountry": "GB", "oddsBetTypes": ["HOME_AWAY", "OVER_UNDER"], "oddsScopes": ["FULL_TIME"], "maxItems": 50 }
How to scrape Flashscore tennis: step by step
- Create a free Apify account. Takes 30 seconds, no card needed.
- Open Flashscore Tennis Scraper in the Apify Console.
- Pick a mode, then set a date range and any filters you want. Leave the dates empty for today.
- Click Start. Most runs finish in seconds.
- Export as JSON, CSV, or Excel, or fetch it from the API.
How much does Flashscore Tennis Scraper cost?
You pay $1.00 per 1,000 rows, and there is no per-run fee. The Apify Free plan gives you $5 in usage credits a month, which is roughly 5,000 rows. The $29/month Starter plan covers about 29,000 rows a month.
Rows are only charged when they are delivered. If a match has no point-by-point, no statistics or no odds published, it is skipped and you are not billed for it.
Input
{"mode": "matches","dateFrom": "2026-08-12","dateTo": "2026-08-13","tours": ["ATP", "WTA"],"drawType": "singles","surfaces": ["hard"],"statuses": ["finished"],"tournamentQuery": ["Cincinnati", "Toronto"],"maxItems": 200}
| Field | Type | Default | Notes |
|---|---|---|---|
mode | string | matches | matches, pointByPoint, statistics, h2h or odds |
startUrls | array | none | Flashscore tournament addresses. Keeps only matches from those tournaments |
dayOffsets | array | none | Individual days from -7 to 1. Replaces the date range, and they need not be consecutive |
dateFrom / dateTo | string | today | YYYY-MM-DD. Flashscore serves 7 days back through tomorrow |
tours | array | all | ATP, WTA, CHALLENGER, ITF_MEN, ITF_WOMEN, JUNIORS, TEAMS |
drawType | string | all | singles or doubles |
surfaces | array | all | hard, clay, grass, carpet |
statuses | array | all | scheduled, live, finished |
tournamentQuery | array | none | Keep tournaments whose name contains any one of these |
matchIds | array | none | Scrape exact match IDs and ignore every filter above |
maxItems | integer | 100 | Your cost ceiling, since you pay per row |
oddsCountry | string | GB | GB, BR, US, DE or IN. Odds mode only |
oddsBetTypes | array | HOME_AWAY | Also OVER_UNDER, ASIAN_HANDICAP, CORRECT_SCORE, ODD_OR_EVEN |
oddsScopes | array | FULL_TIME | Also FIRST_SET, SECOND_SET |
h2hMaxPerSection | integer | 10 | Past matches kept per section. H2H mode only |
How the filters combine. Entries inside one filter are an "any of" list, and separate filters all have to be satisfied. So two tournament URLs return matches from either one, but adding statuses: ["finished"] on top keeps only the finished ones. Note that Flashscore gives singles and doubles separate addresses, so a .../atp-singles/... URL returns no doubles.
Already have match IDs from an earlier run? Pass them straight in:
{ "mode": "odds", "matchIds": ["fqlRb8xp", "YT1HRITp"], "oddsCountry": "GB" }
Output
Matches
{"matchId": "fqlRb8xp","url": "https://www.flashscore.com/match/fqlRb8xp/","matchType": "singles","startTimestamp": 1786572600,"startTime": "2026-08-12T22:10:00.000Z","endTimestamp": 1786580150,"endTime": "2026-08-13T00:15:50.000Z","status": "finished","statusDetailCode": 3,"note": null,"isWalkover": false,"isWithdrawn": false,"isRetired": false,"endedEarly": false,"winner": "away","isInPlay": false,"currentGameScoreHome": null,"currentGameScoreAway": null,"server": null,"homePlayer": {"name": "Jodar R.","names": ["Jodar R."],"players": [{"name": "Jodar R.","participantId": "OdngshVK","playerId": "voyKqlqS","slug": "jodar-rafael","country": "Spain","countryId": 176,"imageUrl": "https://static.flashscore.com/res/image/data/zqkYjime-bJuw1oYE.png"}],"playerId": "voyKqlqS","participantId": "OdngshVK","participantId2": null,"slug": "jodar-rafael","abbreviation": "JOD","country": "Spain","countryId": 176,"imageUrl": "https://static.flashscore.com/res/image/data/zqkYjime-bJuw1oYE.png"},"awayPlayer": {"name": "Nakashima B.","names": ["Nakashima B."],"players": [{"name": "Nakashima B.","participantId": "ETGnbrpH","playerId": "80RkvS6k","slug": "nakashima-brandon","country": "USA","countryId": 200,"imageUrl": "https://static.flashscore.com/res/image/data/Ao55Oc7k-I3vxtblK.png"}],"playerId": "80RkvS6k","participantId": "ETGnbrpH","participantId2": null,"slug": "nakashima-brandon","abbreviation": "NAK","country": "USA","countryId": 200,"imageUrl": "https://static.flashscore.com/res/image/data/Ao55Oc7k-I3vxtblK.png"},"homeSetsWon": 0,"awaySetsWon": 2,"setsPlayed": 2,"sets": [{"set": 1,"home": 6,"away": 7,"homeTiebreak": 3,"awayTiebreak": 7},{"set": 2,"home": 4,"away": 6,"homeTiebreak": null,"awayTiebreak": null}],"scoreSummary": "6-7(3), 4-6","tournament": {"tournamentId": "IyRQC2vM","stageId": "jakzJP44","name": "Montreal","fullName": "ATP - SINGLES: Montreal (Canada), hard","tour": "ATP","tourLabel": "ATP - Singles","drawType": "singles","surface": "hard","country": "Canada","isQualification": false,"urlPath": "/tennis/atp-singles/montreal/","url": "https://www.flashscore.com/tennis/atp-singles/montreal/"},"scrapedAt": "2026-08-13T15:08:57.755Z"}
A doubles pair, with each player separated out. Marcelo Arevalo is Salvadoran and Mate Pavic is Croatian, so a single country on the row would be wrong for one of them:
{"matchId": "IarlCOB7","matchType": "doubles","homePlayer": {"name": "Arevalo M./Pavic M.","names": ["Arevalo M.", "Pavic M."],"players": [{ "name": "Arevalo M.", "participantId": "2Dnk4gai", "playerId": "8IxTwFIq", "slug": "arevalo-marcelo", "country": "El Salvador", "countryId": 70, "imageUrl": "https://static.flashscore.com/res/image/data/ClGancWH-jc6XgREf.png" },{ "name": "Pavic M.", "participantId": "zLNFemL9", "playerId": null, "slug": null, "country": "Croatia", "countryId": 59, "imageUrl": "https://static.flashscore.com/res/image/data/buhflOiT-OhNpdMM4.png" }],"participantId": "2Dnk4gai","participantId2": "zLNFemL9"}}
A live match, with the game score and the server:
{"matchId": "AN06zHRi","status": "live","isInPlay": true,"scoreSummary": "3-6, 7-6(5), 5-4","currentGameScoreHome": "0","currentGameScoreAway": "0","server": "away","endTime": null}
The game score is text, not a number: it is 0, 15, 30, 40 or A for advantage during a normal game, and a plain point count during a tiebreak.
Point-by-point. One row per match, with sets containing games and games containing points. Trimmed here to one game and one tiebreak point:
{"matchId": "KjZnPKTb","matchType": "singles","homePlayer": "Milavsky D.","awayPlayer": "Harris L.","setsPlayed": 3,"gameCount": 30,"pointCount": 157,"breakCount": 3,"miniBreakCount": 7,"sets": [{"set": 1,"label": "Set 1","homeGames": 7,"awayGames": 6,"hasTiebreak": true,"tiebreakHome": 8,"tiebreakAway": 6,"gameCount": 12,"games": [{"gameNo": 9,"server": "home","winner": "home","isBreak": false,"homeGames": 5,"awayGames": 4,"isInProgress": false,"isAbandoned": false,"pointCount": 9,"breakPointCount": 2,"points": [{ "pointNo": 4, "score": "30:30", "home": "30", "away": "30", "isBreakPoint": false, "isSetPoint": false, "isMatchPoint": false },{ "pointNo": 5, "score": "30:40", "home": "30", "away": "40", "isBreakPoint": true, "isSetPoint": false, "isMatchPoint": false }]}],"tiebreakPoints": [{ "pointNo": 1, "server": "home", "winner": "away", "home": 0, "away": 1, "isMiniBreak": true }]}]}
breakCount counts service breaks. Tiebreak points won against the serve are counted separately as miniBreakCount, so a break total stays comparable with every other tennis source.
Statistics
{"matchId": "fVjaLWSG","homePlayer": "Giron M.","awayPlayer": "Rocha H.","periods": ["Match", "Set 1", "Set 2"],"statisticsCount": 49,"statistics": [{ "period": "Match", "group": "Service", "stat": "Aces", "home": "2", "away": "5" },{ "period": "Match", "group": "Service", "stat": "1st serve percentage", "home": "52%", "away": "68%" },{ "period": "Match", "group": "Return", "stat": "Break Points Converted", "home": "2/8", "away": "3/9" }]}
Head to head
{"matchId": "C8MVcxVh","homePlayer": "Mejia N.","awayPlayer": "Fearnley J.","tournamentName": "Cincinnati","headToHeadCount": 1,"headToHead": [{"matchId": "C8MVcxVh","date": "2026-08-12T22:30:00.000Z","tournament": "Cincinnati","surface": "hard","homePlayer": "Mejia N.","awayPlayer": "Fearnley J.","score": "2:1","homeSetsWon": 2,"awaySetsWon": 1,"winner": "home"}],"homeRecentForm": [{ "date": "2026-08-12T22:30:00.000Z", "tournament": "Cincinnati", "score": "2:1", "winner": "home", "resultForSectionPlayer": "w" }],"awayRecentForm": [{ "date": "2026-08-12T22:30:00.000Z", "tournament": "Cincinnati", "score": "2:1", "winner": "home", "resultForSectionPlayer": "l" }]}
Odds
{"matchId": "YT1HRITp","homePlayer": "Siniakova K./Zhang S.","awayPlayer": "Mihalikova T./Nicholls O.","oddsCountry": "GB","bookmakerCount": 20,"offerCount": 74,"odds": [{"bookmakerId": 15,"bookmakerName": "William Hill","betType": "HOME_AWAY","betScope": "FULL_TIME","side": "home","playerName": "Siniakova K./Zhang S.","opening": "1.4","current": "1.22","movement": "down"}]}
Use cases
- π Model building and backtesting. Pull results with set by set detail to train or check a match prediction model.
- π Line movement tracking. Compare the opening price against the current one across 20 bookmakers to spot where money went.
- π Bookmaker comparison. See which book is offering the best price on the same match in Britain, Brazil, Germany, the US or India.
- π° Live scoreboards and content. Feed a site, newsletter or bot with fixtures and results across every tour.
- πΎ Player form research. Combine head to head history with recent form to preview a matchup.
- π Serve and return analysis. Use the per set statistics to break down where a match was won.
- π― Momentum and pressure research. Point-by-point shows how a player does on break points, and where a set actually turned.
- π Tiebreak studies. Every tiebreak arrives point by point, including the deciding set match tiebreak that doubles uses.
- π€ Fantasy and prediction games. Score entries against real results without maintaining a scraper yourself.
- ποΈ Building a results archive. Run daily to accumulate history well past the nine day window Flashscore itself serves.
Limitations
- Nine day window. Flashscore publishes 7 days of past results plus today and tomorrow, so run daily if you want a longer archive.
- Three things Flashscore does not publish for tennis: player rankings, round name, and best of three or five. A "ranking" field on another scraper whose value repeats across unrelated players from the same country is the country ID, which this actor names
countryIdand never calls a rank. - No match duration, and it is not guessable. The only timestamps in the source are the scheduled start and a marker for the end of the last completed set, so a match that starts two hours late would look two hours longer than it was. This actor ships neither a duration nor a guess.
- End time only on finished matches. It is null while a match is in play, and absent on some finished lower tier matches where Flashscore never recorded it.
- Doubles pairs carry one player ID. Both players get a name, participant ID, nationality and photo; the longer
playerIdand profileslugare for the lead player only, and the three letter abbreviation is singles only. - Odds are pre-match. Statistics and point-by-point need a started match. Live in play pricing is not claimed, and scheduled matches have nothing published yet so they are skipped and never charged.
- The point that wins a game is not published. Flashscore lists the score after each point and stops at the last one that left the game unfinished, so a hold to love reads
15:0, 30:0, 40:0. A point flagged as a break, set or match point is therefore an opportunity, and whether it was converted is answered by the game'swinnerrather than by the points list. - No server on a game in progress during a tiebreak. Serve rotation inside a breaker is not published for the point being played, so that one field stays empty until the tiebreak ends.
FAQ
How much does Flashscore Tennis Scraper cost?
It uses pay-per-result pricing. You pay $1.00 for 1,000 results and there is no per-run fee. The Apify Free plan gives you $5 in usage credits a month, enough for around 5,000 results. If you run regularly, the $29/month Starter plan covers about 29,000 results.
No subscription lock-in. Pause whenever.
Is it legal to scrape Flashscore?
Scraping public data is generally allowed in the US and most of the EU, as long as you don't collect personal data covered by GDPR or CCPA without a lawful basis. This actor only touches publicly accessible pages, but how you use the output is on you.
Apify's full breakdown: Is web scraping legal?.
Can I integrate it with other tools?
Push results into Make, Zapier, Slack, Airbyte, GitHub, Google Sheets, Google Drive, and more. Apify treats every actor as a webhook source, so anything that consumes webhooks or pulls from an API works.
Full list: Apify integrations.
Can I use it with the Apify API?
Yes. Every run is available via the Apify REST API:
curl -X POST "https://api.apify.com/v2/acts/sourabhbgp~flashscore-tennis-scraper/runs?token=APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"mode": "matches", "tours": ["ATP"], "maxItems": 50}'
Docs: Apify API reference.
Can I use it through an MCP Server?
Yes. Apify ships an MCP server that exposes every actor as a tool, so Claude Desktop, Cursor, and any other MCP-capable client can call this scraper. Setup: Apify MCP docs.
Your feedback
Bug, missing field, or odd behavior? Drop a note in the Issues tab. Reports go to a human and fixes usually ship the same week.