# SofaScore Scraper – Live Scores, Fixtures & Match Stats (`rl1987/sofascore-api-scraper`) Actor

Scrape SofaScore for live scores, fixtures, results, league tables and team or player profiles. One flat row per match: tournament, kick-off, both teams, score, status, venue, referee. Add match statistics, lineups, incidents, odds, votes, head-to-head. 17 sports. No API key needed.

- **URL**: https://apify.com/rl1987/sofascore-api-scraper.md
- **Developed by:** [R.L.](https://apify.com/rl1987) (community)
- **Features:** Limited permissions
- **Stats:** 114 total users, 39 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.54 / 1,000 result rows

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 Scraper – Live Scores, Fixtures & Match Stats

### What does this SofaScore scraper do?

**SofaScore Scraper** pulls live scores, fixtures and results, deep match detail, league tables, and team & player data straight from [SofaScore](https://www.sofascore.com)'s own backend REST API — the same one the official mobile app talks to. It covers 17 sports — football, basketball, tennis, ice hockey, cricket, esports, motorsport and more. Because it hits the API directly instead of rendering pages, it's fast, cheap, and returns clean structured JSON rather than scraped HTML.

Run it on the Apify platform for scheduling, a REST API to pull results, webhooks and integrations, and one-click dataset export to JSON, CSV or Excel — no script to babysit.

#### Why this one

- **Breadth, not just live football.** Nine modes — live scores, fixtures by date, full match
  detail, search, league tables, league seasons, teams, players, and paste-a-URL — across 17
  sports, with round navigation and date discovery as options on top. Most competing Actors do
  live football scores and stop there.
- **Season performance data, not only results.** Top scorers, assist leaders and per-team or
  per-player season totals, which answer "who is the best striker in this league" rather than
  just "what was the score".
- **Managers and venues are reachable.** SofaScore's mixed search never returns them; the typed
  search here does.
- **You are never stuck on an ID you don't have.** Typed search resolves names to IDs, and
  team/player → competitions resolves an entity to the tournament and season IDs every
  statistics endpoint needs.
- **Nothing fails silently.** A bad ID, a cup with no league table or a round that does not
  exist ends the run with a message naming the input that was wrong and how to fix it.

### What data can it pull from SofaScore?

- **Live scores** for any sport, updated in real time.
- **Fixtures & results** by date range, or by league season.
- **Full match detail** enriched on demand with:
  - **Statistics** — possession, shots, passes, xG and more
  - **Lineups** — formations, starters/bench, per-player match ratings
  - **Incidents** — goals, cards, substitutions, period markers
  - **Odds** — pre-match betting markets
  - **Win-probability votes** — crowd 1 / X / 2 tallies
  - **Head-to-head** — historical record between the two teams
- **League tables (standings)** — full or home/away splits.
- **Team profiles** — venue, manager, colours, and the full squad.
- **Player profiles** — position, market value, height, preferred foot, contract.
- **Season leaderboards** — top scorers, assist leaders, best average ratings and every other
  category a competition ranks, for players and for teams. A Premier League season ranks 32
  player categories and 34 team categories; pick the ones you want with `topStatCategories`,
  because the full set is about 1,950 rows.
- **Aggregate season statistics** — one team's or one player's season totals, 118–127 metrics deep.
- **A team's or player's own fixtures** — their results and upcoming matches directly, plus
  "previous and next match" in a single request.
- **Which competitions a team or player appears in** — the route from a name to the
  tournament and season IDs the statistics endpoints need.
- **Round-by-round navigation** — matchday 12 of a league, or a named knockout stage, instead
  of a flat chronological season list.
- **Best players per match** — who actually played well, with ratings, and the player of the match.
- **Date discovery** — find out whether a date has matches, and which competitions are active
  on it, before downloading any of them.
- **Search** — typed and paged: teams, players, **managers**, **venues**, competitions, or
  everything at once. Resolve any name to its SofaScore ID.
- **Paste-a-URL mode** — drop in any SofaScore match/team/player/tournament link and it's routed automatically.
- **17 sports**, one Actor.

### How do I run it?

1. Click **Try for free** / **Start** on the Actor page.
2. Pick a **Mode** (see the table below).
3. Fill in the fields that mode needs — most are dropdowns or ID pickers.
4. Click **Start** and open the **Dataset** tab when it finishes (export as JSON, CSV, Excel, HTML…).

**Finding IDs:** run `search` mode first (e.g. `"real madrid"`) to get the numeric `entityId` for a team, player or tournament — then feed it to `team`, `player`, `standings` or `tournament` mode. Or just paste the page URL into `url` mode and skip IDs entirely.

### What does each mode return?

Every dataset row carries a `kind` field identifying its shape (`event`, `event_detail`, `search_result`, `standings_row`, `team`, `player`). Wherever SofaScore has a matching web page, the row also carries a **`url`** linking to it (standings rows additionally include a `tournamentUrl`).

Each shape has its own **view** in the Console's dataset tab — *Overview* for matches,
*League table* for standings, *Team profiles*, *Player profiles*, *Search results*, and so
on. The dropdown defaults to *Overview*, which is match-shaped, so if you ran `standings`
or `team` and the table looks half empty, switch the view to the matching one. The export
(JSON / CSV / Excel) always contains every field regardless of the view you are looking at.

> **Changed 22 October 2026 — `team` → `teamName` on standings and player rows.** `team` used to
> be a plain team name on `standings_row` and `player` rows and the full native SofaScore
> team object on `team` rows, so one column header held a string in one run and a nested
> object in another — and CSV export turned the object into `team/id`, `team/name`, …
> while the string stayed a single cell. The label is now **`teamName`** on both row kinds,
> matching `teamId`/`teamSlug` beside it and the `teamName` that search and leaderboard rows
> already used. **`team` now always means the native object.** If you read `team` off a
> standings or player row, read `teamName` instead.

#### `live` — live scores

```json
{ "mode": "live", "sport": "football" }
```

```json
{
  "kind": "event", "id": 16860578, "slug": "port-city-fc-golden-warriors-fc",
  "startTimestamp": 1755532800, "sport": "football", "tournament": "NPSL",
  "homeTeam": "Port City FC", "awayTeam": "Golden Warriors FC",
  "homeScore": 1, "awayScore": 0, "statusType": "inprogress", "statusDescription": "2nd half"
}
```

#### `scheduled` — fixtures & results by date

```json
{ "mode": "scheduled", "sport": "football", "dateFrom": "2026-08-18", "dateTo": "2026-08-18", "maxPages": 3 }
```

Returns one `event` row per match on each day in the range (same shape as `live`). Turn on `fetchEventDetails` to fan out to full match detail per event.

#### `event_detail` — full match detail, with enrichments

```json
{
  "mode": "event_detail", "eventIds": ["16363633"],
  "includeStatistics": true, "includeLineups": true, "includeIncidents": true,
  "includeVotes": true, "includeH2H": true, "includeOdds": true
}
```

```json
{
  "kind": "event_detail", "id": 16363633, "homeTeam": "Arsenal", "awayTeam": "Coventry City",
  "homeScore": 3, "awayScore": 0, "statusType": "finished",
  "statistics": [{ "period": "ALL", "groups": [{ "groupName": "Match overview",
    "statisticsItems": [{ "name": "Ball possession", "home": "64%", "away": "36%", "key": "ballPossession" }] }] }],
  "lineups": { "confirmed": true, "home": { "formation": "4-2-3-1",
    "players": [{ "player": { "name": "David Raya", "position": "G" }, "statistics": { "rating": 7 } }] } },
  "incidents": [{ "incidentType": "period", "text": "FT", "homeScore": 3, "awayScore": 0, "time": 90 }],
  "odds": [{ "marketName": "Full time", "choices": [{ "name": "1", "fractionalValue": "1/5", "winning": true }] }],
  "votes": { "vote1": 110530, "voteX": 8116, "vote2": 7638 },
  "h2h": { "teamDuel": { "homeWins": 1, "awayWins": 0, "draws": 0 } },
  "url": "https://www.sofascore.com/event/16363633"
}
```

Each enrichment toggle nests SofaScore's native payload under a key of the same name (`statistics`, `lineups`, `incidents`, `odds`, `votes`, `h2h`). Enabling any of them fetches full match detail automatically. The same toggles work in `live`, `scheduled`, `tournament` and `url` modes.

#### `standings` — league table

```json
{ "mode": "standings", "uniqueTournamentId": 17, "standingsType": "total" }
```

```json
{
  "kind": "standings_row", "tournament": "Premier League", "uniqueTournamentId": 17,
  "standingsType": "total", "position": 1, "teamId": 17, "teamName": "Manchester City",
  "matches": 3, "wins": 3, "draws": 0, "losses": 0, "scoresFor": 7, "scoresAgainst": 2,
  "points": 9, "promotion": "Champions League",
  "url": "https://www.sofascore.com/football/team/manchester-city/17",
  "tournamentUrl": "https://www.sofascore.com/football/tournament/england/premier-league/17"
}
```

One row per team. Leave `seasonId` empty for the current season, or set it for a historical table. `standingsType` can be `total`, `home` or `away`.

Only leagues and group/league phases have a table. Pure knockout cups (Copa Argentina, US Open Cup, …) have no standings on SofaScore, so the run ends with a status message telling you so instead of crashing -- use `tournament` mode for their fixtures and results instead.

#### `tournament` — a league season's fixtures & results

```json
{ "mode": "tournament", "uniqueTournamentId": 17, "eventsSpan": "last", "maxPages": 3 }
```

Returns `event` rows for a whole league season — `eventsSpan: "last"` for played results, `"next"` for upcoming fixtures. Combine with the enrichment toggles for a full stats sweep of a competition.

#### `team` — team profile (+ optional squad)

```json
{ "mode": "team", "teamId": 42, "includeSquad": true }
```

```json
{
  "kind": "team", "id": 42, "name": "Arsenal", "country": "England",
  "primaryTournament": "Premier League", "managerName": "Mikel Arteta",
  "venue": "Emirates Stadium", "venueCapacity": 60704,
  "squad": [{ "id": 804508, "name": "Viktor Gyökeres", "position": "F", "jerseyNumber": "14" }],
  "url": "https://www.sofascore.com/football/team/arsenal/42",
  "team": { "…": "full native SofaScore team object nested here" }
}
```

#### `player` — player profile

```json
{ "mode": "player", "playerId": 804508 }
```

```json
{
  "kind": "player", "id": 804508, "name": "Viktor Gyökeres", "position": "F",
  "teamName": "Arsenal", "country": "Sweden", "height": 187, "preferredFoot": "Right",
  "marketValue": 61000000, "marketValueCurrency": "EUR",
  "url": "https://www.sofascore.com/player/viktor-gyokeres/804508",
  "player": { "…": "full native SofaScore player object nested here" }
}
```

#### `search` — resolve names to IDs

```json
{ "mode": "search", "searchQuery": "real madrid" }
```

```json
{ "kind": "search_result", "resultType": "team", "entityId": 2829, "entityName": "Real Madrid", "sport": "football" }
{ "kind": "search_result", "resultType": "player", "entityId": 826643, "entityName": "Kylian Mbappé", "teamId": 2829 }
```

#### `url` — paste any SofaScore link

```json
{ "mode": "url", "urls": [
  "https://www.sofascore.com/team/football/arsenal/42",
  "https://www.sofascore.com/player/viktor-gyokeres/804508"
] }
```

Match, team, player and tournament links are each routed to the right fetch and returned in their matching `kind` shape.

### Which leagues and sports does it cover?

`standings` and `tournament` mode take a `uniqueTournamentId`. These are the ones people
ask for most — all verified against SofaScore's own search endpoint:

| Competition | Sport | `uniqueTournamentId` |
|---|---|---|
| Premier League (England) | football | 17 |
| LaLiga (Spain) | football | 8 |
| Serie A (Italy) | football | 23 |
| Bundesliga (Germany) | football | 35 |
| Ligue 1 (France) | football | 34 |
| UEFA Champions League | football | 7 |
| UEFA Europa League | football | 679 |
| FIFA World Cup | football | 16 |
| NBA | basketball | 132 |
| NFL | american-football | 9464 |
| NHL | ice-hockey | 234 |
| Indian Premier League | cricket | 11165 |

Names repeat across sports and countries, so check the sport before you trust an ID:
`35` is the German football Bundesliga, `149` is the German *handball* Bundesliga. For
anything not in the table, run `search` mode with the competition name and read
`entityId` off the `uniqueTournament` result, or paste the league's SofaScore URL into
`url` mode.

`live` and `scheduled` mode take a `sport` slug instead. All 17 accepted values:
`football`, `basketball`, `tennis`, `ice-hockey`, `cricket`, `esports`, `motorsport`,
`handball`, `volleyball`, `baseball`, `american-football`, `rugby`, `futsal`,
`table-tennis`, `badminton`, `snooker`, `darts`.

### What does each input field do?

| Field | Type | Used by | Description |
|---|---|---|---|
| `mode` | select | all | `live`, `scheduled`, `event_detail`, `search`, `standings`, `tournament`, `team`, `player`, `url` |
| `sport` | select | live, scheduled | Sport slug (football, basketball, tennis, …) |
| `dateFrom` / `dateTo` | date | scheduled | `YYYY-MM-DD` range (inclusive) |
| `maxPages` | integer | scheduled, tournament | Pages to sweep |
| `eventIds` | array | event_detail | Match IDs to fetch |
| `searchQuery` | string | search | Team / player / tournament name |
| `urls` | array | url | SofaScore links to route |
| `uniqueTournamentId` | integer | standings, tournament | League ID (17 = Premier League) |
| `seasonId` | integer | standings, tournament | Optional; current season if empty |
| `standingsType` | select | standings | `total` / `home` / `away` |
| `eventsSpan` | select | tournament | `last` (results) / `next` (fixtures) |
| `teamId` | integer | team | Team ID |
| `includeSquad` | boolean | team | Also fetch the squad |
| `playerId` | integer | player | Player ID |
| `fetchEventDetails` | boolean | live, scheduled, tournament | Fan out to full match detail |
| `includeStatistics` / `includeLineups` / `includeIncidents` / `includeOdds` / `includeVotes` / `includeH2H` / `includeBestPlayers` | boolean | event modes | Per-match enrichments (auto-enable detail fetch) |
| `bestPlayersSummary` | boolean | event modes | Condensed best-players form; also names the player of the match |
| `oddsProviderId` | integer | event modes | Which bookmaker's odds (default `1`, SofaScore's regional pick) |
| `oddsScope` | select | event modes | `all` markets, or `featured` headline prices only |
| `includeTopPlayers` / `includeTopTeams` | boolean | standings | Season leaderboards for the same league and season |
| `topStatCategories` | array | standings | Limit leaderboards to e.g. `goals`, `assists`; empty = every ranked category |
| `includeSeasonStatistics` | boolean | team, player | Aggregate season totals (needs `uniqueTournamentId`) |
| `includeEntityEvents` | boolean | team, player | That team's or player's own matches, paged |
| `entityEventsSpan` | select | team, player | `last` / `next` / `both` (players have past matches only) |
| `includeNearEvents` | boolean | team | Previous and next match in one request |
| `includeUniqueTournaments` | boolean | team, player | Competitions the entity appears in, with their IDs |
| `includeTournamentMetadata` | boolean | tournament | One row describing the competition itself |
| `listRounds` | boolean | tournament | One row per round, with names and slugs |
| `tournamentRound` / `tournamentRoundSlug` | string | tournament | Fetch a single matchday or knockout stage |
| `searchEntityType` | select | search | `all`, `teams`, `players`, `managers`, `venues`, `tournaments` |
| `searchScopeSport` | boolean | search | Scope a team search to the chosen sport |
| `dateDiscoveryOnly` | boolean | scheduled | Summary + category rows instead of every match |
| `maxItems` | integer | all | Stop after N rows (`0` = unlimited) |
| `requestDelaySecs` | number | all | Delay between API calls |
| `proxyConfiguration` | object | all | Residential proxy on by default (see below) |

### What does a run cost?

Pay-per-result: you are charged for the rows a run actually delivers, and for nothing
else. **The live prices are on this Actor's [Pricing tab](https://apify.com/rl1987/sofascore-api-scraper),
which is generated from the billing config** — including the rung that applies to your own
Apify plan. They are deliberately not repeated here: prices are tiered by plan and change
on a notice period, so a figure written into this page is a second copy that goes stale
without anyone noticing.

What you are billed **for**:

- **Result row** — a row that costs its own request: a match, full match detail, a search
  hit, a team or player profile, a league-table entry, a fixture.
- **Bulk row** — a row from a set that arrives in one request: a season leaderboard entry,
  a competition a team plays in, a round, a competition active on a date. One request
  delivers hundreds of them, so a bulk row is priced far below a result row.
- **Add-on** — each per-match enrichment (`statistics`, `lineups`, `incidents`, `odds`,
  `votes`, `h2h`, `bestPlayers`), and each aggregate season stat set.

**You are only charged for an enrichment that actually arrived.** A fixture with no odds
posted yet, or a match with no lineups announced, is still fetched and reported in the row
as empty — but it is not billed.

Every **paid** Apify plan pays less per row than the free plan, and the discount deepens
with the plan. From **24 October 2026** this Actor also absorbs platform compute and proxy
usage instead of billing it to you on top, so the price on the Pricing tab is the whole
price; before that date, standard Apify platform usage applies as well. Apify notifies you
before any price change takes effect.

Use `maxItems` / `maxPages`, and enable only the enrichments you need, to cap spend on wide sweeps.

### How do I keep runs fast and cheap?

- Run `search` once to grab the IDs you need, or skip IDs entirely with `url` mode.
- For a fast overview, leave enrichments off; switch them on only when you need the depth.
- `page=1` is the first page of scheduled events for a date — `page=0` always returns empty (an undocumented API quirk).
- Residential proxy is enabled by default because the API is fronted by Cloudflare and blocks datacenter IPs; leave it on unless you're running from an IP Cloudflare already trusts.
- Schedule the Actor (hourly/daily) via Apify **Schedules** for always-fresh data.

### What do these SofaScore terms mean?

- **`uniqueTournamentId`** — SofaScore's stable numeric id for a *competition* (the
  Premier League as an institution). A `tournamentId` in a raw payload can be a single
  season's instance; the unique id is the one this Actor takes as input.
