Sofascore League Standings & Tables Scraper avatar

Sofascore League Standings & Tables Scraper

Pricing

from $1.50 / 1,000 standings rows

Go to Apify Store
Sofascore League Standings & Tables Scraper

Sofascore League Standings & Tables Scraper

Scrape league tables and standings from Sofascore for football, basketball, ice hockey, baseball and more. One row per team, with position, played, W/D/L, points, goal difference and promotion or relegation status. Handles group stages. No API key and no proxy needed.

Pricing

from $1.50 / 1,000 standings rows

Rating

0.0

(0)

Developer

Elena Vance

Elena Vance

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Scrape league tables from Sofascore for football, basketball, ice hockey, baseball and more — one row per team, ready to open in Excel or feed into a spreadsheet.

No API key. No login. No residential proxy. Runs on the Apify free plan.


What you get

One dataset row per team per table, with a stable column set across every sport:

TournamentSeasonGroupPosTeamPWDLPtsGDPromotion
Premier League26/271Arsenal11003+4Champions League
Premier League26/2720Wolverhampton10010−4Relegation
FIFA World Cup2026Group A1Mexico000000
NBA26/271Oklahoma City0000

Group-stage competitions (World Cup groups, MLB divisions, NHL conferences) fill the group column. A single-table league leaves it empty.

What makes this different

  • Built for league tables, not bolted on. Where other Sofascore Actors offer standings at all, it is a checkbox inside a broad multi-mode scraper. Here it is the product: the input, the schema and the pricing are all shaped around one row per team per table.
  • Nested tables come back whole. The NHL returns its league table, both conferences and all four divisions — 96 rows from 32 teams — and group stages fill a group column. Set groupScope to overall to keep only the top table and bill 32 rows instead.
  • One column set across every sport, so a spreadsheet built against a football table works unchanged for basketball, ice hockey and baseball.
  • Off-season is reported, not faked. A competition with no table yet succeeds with a status message saying so and bills nothing beyond the start event, instead of returning an empty run you have to diagnose.
  • A $0.00005 start fee, against up to $0.08 on comparable Actors. For a run that fetches one table, that is the whole price difference.

Input

FieldDescription
tournamentsRequired. Sofascore tournament URLs or numeric IDs. Paste the URL straight from your browser.
seasonIdOptional. Defaults to the latest season. A season pinned in a URL's #id: fragment wins over this.
standingsTypestotal (default), home, away. Each adds one request per tournament.
groupScopeall (default) or overall — see Overlapping tables.
seasonFallbackDefault on — see Off-season behaviour.
maxItemsStop after this many rows.
proxyConfigurationOptional. Only needed to pin a country or a specific proxy.
{
"tournaments": [
"https://www.sofascore.com/tournament/football/england/premier-league/17",
132
],
"standingsTypes": ["total"]
}

Some IDs to start from: 17 Premier League · 8 LaLiga · 23 Serie A · 35 Bundesliga · 34 Ligue 1 · 7 Champions League · 242 MLS · 132 NBA · 234 NHL · 11205 MLB · 16 FIFA World Cup.

Sport coverage

Verified against live data across 14 competitions:

SportTableSport-specific columns
Footballpoints, scoresFor/scoresAgainst, goalDifference, promotion
Basketballpercentage, gamesBehindno points
Ice hockeypoints, overtimeLosses, normaltimeLosses
Baseballpercentage, gamesBehind — no draws
TennisA draw is not a table; there is nothing to return
Pure knockout cupsNo table until a league/group phase exists

Columns a sport doesn't use are null, never missing — so the CSV keeps the same header everywhere.

Overlapping tables

Some leagues return several nested tables at once. The NHL sends the league table plus 2 conferences plus 4 divisions, so 32 teams produce 96 rows — the same team three times, at a different position in each. MLB does the same (9 tables, 90 rows for 30 teams).

Those are real, distinct standings, not duplicates. But if you only wanted the league table, set groupScope to overall:

Leaguealloverall
NHL96 rows32 rows
MLB90 rows30 rows
Premier League20 rows20 rows (already one table)
FIFA World Cup60 rows60 rows (groups don't overlap)

overall keeps the one table that contains every team. Where no such table exists — a group stage, where the groups split the teams rather than nesting — nothing is dropped and the run says so.

Either way the run logs which choice you got and what the other would have returned.

Off-season behaviour

Sofascore lists a season as soon as it is scheduled, but a table only exists once it has started. Measured on 2026-08-24, the Champions League and the NHL both had no table for 2026/27 while 2025/26 was complete.

With seasonFallback on (the default), the Actor returns the previous season's table instead of nothing and records what happened:

  • seasonId / seasonYear — the season the rows actually came from
  • seasonRequested — set only when a fallback happened

So you can always tell "here is 26/27" from "26/27 hasn't started, here is 25/26". Turn the toggle off to get an empty result instead.

Notes

  • A competition with no table is reported in the run's status message, not as a failure — it is a real answer.
  • A run where every request failed fails loudly rather than finishing green with an empty dataset.
  • Requests go directly to Sofascore. A proxy IP is only fetched if a request is actually blocked, and then a datacenter IP (included in every Apify plan) is tried before any residential one.

The Sofascore Actor suite

Six Actors from the same publisher, built on one shared HTTP layer and one ID space — so the output of one is the input of the next.

ActorWhat it returns
Live Scores & FixturesFixtures and live results by date across 19 sports. Emits eventId.
Match Stats, xG & LineupsPer-match shotmaps with pitch coordinates, lineups, ratings, momentum. Takes eventId.
League Standings & TablesThis Actor.
Team & Player DataSquads, bios, market values, transfers, match logs. Takes team and player IDs.
Season StatsSeason leaderboards and complete team statistics. Takes uniqueTournamentId.
Rankings & SearchFIFA, ATP/WTA, UEFA and UFC tables, plus name-to-ID search.

How they chain. Live Scores emits the eventId that Match Stats takes. Rankings' search turns a name into the team, player and tournament IDs the other five accept. Standings and Season Stats share uniqueTournamentId, and Team & Player emits that same ID as primaryTournamentId.

All six need no API key, no login and no headless browser; none requires a residential-proxy add-on, and all run on the Apify free plan.

Development

python -m venv .venv && .venv/bin/pip install -r requirements.txt -r requirements-dev.txt
.venv/bin/python -m pytest # unit tests, no network
.venv/bin/python -m src # local run, reads storage/key_value_stores/default/INPUT.json

See docs/architecture.md for how the transport and season resolution work, and docs/ci-cd.md for the pipeline.