# Flashscore Tennis Scraper - Live Scores & Results (`parsebird/flashscore-tennis-scraper`) Actor

Scrape tennis matches from Flashscore: live scores, results, and schedules across ATP, WTA, ITF, and Challenger tours. Get sets, players, rankings, tournaments, and surfaces. Export as JSON, CSV, or Excel.

- **URL**: https://apify.com/parsebird/flashscore-tennis-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Categories:** News, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 tennis matches

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Flashscore Tennis Scraper

Extract **tennis** live scores, results, and schedules from [Flashscore](https://www.flashscore.com) — ATP, WTA, ITF, and Challenger Tour matches — for any day from a week ago to a week ahead.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Pick any day (or range of days), filter by tour, tournament, or match status, and get set-by-set scores, player rankings, tournament surfaces, and rounds — reading Flashscore's own data feeds directly, no browser required.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
Actor: parsebird/flashscore-tennis-scraper — Scrape tennis matches from Flashscore: live scores, results, and schedules across ATP, WTA, ITF, and Challenger tours.
Usage: from apify_client import ApifyClient; client = ApifyClient("YOUR_TOKEN"); run = client.actor("parsebird/flashscore-tennis-scraper").call(run_input={"dayOffsets": ["-1"], "matchStatuses": ["finished"], "tours": ["atp"]})
Inputs: dayOffsets (array of strings "-7".."7", default ["0"]=today), matchStatuses (array: all|finished|live|scheduled, default ["all"]), tours (array: atp|wta|itf|challenger, default all), tournaments (array, case-insensitive partial name match), startUrls (array of Flashscore tournament/results URLs, overrides tournaments filter), maxItems (integer, optional cap)
Output fields: match_id, match_url, match_date, match_end_timestamp, match_status, match_type, result_type, winner, walkover_note, sets_won_home, sets_won_away, total_match_duration, sets (array of {home,away,duration,tiebreak_home,tiebreak_away}), home_players/away_players (array of {name,short_name,id,id2,slug,nationality,ranking,photo_url}), tournament_name, tournament_id, tournament_url, category_name, surface, round_name, current_server, current_game_score_home, current_game_score_away
API spec: https://apify.com/parsebird/flashscore-tennis-scraper/api
Get token: https://console.apify.com/account/integrations
```

### What does Flashscore Tennis Scraper do?

**Flashscore Tennis Scraper** reads [Flashscore's](https://www.flashscore.com) tennis data directly — the same feeds that power the live scoreboard — so it works as a **Flashscore tennis API alternative** without needing a browser or official API access.

Key capabilities:

- 📅 Fetch any single day or combine multiple days, from 7 days in the past to 7 days ahead
- 🎾 Full coverage across ATP, WTA, ITF, and ATP Challenger — singles and doubles
- 🔴 Live match snapshots with current server and current game score (0/15/30/40/Advantage)
- 🏆 Set-by-set scores, match duration, and winner for finished matches
- 👤 Player details on every match: name, short name, ranking, nationality, and photo
- 🏟️ Tournament name, category, surface, and round for every match
- 🔍 Filter by match status, tour, tournament name, or specific tournament URLs
- ⚡ Fast, lightweight scraping — no browser, no proxies required

### What data can you extract from Flashscore?

| Field | Description |
|-------|-------------|
| `match_id` / `match_url` | Flashscore match identifier and permalink |
| `match_date` / `match_end_timestamp` | Scheduled start and (for finished matches) end time |
| `match_status` | `FINISHED`, `LIVE`, `SCHEDULED`, `POSTPONED`, or `CANCELLED` |
| `match_type` | `singles` or `doubles` |
| `sets_won_home` / `sets_won_away` / `winner` | Final set count and winning side |
| `sets` | Set-by-set game scores |
| `home_players` / `away_players` | Player name, ranking, nationality, and photo (two entries for doubles) |
| `tournament_name` / `tournament_id` / `tournament_url` | Tournament identifiers and link |
| `category_name` / `surface` / `round_name` | Tour and draw (e.g. "ATP - Singles"), court surface, and round |
| `current_server` / `current_game_score_home` / `current_game_score_away` | Live-only point score snapshot |

### How to scrape tennis scores with Flashscore Tennis Scraper

1. Go to [Flashscore Tennis Scraper](https://apify.com/parsebird/flashscore-tennis-scraper) on Apify Store
2. Click **Try for free** to open the input form
3. Set **Days to Fetch** — `["0"]` for today, or any combination from `-7` to `7`
4. Optionally filter by **Match Status**, **Tours**, or **Tournament Name Filter**
5. Or paste a specific tournament's Flashscore URL into **Start URLs** to restrict the run to that event
6. Click **Start** and download results as JSON, CSV, or Excel — or pull them via the API

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| dayOffsets | array of strings | No | `["0"]` | Days to fetch, relative to today ("-7" to "7") |
| matchStatuses | array of strings | No | `["all"]` | `all`, `finished`, `live`, `scheduled` |
| tours | array of strings | No | `[]` (all) | `atp`, `wta`, `itf`, `challenger` |
| tournaments | array of strings | No | `[]` | Case-insensitive partial tournament name match |
| startUrls | array | No | `[]` | Flashscore tournament/results URLs; overrides `tournaments` |
| maxItems | integer | No | unlimited | Cap on total results across all days and tours |

### Output example

```json
{
  "match_id": "dMyRjUTr",
  "match_url": "https://www.flashscore.com/match/dMyRjUTr/",
  "match_date": "2026-08-21T15:00:00",
  "match_end_timestamp": "2026-08-21T16:25:29",
  "match_status": "FINISHED",
  "match_type": "singles",
  "result_type": "NORMAL",
  "winner": "home",
  "sets_won_home": 2,
  "sets_won_away": 0,
  "total_match_duration": "1:25",
  "sets": [
    { "home": 6, "away": 2, "duration": null, "tiebreak_home": null, "tiebreak_away": null },
    { "home": 6, "away": 2, "duration": null, "tiebreak_home": null, "tiebreak_away": null }
  ],
  "home_players": [
    { "name": "Stricker D.", "short_name": "STR", "ranking": 2, "nationality": "Switzerland", "photo_url": "https://static.flashscore.com/res/image/data/MiiS5AjC-Cr7x5z1L.png" }
  ],
  "away_players": [
    { "name": "Compagnucci T.", "short_name": "COM", "ranking": 1, "nationality": "Italy", "photo_url": "https://static.flashscore.com/res/image/data/SUJLD2Pq-OU0NGJVR.png" }
  ],
  "tournament_name": "Sion (Switzerland)",
  "tournament_id": "xr8us4YI",
  "tournament_url": "https://www.flashscore.com/tennis/challenger-men-singles/sion/",
  "category_name": "Challenger Men - Singles",
  "surface": "clay",
  "round_name": "Semi-Finals"
}
```

### Use cases

- 📊 **Results archiving** — Build a historical database of match scores across any tour
- 🔴 **Live score dashboards** — Poll for live matches at short intervals to power a scoreboard widget
- 📈 **Player tracking** — Monitor a specific player's matches, rankings, and results over a tournament
- 🏆 **Tournament coverage** — Pull every match from a single tournament via its Flashscore URL
- 🤖 **Sports data pipelines** — Feed structured tennis results into betting models, stats dashboards, or AI agents

### How it works

1. Fetches Flashscore's own day-based match feed for each requested day offset — the same data source Flashscore's website itself renders from, read directly via HTTP with no browser needed.
2. Parses the pipe-delimited feed format into structured records: tournament (name, category, surface), players (name, ranking, nationality, photo), and set-by-set scores.
3. Applies status, tour, tournament name, or Start URL filters, then caps the result at `maxItems` if set.
4. For each surviving match, reads its page's SEO metadata to fill in the round name, and for live matches, reads the match's own live-score feed for the current server and point score.
5. Records are pushed to the dataset as they're scraped.

### How much does it cost to scrape Flashscore tennis data?

Flashscore Tennis Scraper uses a single pay-per-event billable:

| Event | Free tier | Bronze/Silver/Gold |
|-------|-----------|---------------------|
| `match-scraped` (per match record) | $0.0009 / $0.90 per 1,000 | $0.0008 / $0.80 per 1,000 |

A run returning 100 matches costs about $0.09 (Free tier). The [free trial](https://apify.com/pricing) includes enough credits to test the actor. Platform compute is included in the event price — you only pay for results.

### Integrations and API access

Flashscore Tennis Scraper runs on the [Apify platform](https://apify.com), giving you:

- **Scheduling** — Run daily, or every few minutes for live coverage
- **API access** — Start runs and fetch results programmatically
- **Webhooks** — Get notified when a run completes
- **Integrations** — Connect to Google Sheets, Slack, Zapier, Make, and [more](https://docs.apify.com/platform/integrations)
- **Export formats** — Download as JSON, CSV, Excel, or XML

#### Python example

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("parsebird/flashscore-tennis-scraper").call(run_input={
    "dayOffsets": ["-1"],
    "matchStatuses": ["finished"],
    "tours": ["atp"],
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['home_players'][0]['name']} vs {item['away_players'][0]['name']} — {item['sets_won_home']}-{item['sets_won_away']}")
```

#### JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor("parsebird/flashscore-tennis-scraper").call({
    dayOffsets: ["-1"],
    matchStatuses: ["finished"],
    tours: ["atp"],
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(item => console.log(`${item.home_players[0].name} vs ${item.away_players[0].name} — ${item.sets_won_home}-${item.sets_won_away}`));
```

### Is it legal to scrape Flashscore?

Web scraping of publicly available data is generally legal, as established by the US Ninth Circuit Court ruling in *hiQ Labs v. LinkedIn* (2022). Flashscore Tennis Scraper collects only publicly visible match data — scores and schedules that any visitor can see without logging in.

This actor does not access private account data or bypass payment or authentication systems. Users are responsible for ensuring their use case complies with applicable laws and Flashscore's terms of service.

For more on web scraping legality, see [Apify's guide to web scraping and the law](https://blog.apify.com/is-web-scraping-legal/).

### Related actors

- [Data Deduplicator](https://apify.com/parsebird/dataset-deduplicator) — Remove duplicate records from any Apify dataset
- [Data Cleaner](https://apify.com/parsebird/data-cleaner) — Clean, filter, and transform dataset records
- [HTTP Request Actor](https://apify.com/parsebird/http-request-actor) — Send arbitrary HTTP requests as part of a pipeline

### FAQ

**Why are `tiebreak_home`/`tiebreak_away` and per-set `duration` always null?**
Flashscore's compact match feed doesn't expose tiebreak sub-scores or per-set timing in a way that could be reliably verified during development, so these are left null rather than guessed. Overall `total_match_duration` and set game scores are unaffected.

**Why do some doubles matches have less player detail on the second partner?**
Flashscore's feed only fully exposes id, slug, and short name for the first-listed partner in a pair; the second partner's name, nationality, and photo are still included, but ranking and a few identifiers are not separately available at this level.

**What does `current_game_score` show during a tiebreak or at deuce?**
It passes through whatever Flashscore itself displays, including `"A"` for advantage. Tiebreak point counts (e.g. `"7"`) are shown once a set reaches a tiebreak rather than the usual 0/15/30/40 sequence.

**Does `live` give me a real-time stream?**
No — each run reads a snapshot of live matches at the moment it executes. For near-real-time coverage, [schedule](https://docs.apify.com/platform/schedules) the actor to run at short intervals.

**Can I get every match from one specific tournament?**
Yes — paste that tournament's Flashscore URL (the main page or `/results/` page) into `startUrls`. Matches are still limited to the days selected in `dayOffsets`, so make sure that range covers when the tournament is being played.

**Can I schedule recurring runs?**
Yes. Use [Apify's scheduling feature](https://docs.apify.com/platform/schedules) to run this actor daily, hourly, or at any custom interval.

# Actor input Schema

## `dayOffsets` (type: `array`):

Which days to fetch, relative to today. "0" = today, "-1" = yesterday, "1" = tomorrow. Any value from "-7" to "7" is valid.

## `matchStatuses` (type: `array`):

Filter by match state. If "all" is included, other values are ignored. "live" reflects match status at the moment the run executes, not a continuous stream.

## `tours` (type: `array`):

Restrict results to specific tennis tours. Leave empty to return every tour, including juniors and exhibitions.

## `tournaments` (type: `array`):

Case-insensitive partial match on tournament name, e.g. "Wimbledon" or "Roland Garros". Ignored when Start URLs is set.

## `startUrls` (type: `array`):

Flashscore tournament or results page URLs (must be on www.flashscore.com). Restricts the run to those specific tournaments and overrides the Tournament Name Filter above. Matches are still limited to the selected Days to Fetch.

## `maxItems` (type: `integer`):

Optional cap on total results across all days and tours. Leave blank for no limit.

## Actor input object example

```json
{
  "dayOffsets": [
    "0"
  ],
  "matchStatuses": [
    "all"
  ],
  "tours": [],
  "tournaments": [],
  "startUrls": []
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "dayOffsets": [
        "0"
    ],
    "matchStatuses": [
        "all"
    ],
    "startUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/flashscore-tennis-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "dayOffsets": ["0"],
    "matchStatuses": ["all"],
    "startUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/flashscore-tennis-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "dayOffsets": [
    "0"
  ],
  "matchStatuses": [
    "all"
  ],
  "startUrls": []
}' |
apify call parsebird/flashscore-tennis-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/flashscore-tennis-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/88SXu3xVxZY69WHj3/builds/V0f0YbNulXTlKizdq/openapi.json
