# Flashscore Scraper (`mina_safwat/flashscore-scraper`) Actor

Scrape live scores, results, fixtures and league tables across 22 sports — with match statistics, goal timelines and lineups on request.

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

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Collect **live scores, finished results, upcoming fixtures and league tables** from [Flashscore](https://www.flashscore.com) across **22 sports**, as clean rows, in seconds. No account, no API key, no browser.

### What does Flashscore Scraper do?

Flashscore Scraper collects every match Flashscore lists for the sports and days you choose: who played, when, the score, and whether the match is scheduled, live, finished, postponed, cancelled or decided by walkover. Pick one or more sports and a date range from a week back to a week ahead. **Every competition running in those sports is included**, not just the famous leagues.

On request it also adds the detail behind each match: full statistics including **expected goals (xG)** for the match and each half, the timeline of goals, assists, cards and substitutions, lineups with formations, and **league tables**.

Running on Apify means you can call it through the API, schedule it every few minutes for live scores, monitor runs, and send results to Google Sheets, Make, Zapier or your own pipeline.

### Why scrape Flashscore?

- **Build a results database.** One run covers a whole day across every league in a sport.
- **Track live scores.** Schedule short runs and read the rows whose `status` is `live`.
- **Model and analyse.** xG, shots and possession per match feed prediction models.
- **Publish fixtures.** Upcoming matches with kick-off times, for a site, app or newsletter.
- **Follow league races.** Standings give rank, played, won, drawn, lost, goals and points.
- **Cover minor sports.** Futsal, floorball, beach soccer and field hockey are in here too.

### How to scrape Flashscore results and fixtures

1. Click **Try for free** to open the Actor in Apify Console.
2. Pick your **Sports** and a day range (`0` is today, `-1` yesterday, `1` tomorrow).
3. Optionally turn on statistics, timeline, lineups or league tables.
4. Click **Start** and wait a few seconds.
5. Open the **Output** tab and download the results as JSON, CSV, Excel or HTML.

### Input

Everything is set on the **Input** tab. Every field has a working default.

| Field | What it does |
|---|---|
| `sports` | One or more of 22 sports. Every competition in each is included. |
| `days_from` / `days_to` | Relative days: `0` today, `-1` yesterday, `1` tomorrow. Up to 7 days per run, within a week of today. A wider range keeps its first 7 days and says so in the log. |
| `max_matches_per_day` | Cap per sport per day (default 200). A football weekday lists a few hundred matches and a busy weekend 1,000–1,500, while a golf day can list 1,000+ golfers. |
| `include_statistics` | Possession, shots, corners, xG, for the whole match and per period. One extra request per match. |
| `include_incidents` | Goals with their assists, cards and substitutions, with minutes. One extra request per match. |
| `include_lineups` | Formations and named players, with each player's team and lineup section. One extra request per match. |
| `include_standings` | League tables for the competitions seen in the matches. |
| `max_standings_tables` | Cap on how many league tables are fetched (default 20). |
| `proxy_configuration` | Residential proxy by default. |

```json
{
    "sports": ["football", "tennis"],
    "days_from": -1,
    "days_to": 0,
    "max_matches_per_day": 200,
    "include_statistics": true,
    "include_standings": false,
    "proxy_configuration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

**Sports available:** football, tennis, basketball, hockey, american-football, baseball, handball, rugby-union, rugby-league, volleyball, beach-volleyball, cricket, futsal, floorball, field-hockey, beach-soccer, aussie-rules, badminton, snooker, darts, boxing, golf.

### Output

One row per match. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
{
    "entity": "match",
    "match_id": "YTiXRfng",
    "sport": "football",
    "url": "https://www.flashscore.com/match/YTiXRfng/",
    "status": "finished",
    "start_time": "2026-09-24T18:45:00+00:00",
    "country": "Europe",
    "league": "UEFA Nations League - League A",
    "league_path": "/football/europe/uefa-nations-league/",
    "league_id": "A332sepf",
    "season_id": "A1uGXGgK",
    "home_team": "Netherlands",
    "home_team_id": "WYintcWb",
    "home_logo": "https://www.flashscore.com/res/image/data/MkxaoTAN-fazrR153.png",
    "away_team": "Germany",
    "away_team_id": "ptQide1O",
    "away_logo": "https://www.flashscore.com/res/image/data/0SofTgVH-fB4vYUZp.png",
    "home_score": 1,
    "away_score": 1,
    "winner": "draw",
    "updated_at": "2026-09-24T20:42:28+00:00",
    "scraped_at": "2026-10-01T09:12:44.512331+00:00"
}
```

A tennis row looks the same, with the score in **sets won**:

```json
{
    "entity": "match",
    "sport": "tennis",
    "status": "finished",
    "country": "ATP - SINGLES",
    "league": "Beijing (China), hard",
    "home_team": "Khachanov K.",
    "away_team": "Auger-Aliassime F.",
    "home_score": 2,
    "away_score": 0,
    "winner": "home"
}
```

With the detail options on, each match row also carries:

```json
"statistics": [
    { "period": "Match", "section": "Top stats", "name": "Expected goals (xG)", "home": "3.18", "away": "1.45" },
    { "period": "Match", "section": "Top stats", "name": "Ball possession", "home": "53%", "away": "47%" },
    { "period": "1st Half", "section": "Top stats", "name": "Ball possession", "home": "47%", "away": "53%" }
],
"incidents": [
    { "period": "1st Half", "minute": "32'", "side": "away", "type": "Goal", "player": "Nmecha F.", "player_id": "80RErj9O", "detail": null, "home_score": 0, "away_score": 1 },
    { "period": "1st Half", "minute": "32'", "side": "away", "type": "Assistance", "player": "Adeyemi K.", "player_id": "GvIzwgo8", "detail": null, "home_score": 0, "away_score": 1 }
],
"lineups": {
    "home_formation": "1-4-2-3-1",
    "away_formation": "1-4-2-3-1",
    "players": [
        { "name": "Dumfries D.", "player_id": "QR0j1ejk", "side": "home", "section": "Starting Lineups", "shirt_number": "22", "rating": "7.8" },
        { "name": "Xavi", "player_id": "bs5KnIiT", "side": "home", "section": "Coaches", "shirt_number": null, "rating": null }
    ]
}
```

League tables come as separate rows with `"entity": "standing"`.

#### Dataset views

- **Matches**: the fixture list with scores and status. This is the view you'll use most.
- **Statistics & timeline**: the per-match detail, when you've asked for it.
- **League tables**: the standings columns (rank, team, played, points and so on).

### Data fields

Match rows (`entity: "match"`):

| Field | Description |
|---|---|
| `match_id` | Flashscore's match id. |
| `sport` | The sport you asked for, e.g. `football`. |
| `url` | Link to the match on Flashscore. |
| `status` | `scheduled`, `live`, `finished`, `postponed`, `cancelled`, `interrupted`, `abandoned`, `retired`, `walkover` or `awarded`. In golf, `finished` can mean the golfer has finished the current round while the tournament goes on. |
| `start_time` | Kick-off in UTC (ISO 8601). |
| `country` | The first part of Flashscore's competition title, as Flashscore writes it. Usually the country or region, e.g. `England`, `USA`, `Europe`. Sports without one use their own grouping: the tour and draw in tennis (`ATP - SINGLES`), the weight class in boxing (`MIDDLEWEIGHT - MEN`), the tour in golf (`PGA TOUR`), the category in badminton (`OTHERS - MEN`). |
| `league` | Competition name, e.g. `Premier League`. For tennis, the tournament and surface. |
| `league_path` | The competition's path on Flashscore. |
| `league_id`, `season_id` | Competition and season ids. |
| `home_team`, `away_team` | Team or player names. In tennis doubles, the two names joined by `/`. In golf stroke play each row is one golfer, in `home_team`, and the `away_*` fields are empty. |
| `home_team_id`, `away_team_id` | Flashscore team or player ids. |
| `home_logo`, `away_logo` | Logo image URLs. |
| `home_score`, `away_score` | The score. Empty until the match starts. **In tennis this is sets won**, not games. In Aussie rules it is total points, in cricket runs, and in golf stroke play the golfer's score to par (e.g. `-9`). Boxing has no score. |
| `winner` | `home`, `away` or `draw`, taken from Flashscore's own result. Empty until the result is decided, and for postponed, cancelled, interrupted and abandoned matches. For walkovers and retirements it names the side that went through. Always empty for golf stroke play. |
| `method` | Boxing only: how and in which round the bout ended, e.g. `TKO/7` or `points/10`. |
| `updated_at` | When Flashscore last updated the score. Filled for live matches and most finished ones; empty before kick-off and for some finished matches, so don't rely on it. |
| `scraped_at` | When the row was collected. |
| `statistics` | With `include_statistics`: one entry per stat and period, with `period` (`Match`, `1st Half`, `2nd Half`, or a sport's own periods), `section` (e.g. `Top stats`, `Shots`; empty where the sport has none), `name`, `home` and `away`. Filter on `period: "Match"` for full-match values. |
| `incidents` | With `include_incidents`: one entry per person involved, in match order, with `period`, `minute`, `side`, `type` (e.g. `Goal`, `Assistance`, `Yellow Card`, `Substitution - Out`, `Substitution - In`, `Goal Disallowed`), `player`, `player_id`, `detail` (e.g. the card reason) and the running `home_score`/`away_score` where the incident has one. A goal and its assist, or the two players in a substitution, are separate entries with the same minute. |
| `lineups` | With `include_lineups`: `home_formation`, `away_formation` and `players`, each with `name`, `player_id`, `side` (`home`/`away`), `section` (`Starting Lineups`, `Substitutes`, `Coaches`, or the lines in hockey), `shirt_number` and `rating` (where Flashscore rates players). |

The three detail fields are empty for competitions Flashscore doesn't publish detail for.

League table rows (`entity: "standing"`) carry `sport`, `country`, `league`, `league_id`, `season_id`, `group` (only for tables split into groups), `rank`, `team`, `team_id`, `played`, `wins`, `draws`, `losses`, `goals_for`, `goals_against`, `points` and `scraped_at`.

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

The Actor is priced **per result**: **$0.001 per result**, plus **$0.00005 per run** start at the default 1 GB of memory (the start fee is charged per GB). That works out to **about $1.00 per 1,000 results**. One match is one result, and one team in a league table is one result.

| Run | Results | Cost |
|---|---|---|
| Football + tennis today (the prefilled input) | up to 400 | about $0.40 |
| Football, a weekend day, `max_matches_per_day` raised to 2,000 | ~1,000–1,500 | about $1.00–$1.50 |
| Live check, one sport, `max_matches_per_day: 50` | 50 | about $0.05 per run |

Turning on statistics, timeline or lineups does **not** add results: each enriches a match row that was already going to be pushed. It does add one request per match, so the run takes longer.

A sport and day that returns nothing adds **no result charges** (only the run's small start fee applies). It is listed in the `FAILED_INPUTS` record of the run's key-value store instead, with the reason.

Apify's free plan includes $5 of monthly platform credit, which covers about 5,000 results.

### Tips for faster, cheaper runs

- **`max_matches_per_day` is your cost control.** A weekend day of football alone can list over 1,500 matches.
- For live scores, schedule short runs with `days_from: 0, days_to: 0` and filter for `status: live`.
- A match close to midnight is listed on both neighbouring days. A multi-day run keeps only the first copy, so you're never charged twice.
- Statistics and lineups are only published for the bigger competitions. Smaller leagues return matches and scores but no detail. That comes from Flashscore, not from a failed run.
- League tables only make sense for league competitions. Knockout cups and individual sports return little or nothing.

### FAQ, disclaimers and support

**How far back can I go?** Seven days either side of today, up to 7 days per run. For deeper history, schedule a daily run and accumulate the results.

**Does it cover live matches?** Yes. `status` is `live` while a match is in progress, with the score as it stands.

**Which sports have xG?** Football, mainly. Other sports carry their own statistics.

**Why does a run say some feeds "gave nothing"?** Either nothing was scheduled (an answer, and the run succeeds) or Flashscore refused the request. The status message counts both kinds, and the `FAILED_INPUTS` record lists each sport-day or league table with its reason. A run only fails when every sport-day was refused.

**Is it legal to scrape Flashscore?** This Actor only reads publicly available scores and fixtures. Flashscore's terms of use restrict automated access and commercial reuse of its data, so you are responsible for how you use the results. Check those terms, and take legal advice before redistributing the data commercially. Lineups and timelines contain player names, which may count as personal data in some jurisdictions.

**Known limitations:** the date range is limited to a week either side of today, and detail exists only where Flashscore publishes it. If Flashscore changes its data format, runs may fail until the Actor is updated.

Found a problem or want a field added? Open an issue on the Actor's **Issues** tab. Need a custom sports-data pipeline? Get in touch through the same tab.

# Actor input Schema

## `sports` (type: `array`):

Which sports to collect. Every competition running in each sport is included.

## `days_from` (type: `integer`):

Relative to today: 0 is today, -1 yesterday, 1 tomorrow. Finished results are in the past, fixtures in the future.

## `days_to` (type: `integer`):

The last day to collect, inclusive. A range covers at most 7 days per run.

## `max_matches_per_day` (type: `integer`):

A busy football day lists well over a thousand matches, so this keeps a run from ballooning. Raise it when you want everything.

## `include_statistics` (type: `boolean`):

Possession, shots, corners and expected goals (xG) where the sport has them, for the whole match and per period. Costs one extra request per match, so a large run takes noticeably longer.

## `include_incidents` (type: `boolean`):

The timeline of the match: who scored and assisted, cards and substitutions, when, and the running score. One extra request per match.

## `include_lineups` (type: `boolean`):

Formations and the named players, each with their team and whether they started, were on the bench or coached. One extra request per match.

## `include_standings` (type: `boolean`):

Adds a row per team for every league seen in the matches above — rank, played, won, drawn, lost, goals and points.

## `max_standings_tables` (type: `integer`):

Caps how many league tables are fetched. Only used when league tables are turned on.

## `proxy_configuration` (type: `object`):

Only used as a fallback: each request goes direct first, and moves to this proxy if Flashscore refuses it.

## Actor input object example

```json
{
  "sports": [
    "football",
    "tennis"
  ],
  "days_from": 0,
  "days_to": 0,
  "max_matches_per_day": 200,
  "include_statistics": false,
  "include_incidents": false,
  "include_lineups": false,
  "include_standings": false,
  "max_standings_tables": 20,
  "proxy_configuration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "sports": [
        "football",
        "tennis"
    ],
    "days_from": 0,
    "days_to": 0,
    "max_matches_per_day": 200,
    "max_standings_tables": 20,
    "proxy_configuration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("mina_safwat/flashscore-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 = {
    "sports": [
        "football",
        "tennis",
    ],
    "days_from": 0,
    "days_to": 0,
    "max_matches_per_day": 200,
    "max_standings_tables": 20,
    "proxy_configuration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("mina_safwat/flashscore-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 '{
  "sports": [
    "football",
    "tennis"
  ],
  "days_from": 0,
  "days_to": 0,
  "max_matches_per_day": 200,
  "max_standings_tables": 20,
  "proxy_configuration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call mina_safwat/flashscore-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mina_safwat/flashscore-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/r18bmvO3m0TAlxqlI/builds/aTRoJNFoSuTu34ov1/openapi.json
