# SofaScore Sports Scraper: Live Scores, Timeline, Lineups (`mrbridge/sofascore-sports-scraper`) Actor

Scrape SofaScore football, tennis and basketball matches, one row per match: teams, score, period scores, status, minute, start time and winner. Live, by round, by match link or by day. Football adds referee, venue, goals, cards, substitutions and lineups. JSON, CSV or Excel. By MrBridge

- **URL**: https://apify.com/mrbridge/sofascore-sports-scraper.md
- **Developed by:** [MrBridge](https://apify.com/mrbridge) (community)
- **Categories:** News, Other
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 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/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

## SofaScore Sports Scraper

SofaScore Sports Scraper collects football, tennis and basketball matches from SofaScore (https://www.sofascore.com), one clean row per match, ready for JSON, CSV or Excel. It reads the public pages and responses of the site, so no account and no API key are needed. Each row gives the teams or players, the tournament, the season, the round, the start time, the status, the score, the half-time score, the winner and a link to the match page. You can add the match sheet, the timeline of goals, cards and substitutions, and the line-ups.

Pick `football`, keep the `live` mode and set `maxItems` to 20: the Actor returns up to 20 matches in play right now, each with its tournament, elapsed minute and current score. Switch to the `date` mode with a league such as `premier-league` to get the fixtures and results of a weekend, and turn on the details to get the referee, the venue, each goal with its scorer and the starting line-ups.

### What is SofaScore Sports Scraper?

SofaScore is a live-score website that lists matches of thousands of tournaments, with scores updated during play. The Actor reads those pages for you. It picks the matches according to the mode you choose, applies your league filter, removes duplicates and returns one structured row per match. The first 23 columns follow a fixed sports-matches layout, documented below, so the rows are easy to compare with other sources that use the same layout, such as [Flashscore Matches Scraper](https://apify.com/mrbridge/flashscore-matches-scraper).

#### What data can I extract with it?

One row per match: source, match ID, match link, sport, country, tournament and its ID, season, round, start time, normalized status and status as SofaScore writes it, elapsed minute of a live football match, home and away side with their IDs, score, half-time score, winner and scrape time. Then the SofaScore columns: page code and slug, tournament slug, category, season ID, score of each period, tennis surface, red cards, and the optional `details`.

#### How can I use the results?

- Follow the matches in play right now across a sport, with their score and minute.
- Build a results archive of the leagues you follow, one day or one round at a time.
- Feed a dashboard or a newsletter with the fixtures of the coming days and yesterday's scores.
- Study how often home sides win in a tournament, using the winner and half-time columns.
- Collect the goals, cards, substitutions and line-ups of finished football matches.

### How to use it

1. Open the Actor in Apify Console.
2. Pick a mode, the sports and, if you want to narrow the list, the leagues, the dates, the rounds or the match links.
3. Set `maxItems`, then start the run. Rows appear in the dataset as they are delivered.

### Input

| Field | Meaning | Default |
|---|---|---|
| `mode` | `live`, `tournament`, `matches` or `date` (see below) | `live` |
| `sports` | `football`, `tennis`, `basketball`. Used by the `live` and `date` modes | `["football"]` |
| `tournaments` | Rounds to read in the `tournament` mode, up to 500 | empty |
| `matchUrls` | Match links or IDs to read in the `matches` mode, up to 500 | empty |
| `dates` | Days as `YYYY-MM-DD` in the `date` mode | empty, which means today (UTC) |
| `leagues` | Keep only these leagues in the `date` mode, up to 100. Empty keeps all | empty |
| `maxItems` | Hard cap on match rows returned and billed, 1 to 10000 | 100 |
| `includeDetails` | Add the `details` column to each match | `false` |

The Console form pre-fills `mode` with `live`, `sports` with `football` and `maxItems` with 20. Example input:

```json
{
  "mode": "live",
  "sports": [
    "football"
  ],
  "maxItems": 20
}
```

The four modes:

- `live`: the matches in play now, for each sport of `sports`.
- `tournament`: the matches of the rounds listed in `tournaments`. An entry is `{ "uniqueTournamentId": 17, "seasonId": 96668, "round": 7 }` or `{ "url": "https://www.sofascore.com/football/tournament/england/premier-league/17#id:96668", "round": 7 }`. The round is required.
- `matches`: the matches named in `matchUrls`, as SofaScore match links that end with `#id:<number>` or as match IDs.
- `date`: the matches of the days listed in `dates`, for each sport of `sports`, optionally limited by `leagues`.

A field that does not fit the mode is refused, except `sports`, which the `tournament` and `matches` modes ignore because the sport comes from the match.

`dates` accepts real calendar days from 7 days before to 7 days after the UTC day on which the run starts. A match is kept when its start falls on one of these UTC days.

`leagues` is a local filter. Case is ignored and a match is kept when it fits any entry. An entry takes one of these forms:

- the SofaScore ID of the unique tournament, for example `17`
- the slug of the tournament, for example `premier-league`
- the name or the slug of the category, which is usually the country, for example `England` or `england`
- a key prefixed with a sport, for example `football:17` or `basketball:england`, which applies to that sport only

The sport of a prefix must be `football`, `tennis` or `basketball` and must be in `sports`, otherwise the input is refused. A number alone only matches a tournament ID. A category name that contains a colon is given by its slug.

Invalid input ends the run successfully with one `BAD_INPUT` row in the `errors` dataset that lists every problem, and no match row.

### Output

Matches go to the default dataset, one row per match. Problems go to a separate `errors` dataset and are never billed. The `OUTPUT` record of the key-value store summarizes the run. The dataset has two views: `overview` and `details`.

The first 23 columns are the common layout, in this order:

| Field | Type | Meaning |
|---|---|---|
| `source` | string | Always `SofaScore` |
| `matchId` | string | SofaScore match ID, the key of the row |
| `url` | string or null | SofaScore page of the match |
| `sport` | string | `football`, `tennis` or `basketball` |
| `country` | string or null | Country of the tournament category |
| `tournament` | string or null | Tournament name |
| `tournamentId` | string or null | SofaScore ID of the unique tournament |
| `season` | string or null | Season name |
| `round` | string or null | Round name, or `Round N` when only the number is known |
| `startTime` | string or null | ISO 8601 in UTC |
| `status` | string | `scheduled`, `live`, `finished`, `postponed`, `cancelled`, `abandoned`, `interrupted` or `unknown` |
| `statusRaw` | string or null | The status as SofaScore writes it |
| `minute` | integer or null | Elapsed minute of a live football match in the first or second half. Null otherwise |
| `homeTeam`, `awayTeam` | string or null | Team, or player in tennis |
| `homeTeamId`, `awayTeamId` | string or null | SofaScore IDs |
| `homeScore`, `awayScore` | integer or null | Final or current score. Sets in tennis |
| `homeScoreHalfTime`, `awayScoreHalfTime` | integer or null | Half-time score in football, first two quarters added in basketball, null in tennis |
| `winner` | string or null | `home`, `away` or `draw`, from the winner code of the source |
| `scrapedAt` | string | Time the row was built, ISO 8601 in UTC |

Then the SofaScore columns:

| Field | Type | Meaning |
|---|---|---|
| `customId` | string or null | Short code of the match page link |
| `slug` | string or null | Match slug used in the page link |
| `tournamentSlug` | string or null | Slug of the unique tournament |
| `category` | string or null | Category of the tournament, usually the country |
| `seasonId` | string or null | SofaScore season ID |
| `periodScores` | array or null | Score of each period (half, set or quarter), up to five, objects `{ period, home, away }`. Null when absent |
| `groundType` | string or null | Tennis surface |
| `homeRedCards`, `awayRedCards` | integer or null | Red cards of each side, football |
| `details` | object or null | Match sheet, timeline and line-ups, see below |

Every field is always present, with `null` when SofaScore gives no value.

This is one real row from the example input above, built by the Actor from a stored SofaScore response:

```json
{
  "source": "SofaScore",
  "matchId": "16604724",
  "url": "https://www.sofascore.com/football/match/cd-inca-isidro-metapan/HMjsyyVd#id:16604724",
  "sport": "football",
  "country": "El Salvador",
  "tournament": "Primera División, Apertura",
  "tournamentId": "11537",
  "season": "Primera Division 26/27",
  "round": "Round 19",
  "startTime": "2026-11-07T00:00:00.000Z",
  "status": "live",
  "statusRaw": "1st half",
  "minute": 11,
  "homeTeam": "C.D. Inca Aruba",
  "homeTeamId": "488673",
  "awayTeam": "Isidro Metapan",
  "awayTeamId": "24382",
  "homeScore": 0,
  "awayScore": 0,
  "homeScoreHalfTime": 0,
  "awayScoreHalfTime": 0,
  "winner": null,
  "scrapedAt": "2026-11-07T00:15:00.000Z",
  "customId": "HMjsyyVd",
  "slug": "cd-inca-isidro-metapan",
  "tournamentSlug": "primera-division-apertura",
  "category": "El Salvador",
  "seasonId": "99021",
  "periodScores": [
    {
      "period": 1,
      "home": 0,
      "away": 0
    }
  ],
  "groundType": null,
  "homeRedCards": null,
  "awayRedCards": null,
  "details": null
}
```

The example comes from a test fixture captured on 2026-11-07, so the scores and statuses are those of that day.

#### Details

Set `includeDetails` to `true` to fill `details`. It depends on the sport:

| Sport | Match sheet | `timeline` | `lineups` |
|---|---|---|---|
| Football | yes | yes | yes |
| Basketball | yes | `null` | yes |
| Tennis | none, `details` is `null` | | |

`details` holds these keys:

| Field | Meaning |
|---|---|
| `venue` | `{ name, city, country, capacity }` |
| `referee` | `{ name, shortName, id, country }` |
| `homeManager`, `awayManager` | `{ name, shortName, id }` |
| `injuryTime1`, `injuryTime2` | Added minutes announced for each half, football |
| `timeline` | Incidents of a football match, oldest first, see below |
| `lineups` | `{ confirmed, home, away }` where each side is `{ formation, players }` |

```json
{
  "venue": {
    "name": "Craven Cottage",
    "city": "London",
    "country": "England",
    "capacity": 29600
  },
  "referee": {
    "name": "Chris Kavanagh",
    "shortName": null,
    "id": "107059",
    "country": "England"
  },
  "homeManager": {
    "name": "Álvaro Arbeloa",
    "shortName": "Á. Arbeloa",
    "id": "798940"
  },
  "awayManager": {
    "name": "Sergej Jakirović",
    "shortName": "S. Jakirović",
    "id": "790280"
  },
  "injuryTime1": 1,
  "injuryTime2": 3
}
```

Each element of `timeline` is one incident:

| Field | Meaning |
|---|---|
| `id` | Incident ID |
| `period` | `1st Half`, `2nd Half` or `Extra Time`, null for a period mark |
| `side` | `home` or `away` |
| `minute`, `addedTime`, `minuteText` | Minute, added time and the minute as shown, for example `90+4'`. A period mark carries its label, such as `HT` or `FT` |
| `type` | `Goal`, `Yellow Card`, `Yellow Red Card`, `Red Card`, `Substitution - Out` or `Period` |
| `typeCode`, `playerUrl` | Always null, kept for the same layout as the Flashscore timeline |
| `player`, `playerId` | The player concerned. For a substitution, the player going off |
| `reason` | Reason of a card, or `Injury` for an injury substitution |
| `homeScore`, `awayScore` | Score after a goal or at a period mark |
| `related` | Linked player: the assist of a goal (`Assistance`) or the player coming on (`Substitution - In`) |
| `class` | Class given by SofaScore, for example `regular`, `penalty` or `ownGoal` |
| `rescinded`, `injury` | Flags given by SofaScore, null when absent |

```json
{
  "id": "365726690",
  "period": "1st Half",
  "side": "home",
  "minute": 33,
  "addedTime": null,
  "minuteText": "33'",
  "type": "Goal",
  "typeCode": null,
  "player": "Alex Iwobi",
  "playerId": "352770",
  "playerUrl": null,
  "reason": null,
  "homeScore": 1,
  "awayScore": 0,
  "related": [
    {
      "type": "Assistance",
      "player": "Sander Berge",
      "playerId": "793167",
      "playerUrl": null
    }
  ],
  "class": "regular",
  "rescinded": null,
  "injury": null
}
```

Each player of a line-up has a name, a short name, an ID, a shirt number, a position, a `substitute` flag and a `captain` flag:

```json
{
  "name": "Bernd Leno",
  "shortName": "B. Leno",
  "id": "103335",
  "shirtNumber": 1,
  "position": "G",
  "substitute": false,
  "captain": false
}
```

- `timeline` is `[]` for a football match that is scheduled, postponed or cancelled, and no request is made for it.
- Inside a non-null `details`, `timeline` is `null` for basketball rows, and for a football match whose incidents request failed or could not be read.
- A person comes out with a name, a short name and an ID only. Birth dates, heights, market values and user counts are never output.
- A line-up that SofaScore has not published gives an error row `NOT_FOUND` in the `errors` dataset, and the match row still comes out.
- `details` is `null` when the option is off, for tennis rows, and when nothing could be read for the match.

### Billing

One `match` event is billed per delivered row. One `match-details` event is billed on top for a row whose details hold a timeline with at least one goal, card or substitution, or a line-up with at least one player. The venue, the referee, the managers and the added time alone are not billed, and neither are the period marks (`HT`, `FT`) of a timeline. Errors are never billed: a missing line-up gives a `NOT_FOUND` row in the `errors` dataset and no charge. Duplicates, filtered-out matches and details with nothing billable are not billed either. The Pricing tab of the Actor shows the current prices.

When the platform moves a run to another server or restarts it while it works, the run picks up where it was. A match already returned is neither returned nor billed again.

### Limits

- Details cover football (sheet, timeline and line-ups), basketball (sheet and line-ups, `timeline` null) and no tennis detail.
- The Actor does not output match statistics or player statistics.
- `minute` is computed for football only, and only while the match is in its first or second half.
- `dates` covers 7 days before to 7 days after the UTC day of the launch.
- In the `date` mode, one football day without a filter costs about 150 requests, so a run covers about 6 such days. A `leagues` filter cuts this sharply, one league of one country can take 2 requests. The categories that would exceed the request cap of the run are left out and counted in `categoriesDropped` of the `OUTPUT` record.
- In the `date` mode, the basketball list of a day may be refused, and so may a single category. The run then writes a `TARGET_BLOCKED` row and goes on, so a `date` run can return no basketball match at all. For basketball, the `live` mode or the `matches` mode stay available. In the `matches` mode, basketball details come out with the venue and the line-ups, while the referee and the formation are usually null. The `timeline` is always null for basketball.
- The Actor does not output betting odds. For odds, use [Flashscore Matches Scraper](https://apify.com/mrbridge/flashscore-matches-scraper).
- A match close to midnight can appear in two day lists. It is returned once.
- A run with `includeDetails` makes up to three more requests per match, so it lasts longer. For large runs, raise the run timeout.
- Each run is a snapshot of SofaScore at that moment. Scores move, so two runs a minute apart can differ.

### Run summary and early stops

The `OUTPUT` record counts requests, pages, matches, errors and the details: `detailRequests` (the detail requests really made), `rowsWithDetails` and `detailsCharged`. `categoriesDropped` counts the categories left out of a `date` plan.

`stoppedBy` says why a run ended early. It keeps the first reason only.

- `null`: all the requested work was done.
- `maxItems`: the `maxItems` cap was reached.
- `chargeLimit`: the maximum charge set for the run was reached.
- `deadline`: the run reached its internal time limit.
- `circuitOpen`: too many blocked responses in a row.
- `pageBudget`: the request budget of the run was spent.
- `badInput`: the Actor's access to the data source was refused. This is a configuration problem on the Actor's side and not in your input. Please report it in the Issues tab.
- `fetchFailed`: the last walk ended on a page that could not be fetched. `failedWalks` lists the first 20 failed walks.

When a run stops for `deadline`, `circuitOpen` or `pageBudget` in the middle of a page, the rest of that page gets no details and the rows already read are kept.

Every business error is written to the `errors` dataset with a `kind`: `BAD_INPUT`, `TARGET_BLOCKED`, `RATE_LIMITED`, `FETCH_FAILED`, `UPSTREAM_ERROR`, `SCHEMA_CHANGED`, `LISTING_INVALID` or `NOT_FOUND`. The `OUTPUT` record counts errors in `errorsByKind`.

### Frequently asked questions

#### Why do I get fewer matches than `maxItems`?

The mode, the sports and the days you chose hold fewer matches than the cap, or your `leagues` narrow the list. When no more matching matches exist, the run ends with `stoppedBy` set to `null`.

#### Why is `details` null on some rows?

Tennis rows get no details, and a row also stays null when the option is off or when nothing could be read for the match. Basketball rows have a sheet and line-ups but a `timeline` of `null`.

#### Does it return match statistics or player statistics?

No. A row gives the score, the half-time score and the periods, and with `includeDetails` the match sheet, the timeline of a football match and the line-ups. Possession, shots and other match statistics are not output, and neither are player statistics.

#### Does it return betting odds?

No. For odds, use [Flashscore Matches Scraper](https://apify.com/mrbridge/flashscore-matches-scraper), which adds the prices that operators listed in the United Kingdom show for a match.

#### Can I combine it with Flashscore Matches Scraper?

Yes. Both Actors share the same 23 first columns, in the same order, so their rows can be merged into a single table. Keep the `source` column to tell which site each row came from.

#### Is there a similar Actor for another site?

Yes, [Flashscore Matches Scraper](https://apify.com/mrbridge/flashscore-matches-scraper) returns the same 23 first columns for football, tennis and basketball, with a timeline and odds.

#### Can I use SofaScore Sports Scraper via MCP?

Yes. Any Apify Actor can be called from an MCP client through the Apify MCP server. See the [Apify MCP documentation](https://docs.apify.com/platform/integrations/mcp) for the setup.

#### Your feedback

We are always working on improving our Actors. If you have technical feedback for SofaScore Sports Scraper or found a bug, please create an issue on the Actor's [Issues tab](https://apify.com/mrbridge/sofascore-sports-scraper/issues).

More free tools, scrapers, MCP servers and data studies from the same team: [mr-bridge.com](https://mr-bridge.com).

### Legal and responsible use

The data comes from the public pages and responses of SofaScore (https://www.sofascore.com) and belongs to its owners. SofaScore does not publish an API for it and has no link with this Actor. It has its own terms of use, and it may restrict automated access or commercial reuse. Before you rely on the output, in particular for commercial use, confirm that your use is permitted by the terms that apply. You remain responsible for how you use the results and for complying with the source's terms and with the laws that apply to you.

# Changelog

This Actor's version history is a separate document: https://apify.com/mrbridge/sofascore-sports-scraper/changelog.md

# Actor input Schema

## `mode` (type: `string`):

live: the matches in play now for the sports below. tournament: the matches of the rounds listed in Tournament rounds. matches: the matches listed in Match links. date: the matches of the days listed in Dates, for the sports below, optionally limited to some leagues.

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

Sports read in live and date modes. Ignored in the other modes: the sport comes from the match.

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

One entry per round. Either { "uniqueTournamentId": 17, "seasonId": 96668, "round": 7 } or { "url": "https://www.sofascore.com/football/tournament/england/premier-league/17#id:96668", "round": 7 }. The round is required.

## `matchUrls` (type: `array`):

SofaScore match links that end with #id:<number>, or match ids (numbers).

## `dates` (type: `array`):

UTC days in the form YYYY-MM-DD, from 7 days before to 7 days after the day the run starts. Leave empty for today (UTC). A match is kept when it starts on one of these UTC days.

## `leagues` (type: `array`):

Optional, 100 entries at most. Keeps the matches of a league when an entry (case ignored) equals its SofaScore unique tournament id or its tournament slug (for example 17 or premier-league), or the name or slug of its category, usually the country (England or england). Prefix an entry with a sport to limit it to that sport (football:17, basketball:england): the sport must be one of football, tennis, basketball and be in Sports, any other prefix such as hockey:17 is refused. A number alone only matches a unique tournament id. A category name that contains a colon is given by its slug. Leave empty for every league.

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

Hard cap on the match rows returned and billed, from 1 to 10000. The run stops once that many rows are delivered.

## `includeDetails` (type: `boolean`):

Adds a details column to each match. Football gets the sheet (venue, referee, managers, added time), the timeline (goals, cards, substitutions, period marks) and the line-ups. Basketball gets the sheet and the line-ups, with no timeline. Tennis gets none. Makes up to 3 extra requests per match, so the run lasts longer. One match-details event is billed for a match whose timeline holds at least one goal, card or substitution, or whose line-up holds at least one player. The venue, the referee, the managers and the period marks alone are not billed. See the Pricing tab.

## `capturePlan` (type: `string`):

Maintainer only. Name of a closed diagnostic capture campaign (three names). Requires Internal capture mode. The allowlist lives in the code: any other value is rejected without issuing a request.

## `internalCaptureMode` (type: `boolean`):

Maintainer only. When true, captures raw responses to a named key-value store for building test fixtures. Not for normal use.

## Actor input object example

```json
{
  "mode": "live",
  "sports": [
    "football"
  ],
  "maxItems": 20,
  "includeDetails": false,
  "internalCaptureMode": false
}
```

# Actor output Schema

## `matches` (type: `string`):

Direct link to all dataset items produced by the run.

## `summary` (type: `string`):

Direct link to the OUTPUT record: requests made, matches read, returned and billed, errors by kind and the reason of an early stop.

# 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 = {
    "mode": "live",
    "sports": [
        "football"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrbridge/sofascore-sports-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 = {
    "mode": "live",
    "sports": ["football"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("mrbridge/sofascore-sports-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 '{
  "mode": "live",
  "sports": [
    "football"
  ],
  "maxItems": 20
}' |
apify call mrbridge/sofascore-sports-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrbridge/sofascore-sports-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/NcanGMAgmJozVK5Cs/builds/fUvG49eUSh1QuSbvh/openapi.json
