Sofascore Team & Player Data Scraper
Pricing
from $2.50 / 1,000 player records
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
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.
primaryTournamentIdon 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
maxSeasonscaps the cost up front rather than surprising you afterwards.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
teams | array | — | Team IDs or Sofascore team URLs |
players | array | — | Player IDs or Sofascore player URLs |
includeSquad | bool | true | Teams only |
includeResults | bool | true | Last 30 matches; players get their own rating per match |
includeTransfers | bool | true | Club ins/outs, or a player's career moves |
includeAttributes | bool | true | Radar percentiles. Players, football only |
includeFixtures | bool | false | Next 30 matches. Teams only |
includeCompetitions | bool | false | Every competition-season, with the IDs to fetch them |
includeStatistics | bool | false | Expensive — one request per season |
includeNationalTeam | bool | false | Caps, goals, debut. Players, football only |
includeCharacteristics | bool | false | Unlabelled style codes — see below |
expandSquad | bool | false | Scrape every squad player as a full record too |
seasonScope | enum | latest | latest or all |
maxSeasons | int | 5 | Cap for seasonScope: all |
maxEventPages | int | 1 | 30 matches per page |
maxItems | int | 100 | Total records, squad expansion included |
proxyConfiguration | object | off | Only 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 # currenthttps://www.sofascore.com/team/football/manchester-city/17 # older, 301shttps://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.
| Field | Football | Basketball |
|---|---|---|
| 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 statistics | overall | regularSeason |
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, soincludeCharacteristicsis 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.
| Actor | What it returns |
|---|---|
| Live Scores & Fixtures | Fixtures and live results by date across 19 sports. Emits eventId. |
| Match Stats, xG & Lineups | Per-match shotmaps with pitch coordinates, lineups, ratings, momentum. Takes eventId. |
| League Standings & Tables | League tables, group stages, conferences and divisions. Takes uniqueTournamentId. |
| Team & Player Data | This Actor. |
| Season Stats | Season leaderboards and complete team statistics. Takes uniqueTournamentId. |
| Rankings & Search | FIFA, 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 networkapify 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.