Sofascore Team & Player Data Scraper avatar

Sofascore Team & Player Data Scraper

Pricing

from $2.50 / 1,000 player records

Go to Apify Store
Sofascore Team & Player Data Scraper

Sofascore Team & Player Data Scraper

Scrape football, basketball and hockey clubs and athletes from Sofascore. Squads with market values and contracts, player bios, radar attributes, transfer history, match logs with ratings and full season statistics. Expand a club into every player in one run. No API key, no login.

Pricing

from $2.50 / 1,000 player records

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

Scrapes clubs and athletes from Sofascore's public API — squads with market values and contracts, player bios, radar attributes, transfer history, match logs with per-match ratings and full season statistics. Paste a team URL and get the club plus every player in it.

No API key, no login, no browser, and no proxy unless a request is actually blocked.

What you get

One dataset row per team or player. An entityType column says which.

Team rows — name, country, founded year, manager, stadium with capacity and coordinates, club colours, main competition, plus (optionally) the full squad, transfers in and out, recent results, upcoming fixtures, the competition-season catalogue, and season statistics.

Player rows — name, position, shirt number, height, weight, preferred foot, date of birth and age, contract expiry, market value, current club and the competition it plays in, plus (optionally) radar attributes, career transfers, a match log carrying their rating and minutes for each game, national-team caps and season statistics.

What makes this different

  • Squad expansion: one club in, every player out. Paste a team URL and get the club row plus a full record for each player in the squad, in a single run, without collecting player IDs by hand first.
  • A 28-man squad is one team charge, not 28. The per-player charge applies only to players expanded into their own full records.
  • Market values, contract expiry and transfer history, alongside radar attributes and a match log carrying each player's rating and minutes per game.
  • primaryTournamentId on every row — the same ID the Standings and Season Stats Actors take as input, so a team row chains straight into them.
  • Season statistics are bounded before the run. "All seasons" multiplies per competition and a top player has 19 of them, so maxSeasons caps the cost up front rather than surprising you afterwards.

Input

FieldTypeDefaultNotes
teamsarrayTeam IDs or Sofascore team URLs
playersarrayPlayer IDs or Sofascore player URLs
includeSquadbooltrueTeams only
includeResultsbooltrueLast 30 matches; players get their own rating per match
includeTransfersbooltrueClub ins/outs, or a player's career moves
includeAttributesbooltrueRadar percentiles. Players, football only
includeFixturesboolfalseNext 30 matches. Teams only
includeCompetitionsboolfalseEvery competition-season, with the IDs to fetch them
includeStatisticsboolfalseExpensive — one request per season
includeNationalTeamboolfalseCaps, goals, debut. Players, football only
includeCharacteristicsboolfalseUnlabelled style codes — see below
expandSquadboolfalseScrape every squad player as a full record too
seasonScopeenumlatestlatest or all
maxSeasonsint5Cap for seasonScope: all
maxEventPagesint130 matches per page
maxItemsint100Total records, squad expansion included
proxyConfigurationobjectoffOnly to pin a specific proxy

At least one of teams or players is required. A URL is read as whatever it says it is, so a player URL pasted into the team box still works.

Both URL spellings parse:

https://www.sofascore.com/football/team/manchester-city/17 # current
https://www.sofascore.com/team/football/manchester-city/17 # older, 301s
https://www.sofascore.com/football/player/erling-haaland/839956

Squad expansion

expandSquad is what turns this from a lookup into a database: after scraping a club, every player in its squad is queued as a full player record. One Premier League club becomes about 28 records. It is bounded by maxItems, deduplicated (clubs in one league share loan players), and off by default, because it multiplies both the run time and the bill by the size of a squad.

Sport coverage

Every sport Sofascore covers has teams and players, but they do not carry the same fields. Nothing is dropped or faked — a field a sport does not report simply arrives as null.

FieldFootballBasketball
Name, position, height, date of birth, country
First / last name split
Preferred foot, market value
Weight, salary, roster status
Radar attributes (attributes)❌ 404
National-team record
Season statisticsoverallregularSeason

That last row is the one to know about. Whether a competition's statistics are called overall or regularSeason is a property of the competition, not of the sport — the same basketball player has regularSeason for the NBA and overall for FIBA EuroBasket. Player records read the right spelling out of Sofascore's own typesMap; team records probe for it once per competition-season and cache the answer for the rest of the run. Either way the statisticsType field on each block records which was used.

Season statistics

Off by default, because they cost a discovery request plus one request per season. With seasonScope: latest that is one season — the newest of the team's or player's main competition. With all it walks every competition they have played in, newest first, capped by maxSeasons.

Sofascore lists a season as soon as it is scheduled but only publishes statistics once it has started, so in the summer the newest entry is routinely empty. latest falls back to the two previous seasons of the same competition rather than returning nothing, and the seasonId / seasonYear on each block says which season you actually got.

Notes

  • Playing-style codes are unlabelled. Sofascore used to send {"type": 1, "name": "Finishing", "level": 3} and now sends {"type": 5, "rank": 16}. The labels are gone and there is no published mapping, so includeCharacteristics is off by default and ships the raw codes rather than pretending to know what they mean.
  • Invalid input does not fail the run. A mistyped ID is recorded as an unbilled {"error": "INVALID_INPUT"} row with an explanation, and the run finishes green. One bad entry in a list never costs the good ones.
  • A run where every request failed does fail, loudly, with the real error — rather than finishing green with an empty dataset.

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 DataThis Actor.
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-dev.txt
.venv/bin/python -m pytest -q # 144 tests, no network
apify run # needs storage/key_value_stores/default/INPUT.json

See docs/architecture.md for how it works, docs/ci-cd.md for the pipeline, and docs/publishing.md for the Store listing.