Understat Scraper: Football xG & Player Stats
Pricing
Pay per event
Understat Scraper: Football xG & Player Stats
Scrape Understat expected goals (xG), xA, npxG, shots and key passes per player for the Premier League, La Liga, Bundesliga, Serie A, Ligue 1 and RFPL since 2014. Computed per-90 rates. Export CSV, Excel, JSON. No login or API key. La Liga 2025/26 returns 600 players.
Pricing
Pay per event
Rating
0.0
(0)
Developer
RecordsData
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
9 days ago
Last modified
Categories
Share
โฝ Understat Scraper: Football xG, Team Tables, Matches & Shots
The Understat xG Scraper exports expected goals data from understat.com as CSV, Excel or JSON. For any season since 2014/15 it returns player rows, team season tables with xG, xGA and xPoints, match results with match xG, shot-level data with pitch X/Y, and full player careers for the Premier League, La Liga, Bundesliga, Serie A, Ligue 1 and RFPL. No login or API key.
This Understat scraper pulls a full league player table (La Liga 2025/26 returns 600 player rows), a team season table (Arsenal 2025/26: 85 points, xG 77.49, xGA 33.13), the matches of a season, or every shot of a match. It adds columns Understat does not show: xG/90, xA/90, shots/90 and goals minus xG. An optional only-new mode delivers just the rows that changed since your last run.
โฝ What does the Understat xG Scraper do?
Pick what to export with the entity input:
- players: league player tables and club squad tables, with a minimum-minutes filter and seven sort keys.
- teams: one row per team and season with rank, W/D/L, points, goals, xG, xGA, xGD, npxG, xPoints, PPDA and deep passes. Optional situation splits per club.
- matches: results and upcoming fixtures with match xG, xPoints, PPDA and Understat win probabilities. Filter by dates, clubs or match IDs.
- playerCareer: one row per season and club for a player, found by Understat ID, player URL or exact name.
- Shots (
includeShots): one row per shot with minute, X, Y, xG, result, situation, shot type, last action and assisting player. - Only-new mode (
onlyNew): skips rows already delivered, so repeat runs cost less. - Covers six leagues and every season from 2014/15. Invalid input, unknown teams and empty results cost nothing.
๐ What data can you extract from Understat?
The dataset schema has 96 columns in one fixed order. A row carries only the keys that have a value, and the recordType column tells you which kind of row it is (league-player, team-player, player-season, team-season, match, shot or team-split).
| Group | Fields |
|---|---|
| Player identity | name, playerId, team, position, season, games, minutes |
| Player metrics | goals, nonPenaltyGoals, xG, npxG, xGDiff, assists, xA, xADiff, shots, keyPasses, yellowCards, redCards, xGChain, xGBuildup |
| Per-90 rates | xGPer90, xAPer90, npxGPer90, xGChainPer90, shotsPer90 |
| Team table | rank, wins, draws, losses, points, goalsAgainst, goalDiff, xGA, xGD, npxGA, npxGD, xPoints, xPointsDiff, ppda, oppda, deep, deepAllowed |
| Team splits | splitGroup, split (situation, formation, game state, timing, shot zone, attack speed, result) |
| Match | matchId, date, kickoff, homeTeam, awayTeam, goals, homeXG, awayXG, xPoints, PPDA, deep, shots on target, win, draw and loss probabilities |
| Shot | shotId, minute, X, Y, xG, result, situation, shotType, lastAction, assistedBy |
| Meta | recordType, scope, scopeValue, league, changeType, url, scrapedAt |
๐งพ Understat scraper sample output
A real player row from a cloud run (La Liga, season 2025, 10 rows requested, 10 delivered):
{"recordType": "league-player","scope": "league","scopeValue": "La_liga","season": "2025/2026","playerId": "3423","name": "Kylian Mbappe-Lottin","team": "Real Madrid","position": "F S","games": 31,"minutes": 2623,"goals": 25,"xG": 25.8,"xGDiff": -0.8,"assists": 5,"xA": 7.24,"shots": 146,"keyPasses": 65,"xGPer90": 0.89,"shotsPer90": 5.01,"url": "https://understat.com/player/3423","scrapedAt": "2026-10-04T04:15:31.634Z"}
A trimmed team row (EPL, season 2025). Only values read from the cloud run are shown, other columns are left out:
{"recordType": "team-season","league": "EPL","team": "Arsenal","points": 85,"xG": 77.49,"xGA": 33.13}
Rows are never padded with empty columns. The player row comes from an earlier version without the newer columns.
๐ฐ How much does it cost to scrape Understat?
Pricing is pay per event. Six events are live, at the Free plan rate shown below. Paid Apify plans get a lower per-row price on the player events, and the other four events keep the same price on every plan.
| Event | When it is charged | Price per row (Free plan) |
|---|---|---|
| League player row | One player-season from a league request or a player career | $0.015 |
| Team player row | One player-season from a club request | $0.015 |
| Team season row | One team-season table row | $0.004 |
| Match row | One match with result, xG and win probabilities | $0.002 |
| Team split row | One situation, formation, timing or zone split row | $0.001 |
| Shot row | One shot with position, xG, minute and result | $0.0001 |
On the Gold plan a player row costs $0.01275. Paid plans pay less per player row than the Free plan.
Examples at the Free plan rate: 10 player rows cost $0.15, a full 600-row La Liga season costs $9.00, and 1,000 rows cost 1,000 x $0.015 = $15.00. A 20-team EPL table costs 20 x $0.004 = $0.08. A match with its shots costs $0.002 plus $0.0001 per shot, so 3 matches and 57 shots cost $0.0117. You are not charged for failed, empty or "not found" lookups, and the actor stops when your maximum cost per run is reached. Use maxItems to cap the rows and the spend.
๐ How to scrape Understat in 3 steps
- Open the actor on Apify and click Try for free.
- Choose what to export, then one or more leagues, or club names such as
Arsenal, and set the season (2025 means 2025/26). - Click Start, then download the dataset as CSV, Excel, JSON or XML.
โ๏ธ Understat scraper input
| Field | Type | Default | What it does |
|---|---|---|---|
entity | string | players | players, teams, matches or playerCareer |
leagues | array | ["EPL"] | EPL, La_liga, Bundesliga, Serie_A, Ligue_1, RFPL (max 6) |
teams | array | [] | Club names; squad tables for players, club filter for teams and matches |
season | string | 2025 | Season start year, 2014 or later |
matchStatus, dateFrom, dateTo | string | played | Matches only: played, scheduled or all, and a date range |
matchIds | array | [] | Matches only: Understat match IDs or URLs (up to 200) |
playerIds | array | [] | Careers only: player IDs, URLs or exact names (up to 200) |
includeShots | boolean | false | Matches and careers: one extra row per shot |
includeSplits | boolean | false | Teams: situation, formation and timing splits per club |
minMinutes, sortBy | integer, string | 0, xG | Players only: minutes filter and sort (xG, goals, xA, assists, shots, time, xGChain) |
onlyNew, stateKey, resetSeen | boolean, string | off | Deliver only new or changed rows; name or clear the memory |
maxItems | integer | none | Maximum rows to export and be charged for |
Example input:
{"entity": "matches","leagues": ["EPL"],"season": "2025","teams": ["Arsenal"],"dateFrom": "2026-05-01","includeShots": true,"maxItems": 60}
Free users get a 10-row preview; paid users export up to 1,000,000 rows. Lists take up to 200 entries, and a season below 2014 fails at once with a clear message.
๐ฆ Understat scraper output
Each row is one player, team, match, shot or split, as set by recordType. Views are ready for players, teams, matches, shots and team splits. If a league, team or season returns no rows, the run still succeeds with a clear status message and charges nothing. If Understat cannot be read at all, the run fails with an explicit message instead of reporting an empty success. Understat's split figures do not sum to the table xG (Arsenal 2025: 83.98 against 77.49), so use each as published.
๐ Understat scraper vs alternatives
Read on 2026-10-10 from the public Store pages.
| This actor | scrapers_lat | jungle_synthesizer | |
|---|---|---|---|
| Data | Players, teams, matches, shots, careers | League, player, team, match, shots | Team season tables only |
| Only-new mode | Yes | Not shown | Not shown |
| Situation splits | Team splits | Squad splits | No |
| Price per 1,000 | $15 players, $4 teams, $2 matches, $0.10 shots | From $8.32 | From $0.90 |
parseforge ($5 per 1,000) sells player tables only, with no team, match or shot data. scrapers_lat covers similar modes and adds an optional AI summary, which we do not have. For player rows we cost about 1.7 times scrapers_lat and 3 times parseforge. Our team rows cost $4 per 1,000, so a team table costs more than at jungle_synthesizer, but ours adds players, matches and shots in one actor. Check current prices before choosing.
๐ผ Understat xG use cases
- Recruitment and scouting: shortlist players by xG/90 and xA/90 across six leagues.
- Betting models: build features from goals minus xG, team xGA and match xG.
- Fantasy football and media: refresh xG and xA each matchday with only-new mode; source xPoints tables and shot maps.
๐ Run the Understat scraper via API and integrations
Call it from any language with the Apify API, or schedule it after each matchday.
curl -X POST "https://api.apify.com/v2/acts/recordsdata~understat-xg-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \-H "Content-Type: application/json" \-d '{"entity":"teams","leagues":["EPL"],"season":"2025","maxItems":20}'
Results flow to Google Sheets, Zapier, Make, n8n or Airbyte through the Apify integrations.
๐ค Understat Scraper MCP server for AI agents
AI agents can call this Actor through the Apify MCP server at https://mcp.apify.com?tools=RecordsData/understat-xg-scraper. The URL loads only this Actor as a tool.
Add this to your MCP client configuration (Claude Desktop, Cursor, VS Code):
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=RecordsData/understat-xg-scraper"}}}
Example agent prompt:
Use the Understat Scraper with entity teams for the EPL 2025 season, then list the three teams whose points are furthest above their xPoints and say who is over-performing.
Tool description: use it when an agent needs football xG, xA, team xGA and xPoints, match xG or shot coordinates for the top six leagues. It takes the same fields as the Input table.
โ๏ธ Is it legal to scrape Understat?
The actor reads only public aggregate football statistics at a polite request rate, with no login and no personal data beyond public player names. Check Understat's terms for your use case and credit Understat when you republish its numbers.
โ Frequently asked questions
What is xG in football and how does Understat Scraper use it?
Expected goals (xG) is the probability-weighted value of the chances a player took. Understat Scraper exports xG from understat.com for every player, team, match and shot and computes xGDiff, which is goals minus xG. A positive value means a player scores more than their chances suggest.
How do I spell team names in Understat Scraper?
Use Understat's own spelling with underscores in the teams field, for example Manchester_City, Real_Madrid or Bayern_Munich. A spelling that Understat does not know returns no rows from Understat Scraper and no charge. If a club returns nothing, check the underscore spelling against the club name on understat.com.
Which seasons and leagues does Understat Scraper cover?
Understat Scraper covers the Premier League (EPL), La Liga, Bundesliga, Serie A, Ligue 1 and the Russian Premier League, from the 2014/15 season to the current one. Enter the start year of the season in the season field, for example 2025 for 2025/26, and pick one or more leagues in leagues.
Why did my Understat Scraper run return 0 results?
Usually the team spelling is wrong, the season is outside 2014 to the current year, or minMinutes is higher than any player reached. Understat Scraper then succeeds with a status message and costs nothing. An invalid season such as 1999 fails immediately with a clear message instead of an empty success.
How many player rows does an Understat league return?
When checked in October 2026, Understat Scraper returned these player rows for the 2025/26 season: 537 for the Premier League, 600 for La Liga, 499 for Bundesliga, 586 for Serie A, 553 for Ligue 1 and 470 for the Russian Premier League. A full season is one league request and costs one row price per player.
Am I charged for errors in Understat Scraper?
No. Understat Scraper charges only for valid priced rows, never for failed lookups. Error rows, empty results, unknown team lookups and duplicate rows are never billed, and the run stops cleanly when your maximum cost per run is reached. Use maxItems to cap spend.
Can I try Understat Scraper for free?
Yes. Free Apify users get a 10-row preview of Understat Scraper, which costs $0.15 at the Free-plan rate of $0.015 per player row. That is enough to check the columns before a full league export. Paid Apify plans unlock exports of up to 1,000,000 rows.
Can I scrape single matches or shots with Understat Scraper?
Yes. Set entity to matches and add includeShots to get one row per shot, with minute, X, Y, xG, result, situation, shot type and assisting player. Understat Scraper accepts match IDs or URLs, or a date range and clubs. For one player's shots over a whole career, use playerCareer with includeShots. Shots are off by default and cost $0.0001 per shot row.
Can I get team tables and xPoints with Understat Scraper?
Yes. Set entity to teams to get one row per team and season with rank, points, xG, xGA, xGD, npxG, xPoints and PPDA, computed from Understat's per-match history in the site's own order. Add includeSplits for situation, formation and timing splits. Team rows cost $0.004 each and split rows $0.001 each.
Can Understat Scraper return only new results?
Yes. Turn on onlyNew and Understat Scraper delivers only rows that are new or changed since the last run with the same filters, such as new match results, new shots and updated totals. Skipped rows are not charged. A second run on the same match returned 0 rows and charged 0. Use stateKey to name the memory and resetSeen to clear it.
Can I look up one player by ID or name in Understat Scraper?
Yes. Set entity to playerCareer and enter Understat player IDs, player URLs such as understat.com/player/8260, or a full name in playerIds. Understat Scraper returns one row per season and club, billed as player rows. An ambiguous name is rejected with the candidate IDs listed, so use the ID when two players share a name.
๐ Want more football and sports data?
๐ Support
Found a bug or a missing field? Open the Issues tab on this actor's page or write to contact.punkrecordsdata@gmail.com. Custom solutions available on request.
Last updated: 2026-10-11