- **`seasonId`** — one edition of that competition. Leave it empty and the Actor resolves
  the current season; set it for a historical table or a past season's fixtures. Every
  `event` row carries the `seasonId` it belongs to, so you can read past ids off a result.
- **`kind`** — added by this Actor (not SofaScore) to every row, naming the row's shape:
  `event`, `event_detail`, `standings_row`, `team`, `player`, `search_result`.
- **`statusType`** — SofaScore's status bucket, passed through unchanged: `notstarted`,
  `inprogress`, `finished`, `postponed`, `canceled`, `interrupted`. `statusDescription` is
  the human label next to it ("2nd half", "FT").
- **`standingsType`** — `total` is the full league table; `home` and `away` are the same
  table computed from home-only or away-only results.
- **Enrichment** — one extra per-match API call for depth SofaScore does not put in the
  fixture list: `statistics`, `lineups`, `incidents`, `odds`, `votes` or `h2h`.
- **xG (expected goals)** — a shot-quality model score that appears inside the
  `statistics` payload; it estimates how many goals an average team would score from the
  chances taken.
- **Head-to-head (`h2h`)** — the historical win/draw/loss record between the two teams in
  this fixture.
- **Votes** — SofaScore users' pre-match 1 / X / 2 poll tallies, not a bookmaker's line.

