Sofascore Season Stats Scraper avatar

Sofascore Season Stats Scraper

Pricing

from $1.50 / 1,000 player leaderboard rows

Go to Apify Store
Sofascore Season Stats Scraper

Sofascore Season Stats Scraper

Scrape season leaderboards and team statistics from Sofascore for football, basketball and ice hockey. Top scorers, assists, ratings and 30 more statistics per league, plus a complete team table and knockout brackets. No API key, no login.

Pricing

from $1.50 / 1,000 player leaderboard rows

Rating

0.0

(0)

Developer

Elena Vance

Elena Vance

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

16 hours ago

Last modified

Share

Season leaderboards and team statistics from Sofascore, for any competition it covers. Top scorers, assist leaders and match ratings; a complete team table with every statistic the league publishes; and the knockout bracket where there is one.

No API key, no login, no browser. Calls Sofascore's own JSON API directly and only reaches for a proxy if a request is actually blocked.

What you get

Three row types in one dataset, told apart by the recordType column.

playerLeaderboard — one row per player per statistic, ranked. Football publishes 34 leaderboards (goals, assists, rating, expected goals, key passes, tackles, kilometres covered, top speed, saves…), basketball 24 (points, rebounds, triple-doubles, true shooting, player efficiency…) and ice hockey 21 (points, save percentage, time on ice, power-play goals…). Each row carries the rank, the value, the appearances behind it, the player and the club they played for.

teamStats — one row per team with every team statistic merged into one object: goals scored and conceded, expected goals, possession, passing accuracy, corners, cards for football; offensive and defensive rating, pace, true shooting for basketball. This is not a top-N cut — every team in the competition is there, so a Premier League run is twenty complete rows.

cupBracket — one row per tie: round, both teams, the aggregate result and who went through. Cups, tournament knockout stages and play-off leagues have one; the NBA returns its fifteen-tie play-off bracket. Round-robin leagues decided on points return nothing.

What makes this different

  • Around thirty ranked tables merged into one row per team. Sofascore publishes team statistics as dozens of separate leaderboards; this Actor fetches them all and joins them, so a season arrives as one table you can open rather than thirty you have to reconcile yourself.
  • Not a top-N cut. Every team in the competition gets a row — 20 for a Premier League season, 30 for the NBA, 32 for the NHL.
  • 34 football leaderboards, 24 basketball, 21 ice hockey, each row carrying the rank, the value, the appearances behind it and the club the player played for.
  • Knockout brackets where a competition has one — round, both teams, the aggregate result and who advanced. Round-robin leagues return nothing and are never charged for it.
  • Failures are never billed, and unusable input returns an unbilled diagnostic row rather than failing the run.

Input

FieldTypeDefaultWhat it does
tournamentsarraySofascore tournament URLs or unique-tournament IDs. 17 = Premier League, 132 = NBA, 234 = NHL, 7 = Champions League.
seasonIdintegerlatestWhich season. A #id: fragment in a pasted URL wins over this.
seasonFallbackbooleantrueUse the previous season when the newest one has been scheduled but not played.
includePlayerLeaderboardsbooleantrueThe ranked player tables.
includeTeamStatsbooleantrueThe complete team table.
includeCupBracketbooleanfalseThe knockout bracket.
playerCategoriesarrayrating, goals, assistsWhich leaderboards to keep, or ["all"]. This is the setting that decides the size of your bill.
topNinteger50Keep the top N of each leaderboard. 50 is Sofascore's maximum.
statisticsTypesarrayautoLeave empty. Set it only to reach a table the automatic choice skips — see below.
maxItemsinteger10000Stop after this many rows.
proxyConfigurationobjectoffOnly needed if your IP is blocked.

Minimal input:

{ "tournaments": ["https://www.sofascore.com/tournament/football/england/premier-league/17"] }

What a run costs

Requests are fixed and small — the whole 34-category table arrives in one call, so a competition-season is two to five requests whatever you ask for. What varies is the row count, and playerCategories is the dial:

InputPlayer rowsTeam rows
Default three categories15020
["goals", "assists"]10020
["all"]1,56020

Sport coverage

Verified against the live API for football, basketball and ice hockey, across the Premier League, the Champions League, the NBA, the NHL and the World Cup. Tennis and other individual sports have no team or squad concept and publish no leaderboards here. Baseball has none at all — Sofascore returns nothing for MLB, which the Actor reports rather than failing.

The two things that are not obvious

Statistics have a type, and it belongs to the competition. Football spells it overall; the NBA and NHL answer 404 for that and want regularSeason, and the NBA publishes playoffs as a separate table. Sofascore has no endpoint that says which — so the Actor probes for it and remembers the answer per competition, which is why a multi-league run doesn't pay for it repeatedly. Set statisticsTypes yourself only to reach a table the probe skips: pinning ["regularSeason", "playoffs"] returns both NBA tables in one run.

A "latest" season is often empty. Sofascore lists a season as soon as it is scheduled, but statistics appear only once matches have been played. Measured in late August 2026, the NBA, NHL and Champions League all returned nothing for their newest season while the previous one was complete. With seasonFallback on (the default) the Actor walks back up to two seasons and records what it used in seasonYear; seasonRequested is filled in only when a fallback happened, so you can always tell.

Notes

  • Player leaderboards are a top-50 cut, team tables are not. That is why the two have different row shapes: 381 Premier League players spread over 34 leaderboards fill 12% of the cells a pivoted table would need, so pivoting them would imply a striker made no tackles when he is simply outside the top 50. Team tables cover every team in every category, so they pivot losslessly.
  • A category that doesn't exist for a sport (goals in basketball) is reported in the log along with the full list of the ones that do, rather than failing the run.
  • Bad input is recorded as an unbilled INVALID_INPUT row rather than crashing the run.

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 & TablesLeague tables, group stages, conferences and divisions. Takes uniqueTournamentId.
Team & Player DataSquads, bios, market values, transfers, match logs. Takes team and player IDs.
Season StatsThis Actor.
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

pip install -r requirements-dev.txt
pytest # 131 tests, no network
npx apify-cli@1 validate-schema
apify run # needs storage/key_value_stores/default/INPUT.json

docs/architecture.md covers how the client, season resolution and billing fit together; docs/ci-cd.md the GitHub Actions pipeline; docs/publishing.md the Apify Store listing and pricing.