Sofascore Match Stats, xG & Lineups Scraper
Pricing
from $4.00 / 1,000 analysed matches
Sofascore Match Stats, xG & Lineups Scraper
Deep Sofascore match data: xG shotmaps with pitch coordinates, lineups with 33 per-player stats and ratings, attack-momentum graphs, average-position maps, incident timelines, team statistics and odds. Feed it match IDs or URLs. No API key, no login, and no residential proxy needed.
Pricing
from $4.00 / 1,000 analysed matches
Rating
0.0
(0)
Developer
Elena Vance
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
15 hours ago
Last modified
Categories
Share
Sofascore Match Analytics Scraper
Deep per-match data from Sofascore: xG shotmaps with pitch coordinates, lineups with 33 per-player stats and ratings, attack-momentum graphs, average-position maps, incident timelines, team statistics, bookmaker odds and more. No Sofascore API key, no login.
Give it match IDs or Sofascore URLs and pick exactly which sub-resources you want — every switch is one extra request per match, so a narrow run is a cheap run.
Results are stored in an Apify dataset you can export as JSON, CSV, Excel, XML or HTML.
Why this is cheap to run
No proxy required, and no premium plan required.
Sofascore is called directly — no headless browser, and no proxy at all unless a request is actually blocked. If an IP does get blocked, the Actor escalates on its own, cheapest first: a datacenter proxy (included in every Apify plan, free tier included) with a few IPs rotated, and only then a residential one if your plan has it. There is no residential-proxy add-on requirement.
Pairs with the Live & Daily Scores Scraper
This Actor consumes match IDs. The
Sofascore Live Scores & Fixtures Scraper emits
eventId for every match it finds, so the usual pattern is: find matches with
that Actor, analyse them with this one. You can also paste match URLs straight
in.
What makes this different
- Eight sub-resources, each independently switchable. Shotmap, lineups, average positions, attack momentum, incidents, team statistics, odds and heatmaps are separate flags, and each is one extra request per match. You pay for the shape of data you asked for and nothing else.
- Heatmaps are billed only when they actually arrive. The surcharge keys on the field written to the record, not on the input flag, so asking for heatmaps on a match that has none costs nothing extra.
- xG shotmaps carry pitch coordinates, not just shot totals — enough to redraw the map or compute your own spatial metrics.
- 33 per-player stats with ratings, per player, per match.
- Failures are never billed, and unusable input returns an unbilled diagnostic row rather than failing the run.
- No API key, no login, no headless browser, no residential-proxy add-on — see Why this is cheap to run.
Input
| Field | Type | Default | Description |
|---|---|---|---|
eventIds | array of integers | – | Sofascore match IDs, e.g. [16363246]. |
matchUrls | array of strings | – | Match URLs, e.g. https://www.sofascore.com/football/match/newcastle-liverpool#id:16363246. |
includeStatistics | boolean | true | Team stats per period. |
includeLineups | boolean | true | Formations plus 33 stats per player. |
includeIncidents | boolean | true | Goals, cards, subs timeline. |
includeShotmap | boolean | true | Shots with coordinates and xG. |
includeGraph | boolean | true | Attack momentum per minute. |
includeAveragePositions | boolean | false | Average pitch position per player. |
includeBestPlayers | boolean | false | Best player per side. |
includeTeamStreaks | boolean | false | Form and head-to-head streaks. |
includeVotes | boolean | false | Crowd predictions. |
includeWinProbability | boolean | false | Home / draw / away probability. |
includeManagers | boolean | false | Both managers. |
includeH2H | boolean | false | Historical win/draw/loss tally. |
includeOdds | boolean | false | Bookmaker markets, fractional odds. |
includeComments | boolean | false | Text commentary (largest payload). |
includeHeatmaps | boolean | false | Touch heatmap per player — one request per player, ~28 per football match. |
maxItems | integer | 100 | Cap on matches stored. |
proxyConfiguration | object | off | Leave off; see above. |
At least one of eventIds / matchUrls is required.
Sport coverage — read this before running
Only football has every sub-resource. Other sports return a useful subset,
and anything a sport doesn't support is set to null rather than failing the
run.
| Sub-resource | football | basketball | am. football | baseball | volleyball | ice-hockey | tennis | handball |
|---|---|---|---|---|---|---|---|---|
| statistics | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — |
| h2h / votes | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| team streaks | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | ✅ |
| odds | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | — |
| incidents | ✅ | ✅ | ✅ | — | ✅ | ✅ | — | — |
| lineups | ✅ | ✅ | ✅ | ✅ | — | — | — | — |
| graph / best players | ✅ | ✅ | ✅ | — | — | — | — | — |
| average positions | ✅ | — | ✅ | ✅ | — | — | — | — |
| shotmap (xG) | ✅ | — | — | — | — | — | — | — |
| win probability | ✅ | — | — | — | — | — | — | — |
A note on xG: Sofascore only models expected goals for major competitions.
A Premier League match carries xG on every shot; a minor cup tie carries none.
Where it isn't modelled, xg and xgot are null rather than 0, so you can
tell "not modelled" from "genuinely zero".
Output
One row per match. Requested-but-unavailable sub-resources are null.
{"eventId": 16363246,"sport": "football","tournament": { "name": "Premier League", "uniqueTournamentId": 17 },"homeTeam": { "id": 39, "name": "Newcastle United", "shortName": "Newcastle" },"awayTeam": { "id": 44, "name": "Liverpool FC", "shortName": "Liverpool" },"homeScore": 2,"awayScore": 2,"status": { "code": 100, "description": "Ended", "type": "finished" },"venue": { "name": "St James' Park", "city": "Newcastle upon Tyne" },"referee": "Stuart Attwell","statistics": {"ALL": {"ballPossession": { "home": "39%", "away": "61%", "homeValue": 39, "awayValue": 61 },"expectedGoals": { "home": "1.43", "away": "2.73", "homeValue": 1.43, "awayValue": 2.73 }}},"shotmap": [{"player": { "id": 869856, "name": "Dominik Szoboszlai" },"shotType": "goal", "situation": "penalty", "bodyPart": "right-foot","xg": 0.7884, "xgot": 0.9887,"playerCoordinates": { "x": 88, "y": 50 }, "time": 90}],"lineups": {"home": { "formation": "4-2-3-1", "players": [{ "id": 979232, "name": "Anthony Elanga", "rating": 7.7, "minutesPlayed": 90 }] }},"graph": [{ "minute": 1, "value": -7 }, { "minute": 2, "value": -6 }]}
statistics is keyed by Sofascore's own stat key, so you can pull
statistics.ALL.expectedGoals.homeValue directly instead of walking nested
group arrays.
Example: one match, everything cheap
{ "eventIds": [16363246] }
Example: xG and tactical shape for several matches
{"eventIds": [16363246, 16248441],"includeShotmap": true,"includeAveragePositions": true,"includeLineups": true,"includeStatistics": false,"includeIncidents": false}
Example: from a URL you pasted
{ "matchUrls": ["https://www.sofascore.com/football/match/newcastle-liverpool#id:16363246"] }
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 | This Actor. |
| League Standings & Tables | League tables, group stages, conferences and divisions. Takes uniqueTournamentId. |
| Team & Player Data | Squads, bios, market values, transfers, match logs. Takes team and player IDs. |
| 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.