### FAQ

**Do I need a SofaScore account, login or API key?** No. The Actor calls SofaScore's
public, unauthenticated backend endpoints — there is nothing to register and no key to
paste. An Apify account is all you need.

**What exactly is in one row?** It depends on the mode, and every row says which shape it
is in its `kind` field. An `event` row is one match flattened to a single level: `id`,
`slug`, `startTimestamp`, `sport`, `tournament`, `uniqueTournament`,
`uniqueTournamentId`, `seasonId`, `category`, `country`, `round`, `roundName`, both teams'
`…TeamId` / `…Team` / `…TeamSlug` / `…TeamCountry`, `homeScore`, `awayScore`, `statusCode`,
`statusType`, `statusDescription`, `venue`, `venueCity`, `referee` and `url`.

**Can I get match statistics and lineups, not just the scoreline?** Yes — that is what the
enrichment toggles are for, and they work in `live`, `scheduled`, `tournament`, `url` and
`event_detail` mode. Each one nests SofaScore's own payload under a key of the same name.

**Can I get past seasons, or only the current one?** Past seasons too. Set `seasonId` on
`standings` or `tournament` mode; leave it empty and you get the current season.

**Can I schedule it and pull the data into my own system?** Yes. Use Apify **Schedules**
for hourly or daily runs, and the Apify API or a webhook to collect each run's dataset —
or export manually to JSON, CSV or Excel from the **Dataset** tab.

