Football analytics projects often stall at the data acquisition phase. While basic statistics like goals and assists are widely available, advanced metrics such as Expected Goals (xG), Expected Assists (xA), and xGChain are typically locked behind proprietary APIs or buried in complex web layouts.
Understat is a primary source for this advanced data, covering the Premier League, La Liga, Bundesliga, Serie A, Ligue 1, and the Russian Premier League. However, because Understat embeds its raw data inside nested JavaScript variables within the page HTML rather than serving it via a public API, building a custom scraper requires writing fragile regex patterns or maintaining complex HTML parsers that break whenever the site layout changes.
Using the understat-scraper Actor solves this extraction problem by parsing the underlying data structures directly and returning clean, structured JSON payloads. This approach eliminates the need to write custom parsing scripts, manage proxy rotations, or handle page-loading issues.
Mapping the Understat Data Structure
To extract data systematically, you need to understand how the scraping tool targets the site's data model. The Actor operates in three distinct modes, configured via the mode input property:
-
leagueStats: Retrieves season-wide player metrics. This mode yields crucial fields such asxG(expected goals),xA(expected assists),xGChain(the total xG of possession chains a player was involved in), andxGBuildup(possession contribution excluding shots and key passes). -
teamStats: Extracts aggregated team performance data over a season, showing expected goals created (xG) versus expected goals against (xGA). -
playerStats: Extracts a detailed, match-by-match history for a single player.
For target targeting, the league property accepts standard codes: EPL, La_liga, Bundesliga, Serie_A, Ligue_1, and RFPL. The season property requires the four-digit start year of the season (for example, 2024 targets the 2024/25 season).
Resolving Player IDs
One common bottleneck in football data pipelines is mapping player names to specific database IDs. In Understat, every player has a unique identifier (for example, Mohamed Salah is 1250).
If you do not know a player's ID, you cannot query their match-by-match history directly. The scraper resolves this by allowing you to search. You can run the scraper in leagueStats mode with the playerName filter applied. The Actor searches the league roster, matches the name, and returns the record containing the correct playerId. Once retrieved, this ID can be passed into the playerId input field in playerStats mode to extract their complete historical match log.
Step-by-Step Data Extraction
To set up an automated pipeline that extracts expected goals data, follow this implementation sequence.
1. Configure the Run Input
Define the target dataset by structuring the JSON input. To retrieve the top performing players in the Premier League for the 2024 season, use the following configuration:
{
"mode": "leagueStats",
"league": "EPL",
"season": "2024",
"maxItems": 50
}
2. Execute the Actor
Run the Actor on the Apify platform. The scraper bypasses the front-end rendering, extracts the embedded JSON data from the Understat page source, normalizes the keys, and populates the default dataset.
3. Retrieve Structured Results
The scraper outputs flat JSON records. Below is an example of the structured data returned for an individual player:
{
"playerId": "1250",
"playerName": "Mohamed Salah",
"team": "Liverpool",
"position": "AML",
"games": 32,
"goals": 20,
"assists": 12,
"xG": 18.5,
"xA": 9.2,
"xGChain": 22.1,
"season": "2024",
"league": "Premier League",
"playerUrl": "https://understat.com/player/1250"
}
This clean output format allows you to pipe the data directly into analytical databases, visualization tools, or local pandas DataFrames without any post-processing scripts.
Calculating Extraction Costs
Running this scraper incurs costs based on a predictable, event-based pricing model. Every execution is billed per event, alongside the platform usage consumed by the run.
The charges are structured as follows:
- Actor Start: $0.005 per GB of memory allocated to the run.
- Result: Charged per single result item returned in the default dataset.
The price per result event scales down based on your account's discount tier:
- FREE: $0.005 per event
- BRONZE: $0.00433 per event
- SILVER: $0.00367 per event
- GOLD: $0.003 per event
- PLATINUM: $0.003 per event
- DIAMOND: $0.003 per event
Each result costs $0.005 on the free tier, plus a one-time start charge of $0.005 per GB of memory allocated to the run. Platform usage for the run is billed separately at your Apify plan's rates.
For example, running a query to fetch the top 100 players from the Bundesliga requires one Actor Start event and 100 result events.
Integration Limitations
While this tool simplifies data collection, it has structural limitations. It is designed specifically for historical and post-match analysis; it does not support real-time, live-match event streaming. Because Understat updates its data after matches conclude, attempting to use this scraper for real-time in-game tracking or live betting applications will not work. For projects requiring live event coordinates, opt for premium sports data feeds instead.
The examples here were produced with Understat xG Football Data Scraper. Its README lists the output fields, so you can check a response against the schema before you build on it.
Prices quoted above are this Actor's published pay-per-event rates on the Apify Store, read from the Apify platform API on 2026-09-26. Check the Actor page for the current rates.
Top comments (0)