Flashscore Tennis Scraper - Live Scores, Stats, H2H & Odds avatar

Flashscore Tennis Scraper - Live Scores, Stats, H2H & Odds

Pricing

$1.00 / 1,000 tennis row delivereds

Go to Apify Store
Flashscore Tennis Scraper - Live Scores, Stats, H2H & Odds

Flashscore Tennis Scraper - Live Scores, Stats, H2H & Odds

Scrape ATP, WTA, Challenger and ITF tennis from Flashscore: results, fixtures and live scores with set by set scores, tiebreaks and the current game score. Both doubles players are identified. Switch modes for statistics, head to head history or bookmaker odds. No proxy needed.

Pricing

$1.00 / 1,000 tennis row delivereds

Rating

0.0

(0)

Developer

Sourabh Kumar

Sourabh Kumar

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

3

Monthly active users

2 days ago

Last modified

Share

Flashscore tennis scraper: scores, statistics, head to head and odds

Pull tennis results and fixtures from Flashscore with set by set scores and tiebreaks. Switch modes to add 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.
  • ๐ŸŽพ Four modes in one actor. Scores, statistics, head to head and odds usually mean four separate scrapers, each billing you separately.
  • ๐Ÿ‘ฅ 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 250 row pull finishes in about 13 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
๐Ÿค 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 }

๐Ÿ“Š 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

  1. Create a free Apify account. Takes 30 seconds, no card needed.
  2. Open Flashscore Tennis Scraper in the Apify Console.
  3. Pick a mode, then set a date range and any filters you want. Leave the dates empty for today.
  4. Click Start. Most runs finish in under 15 seconds.
  5. 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 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
}
FieldTypeDefaultNotes
modestringmatchesmatches, statistics, h2h or odds
startUrlsarraynoneFlashscore tournament addresses. Keeps only matches from those tournaments
dayOffsetsarraynoneIndividual days from -7 to 1. Replaces the date range, and they need not be consecutive
dateFrom / dateTostringtodayYYYY-MM-DD. Flashscore serves 7 days back through tomorrow
toursarrayallATP, WTA, CHALLENGER, ITF_MEN, ITF_WOMEN, JUNIORS, TEAMS
drawTypestringallsingles or doubles
surfacesarrayallhard, clay, grass, carpet
statusesarrayallscheduled, live, finished
tournamentQueryarraynoneKeep tournaments whose name contains any one of these
matchIdsarraynoneScrape exact match IDs and ignore every filter above
maxItemsinteger100Your cost ceiling, since you pay per row
oddsCountrystringGBGB, BR, US, DE or IN. Odds mode only
oddsBetTypesarrayHOME_AWAYAlso OVER_UNDER, ASIAN_HANDICAP, CORRECT_SCORE, ODD_OR_EVEN
oddsScopesarrayFULL_TIMEAlso FIRST_SET, SECOND_SET
h2hMaxPerSectioninteger10Past 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.

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.
  • ๐Ÿค– 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 countryId and 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 playerId and profile slug are for the lead player only, and the three letter abbreviation is singles only.
  • Odds are pre-match, and statistics need a started match. Live in play pricing is not claimed, and scheduled matches have no statistics yet so they are skipped and never charged.

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.

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.