**What happens when something goes wrong?** Nothing crashes out silently. An id SofaScore
has no data for, a missing required field, or a knockout cup with no league table ends the
run with a status message explaining which input was wrong. A single page or enrichment
that fails after retries is logged as a warning and the run keeps everything else it
collected, rather than throwing the whole dataset away.

**How do I get live football scores via an API?** Set **Mode** to `live` and **Sport** to
`football`, and run it. Each row is one in-play match with its score, status and minute.
Schedule it every few minutes and pull each run's dataset from the Apify API for a
continuously updated feed.

**How do I get league standings?** Set **Mode** to `standings` and **Tournament ID** to the
competition — 17 is the Premier League. Leave **Season ID** empty for the current season. Add
**Season leaderboards** to get the top scorers and assist leaders alongside the table.

**How do I find the top scorer in a league this season?** `standings` mode with **Season
leaderboards: top players** switched on. One request returns every category the competition
ranks — goals, assists, rating, expected goals and the rest — as one row per player per
category, with `statCategory`, `rank` and `statValue`.

**How do I get one team's fixtures and results?** `team` mode with **Team/player own fixtures
& results**. That returns their matches directly, instead of pulling a whole league season and
filtering it client-side. **Previous and next match** answers "what's next" in one request.

**How do I get the fixtures for one matchday or cup round?** `tournament` mode with **List the
season's rounds** to see what the season has, then **Single round** to fetch just that one.
Knockout stages come back as named stages, so a quarter-final is labelled as one.

**How do I find a team's or player's SofaScore ID?** `search` mode, with **Search: entity
type** set to Teams or Players. It is paged, so a common name is not truncated at 20 results.
Managers and venues are searchable the same way and are not available any other way.

**Which competitions does a team play in?** `team` mode with **Competitions the team/player
appears in**. Each row carries a `uniqueTournamentId` you can feed straight into `standings`,
`tournament` or the season-statistics inputs.

**How do I avoid downloading every match in the world for a date?** `scheduled` mode with
**Date discovery only**. It returns one summary row per date plus one row per competition
category with its match count, so you can see that, say, 780 of that day's football matches
are Italian amateur fixtures before you pay for any of them.

**Is this an official SofaScore API?** No. SofaScore does not license API access, so treat
this as an unofficial integration of a public, unauthenticated endpoint
(`access-control-allow-origin: *`, no login). It is provided for research and legitimate
data-integration use, and you are responsible for complying with SofaScore's Terms of
Service in your jurisdiction.

Found a bug or need a custom field or endpoint? Open an issue in the Actor's **Issues** tab.

### Did you find this useful?

Rate this Actor on Apify! Your feedback helps other users find it and helps us keep improving it.

# Actor input Schema

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

What to scrape. Pick a mode, then fill in the matching section below.

## `sport` (type: `string`):

SofaScore sport. Used by 'Live events' and 'Scheduled events' modes.

## `dateFrom` (type: `string`):

Start date for 'Scheduled events' mode. Defaults to today.

## `dateTo` (type: `string`):

End date for 'Scheduled events' mode, inclusive. Defaults to dateFrom.

## `dateDiscoveryOnly` (type: `boolean`):

On mode='scheduled'. Instead of paging every match on each date, return one summary row per date plus one row per competition category that has matches. Use it to find out whether a date is worth scraping, or which competitions are active, before committing to a full sweep — rows are the billed unit, so this is a cost question as much as a speed one.

## `eventIds` (type: `array`):

SofaScore event IDs to fetch full detail for. Add one ID per line.

## `searchQuery` (type: `string`):

Free-text query (team, player, tournament). Returns matches with their SofaScore IDs.

## `searchEntityType` (type: `string`):

On mode='search'. 'Everything' is the old behaviour: one unpaged mixed call, capped at about 20 results. Pick a type to get paged results of just that kind — and note that managers and venues appear in no other way, as the mixed search never returns them.

## `searchScopeSport` (type: `boolean`):

Only for the 'Teams' search type: restricts matches to the sport set above, which is useful for a name that exists in several sports.

## `uniqueTournamentId` (type: `integer`):

SofaScore uniqueTournament ID (e.g. 17 = Premier League, 8 = LaLiga, 23 = Serie A). Find it via 'Search' mode or a tournament page URL.

## `seasonId` (type: `integer`):

Optional season ID. Leave empty to use the current season automatically.

## `standingsType` (type: `string`):

Which table to return in 'League table (standings)' mode.

## `eventsSpan` (type: `string`):

For 'League fixtures & results (tournament)' mode: past results or upcoming fixtures.

## `includeTournamentMetadata` (type: `boolean`):

On mode='tournament'. Adds one row describing the competition itself — name, category, country and current season — so a dataset whose rows all carry a tournament id also says what that tournament is.

## `listRounds` (type: `boolean`):

On mode='tournament'. Emits one row per round with its number, name and slug, and flags the current round. This is the discovery call for 'Single round' below; in a knockout the rounds are named stages a flat fixture list cannot distinguish.

## `tournamentRound` (type: `string`):

On mode='tournament'. Fetch just this round — matchday 12, or a cup stage — instead of walking the whole season chronologically. Mutually exclusive with 'Which fixtures': asking for one round returns that round only. Use 'List the season's rounds' first to see what exists.

## `tournamentRoundSlug` (type: `string`):

Some knockout stages share a round number between legs and are told apart by slug, e.g. 'quarterfinals'. Only needed if a round number alone returns the wrong tie or nothing.

## `teamId` (type: `integer`):

SofaScore team ID. Find it via 'Search' mode or a team page URL.

## `includeSquad` (type: `boolean`):

Also fetch the full squad (players) and nest it on the team row.

## `includeTopPlayers` (type: `boolean`):

On mode='standings'. Adds season player leaderboards for the same league and season — rating, goals, assists, expected goals and every other category SofaScore ranks. One row per player per category; a Premier League season is 32 categories, about 1,300 rows. From 24 October 2026 these are billed as bulk rows at $0.40/1,000 rather than full result rows.

## `includeTopTeams` (type: `boolean`):

On mode='standings'. Adds season team leaderboards — average rating, goals scored and conceded, big chances and the rest. 34 categories, about 650 rows on a Premier League season, billed as bulk rows from 24 October 2026.

## `topStatCategories` (type: `array`):

Limit the leaderboards to these stat categories, e.g. goals, assists, rating. Leave empty for every category the league ranks, which on a Premier League season is about 1,950 rows across both boards. Player and team boards use different category names — players rank on goals/assists/rating, teams on goalsScored/avgRating.

## `includeSeasonStatistics` (type: `boolean`):

On mode='team' or mode='player'. Adds one row of that entity's aggregate statistics for a season. Requires uniqueTournamentId as well, because these totals are per competition — set seasonId too, or the current season is used.

## `includeEntityEvents` (type: `boolean`):

On mode='team' or mode='player'. Adds that team's or player's own matches, paged, instead of making you walk a whole tournament season and filter it. Uses the run's maxPages and maxItems budgets. Players only have past matches.

## `entityEventsSpan` (type: `string`):

Past results, upcoming fixtures, or both. Only applies with 'Team/player own fixtures & results'. Players have no upcoming-matches endpoint, so 'next' and 'both' fall back to past matches for them.

## `includeNearEvents` (type: `boolean`):

On mode='team'. Answers "what did they just play and what is next" in a single request, with no paging. Emits up to two rows.

## `includeUniqueTournaments` (type: `boolean`):

On mode='team' or mode='player'. Lists the competitions this entity plays in, with their tournament ids — the route to the uniqueTournamentId that the season-statistics inputs need.

## `playerId` (type: `integer`):

SofaScore player ID. Find it via 'Search' mode or a player page URL.

## `urls` (type: `array`):

Paste SofaScore links (matches, teams, players, tournaments). Each is routed to the right fetch automatically. One URL per line.

## `fetchEventDetails` (type: `boolean`):

For 'Live'/'Scheduled'/'Tournament' modes, fan out and fetch full match detail (GET /event/{id}) for every event found instead of pushing the list item as-is. Multiplies request count. (Enabling any enrichment below turns this on automatically.)

## `includeStatistics` (type: `boolean`):

Nest per-match statistics (possession, shots, passes, etc.) on each event row. Fetches full match detail per event.

## `includeLineups` (type: `boolean`):

Nest starting lineups, formations and per-player match ratings on each event row.

## `includeIncidents` (type: `boolean`):

Nest match incidents (goals, cards, substitutions, period markers) on each event row.

## `includeOdds` (type: `boolean`):

Nest pre-match betting markets and odds on each event row.

## `includeBestPlayers` (type: `boolean`):

Adds the match's standout players with their ratings — the per-match counterpart to the season leaderboards. Nothing else in this Actor says who actually played well.

## `bestPlayersSummary` (type: `boolean`):

Fetch the condensed form instead, which also names the player of the match. Only applies with 'Best players'.

## `oddsProviderId` (type: `integer`):

Which bookmaker's odds to fetch. 1 is whatever SofaScore serves your region and stays the default, so existing runs are unchanged. Set this to pin a specific provider — previously the 1 was hardcoded, with no way to ask for another and no way out if provider 1 stopped being served.

## `oddsScope` (type: `string`):

The full markets payload is large and most callers want the headline prices. 'All markets' is the existing behaviour.

## `includeVotes` (type: `boolean`):

Nest the crowd win/draw/win vote tallies on each event row.

## `includeH2H` (type: `boolean`):

Nest the head-to-head summary between the two teams on each event row.

## `maxPages` (type: `integer`):

Pages to sweep per day ('Scheduled') or per league season ('Tournament'). Scheduled pagination is 1-indexed; the scraper stops early once a page returns no events.

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

Stop after pushing this many dataset items. 0 = unlimited.

## `requestDelaySecs` (type: `number`):

Small delay between outgoing API calls to stay polite to Cloudflare-fronted api.sofascore.com.

## `proxyConfiguration` (type: `object`):

Cloudflare fronts api.sofascore.com and appears to block Apify's datacenter IP range outright, so residential proxy is enabled by default. You can disable it if running from an IP Cloudflare already trusts.

## Actor input object example

```json
{
  "mode": "live",
  "sport": "football",
  "dateDiscoveryOnly": false,
  "eventIds": [],
  "searchEntityType": "all",
  "searchScopeSport": false,
  "standingsType": "total",
  "eventsSpan": "last",
  "includeTournamentMetadata": false,
  "listRounds": false,
  "includeSquad": false,
  "includeTopPlayers": false,
  "includeTopTeams": false,
  "topStatCategories": [],
  "includeSeasonStatistics": false,
  "includeEntityEvents": false,
  "entityEventsSpan": "last",
  "includeNearEvents": false,
  "includeUniqueTournaments": false,
  "urls": [
    "https://www.sofascore.com/team/football/arsenal/42"
  ],
  "fetchEventDetails": false,
  "includeStatistics": false,
  "includeLineups": false,
  "includeIncidents": false,
  "includeOdds": false,
  "includeBestPlayers": false,
  "bestPlayersSummary": false,
  "oddsProviderId": 1,
  "oddsScope": "all",
  "includeVotes": false,
  "includeH2H": false,
  "maxPages": 3,
  "maxItems": 0,
  "requestDelaySecs": 0.3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset rows produced by the run (events or search results, one flat row per item).

# 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 = {
    "urls": [
        "https://www.sofascore.com/team/football/arsenal/42"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("rl1987/sofascore-api-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 = { "urls": ["https://www.sofascore.com/team/football/arsenal/42"] }

# Run the Actor and wait for it to finish
run = client.actor("rl1987/sofascore-api-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 '{
  "urls": [
    "https://www.sofascore.com/team/football/arsenal/42"
  ]
}' |
apify call rl1987/sofascore-api-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rl1987/sofascore-api-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/62hJll1LuUdPyxpbG/builds/hckMQMnCavYqxycdi/openapi.json
