Understat Football xG & Shot Data Scraper avatar

Understat Football xG & Shot Data Scraper

Pricing

from $2.16 / 1,000 item extracteds

Go to Apify Store
Understat Football xG & Shot Data Scraper

Understat Football xG & Shot Data Scraper

Export public Understat league, team, player, match, and shot expected-goals records for recurring football scouting and performance analysis.

Pricing

from $2.16 / 1,000 item extracteds

Rating

0.0

(0)

Developer

Stas Persiianenko

Stas Persiianenko

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Categories

Share

Export public Understat football xG and shot data as structured league, team, player, match, and shot records. Use it for recurring scouting, performance analysis, football content, spreadsheets, dashboards, and model datasets.

The Actor supports Understat's six competitions and public league, team, player, and match URLs. It reads the same structured data used by the public site and does not require an Understat account.

What can you extract?

Choose the records needed for your analysis:

  • league team aggregates;
  • league player aggregates;
  • match schedules and results;
  • match-level shot maps;
  • team player aggregates;
  • team tactical breakdowns;
  • player match histories;
  • player shot histories.

Every row has a recordType, source URL, scrape timestamp, useful normalized fields, and a data object preserving source-specific details. This lets one run feed a spreadsheet while retaining enough detail for a football model.

Who is this Understat football data Actor for?

Football scouts and analysts

Compare team xG and xGA, inspect player production, or review how chances were created in a specific match.

Data scientists

Build repeatable training datasets with expected-goals values, shot coordinates, situations, results, and match context.

Sports writers and creators

Support match reports and season reviews with source-linked expected-goals records instead of copying tables manually.

Clubs and agencies

Refresh player and team benchmarks on a schedule and connect the dataset to internal reporting tools.

Football app builders

Use Apify API or MCP to fetch structured Understat records for prototypes and internal applications.

Supported leagues and seasons

The league selector supports:

Input valueCompetition
EPLPremier League
La_ligaLa Liga
BundesligaBundesliga
Serie_ASerie A
Ligue_1Ligue 1
RFPLRussian Premier League

Enter a season by its start year. For example, 2025 means the 2025/2026 season. Understat availability differs by competition and season.

Input options

FieldTypeWhat it controls
startUrlsURL listPublic Understat league, team, player, or match pages to extract.
leaguesstring listLeague discovery when no explicit URL is supplied.
seasonsstring listFour-digit season start years used with leagues.
recordTypesstring listEntity types to include in the default dataset.
maxItemsintegerGlobal cap across every URL and selected record type.

If startUrls is present, the Actor processes those URLs and does not add the default league. If URLs are absent, provide at least one league and one season.

Only understat.com public URLs are accepted. Unsupported hosts and malformed paths fail the run instead of producing misleading empty data.

Getting started

  1. Open the Actor in Apify Console.
  2. Choose one or more leagues and season start years, or paste public Understat URLs.
  3. Select the record types needed by your workflow.
  4. Set maxItems to bound the output volume.
  5. Click Start.
  6. Open the default dataset to inspect, download, or integrate the rows.
  7. Save the input as an Apify Task if you want to schedule the same extraction.

A simple league table input is:

{
"leagues": ["EPL"],
"seasons": ["2025"],
"recordTypes": ["leagueTeam"],
"maxItems": 20
}

Extract one match and its shots

Use a public match URL with match and shot records:

{
"startUrls": [
{ "url": "https://understat.com/match/27828" }
],
"recordTypes": ["match", "shot"],
"maxItems": 30
}

The match row includes league, season, teams, score context, xG, PPDA, and shot counts in data when Understat exposes them. Shot rows include player, team, minute, xG, result, situation, body part, and pitch coordinates.

Build a team-season analysis dataset

A team page can return matches, players, and tactical breakdowns in one run:

{
"startUrls": [
{ "url": "https://understat.com/team/Arsenal/2025" }
],
"recordTypes": ["match", "teamPlayer", "teamBreakdown"],
"maxItems": 100
}

This is useful for season reviews, scouting notebooks, and scheduled dashboard refreshes. The global item limit applies across all three record types.

Output fields

Common normalized fields include:

FieldMeaning
recordTypeOne of the eight supported entity types.
recordIdUnderstat source identifier when present.
leagueUnderstat league key or name.
seasonSeason start year.
team / playerRelevant team or player name.
matchIdUnderstat match identifier.
dateMatch date, or shot minute for shot rows.
homeTeam / awayTeamMatch participants.
goalsGoals for player aggregate rows.
xG / xGAExpected goals and expected goals against.
xAExpected assists.
npxG / npxGANon-penalty expected-goals values.
shots / minutesPlayer activity totals.
resultShot outcome when applicable.
situation / bodyPartShot context.
x / yUnderstat shot-map coordinates.
sourceUrlPublic page associated with the row.
scrapedAtISO timestamp for the extraction.
dataAdditional source-specific fields.

Fields that do not apply to a record type are omitted. Use recordType before interpreting optional columns.

Example output

A real league-team row has this shape:

{
"recordType": "leagueTeam",
"recordId": "71",
"league": "EPL",
"season": 2025,
"team": "Aston Villa",
"xG": 56.203311,
"xGA": 56.682839,
"npxG": 56.203311,
"npxGA": 55.160499,
"sourceUrl": "https://understat.com/league/EPL/2025",
"scrapedAt": "2026-09-01T14:53:23.475Z",
"data": {
"games": 38,
"wins": 19,
"draws": 8,
"loses": 11,
"goals": 58,
"goalsAgainst": 51,
"points": 65,
"expectedPoints": 51.0701
}
}

Values change as Understat updates its public data. The source URL makes each row traceable.

How much does it cost to export Understat football records?

The Actor uses pay-per-event pricing:

  • a $0.005 start event once per run;
  • an item event once for each useful row saved to the default dataset;
  • no charge for rejected, duplicate, empty, or failed records.

The current BRONZE item rate is $0.0036 per record, with lower rates on higher Apify tiers. At that rate, 20 league-team rows cost about $0.077 including the start event. A 100-row team analysis costs about $0.365 including the start event. Your active Apify tier and the live Console pricing table are authoritative.

Set the output limit to create a predictable upper bound. Infrastructure usage is covered by the Actor's pay-per-event model when the run is launched under that model.

Scheduling and recurring analysis

Save a tested input as an Apify Task, then attach a schedule. Common patterns include:

  1. refresh a league table after each match week;
  2. export one team's player and tactical data each morning;
  3. collect selected player histories for a scouting shortlist;
  4. snapshot one match's shots for a post-match report;
  5. send dataset changes to a warehouse or webhook workflow.

The Actor returns current source data. It does not maintain a historical change log between runs, so store snapshots in your destination when comparisons matter.

Export and integration patterns

From the dataset page you can download JSON, CSV, Excel, XML, or RSS using Apify dataset endpoints. You can also connect runs to:

  • Google Sheets;
  • Make;
  • Zapier;
  • webhooks;
  • a database or data warehouse;
  • Python or JavaScript notebooks;
  • an AI assistant through Apify MCP.

For multi-type datasets, filter on recordType in the destination. Keep recordId plus recordType as part of a stable deduplication key.

Run through the Apify API

Replace <APIFY_TOKEN> with your token.

cURL

curl -X POST \
"https://api.apify.com/v2/acts/automation-lab~understat-football-xg-shot-data/runs?token=<APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"leagues": ["EPL"],
"seasons": ["2025"],
"recordTypes": ["leagueTeam"],
"maxItems": 20
}'

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/understat-football-xg-shot-data').call({
startUrls: [{ url: 'https://understat.com/match/27828' }],
recordTypes: ['match', 'shot'],
maxItems: 30,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Python

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/understat-football-xg-shot-data').call(run_input={
'startUrls': [{'url': 'https://understat.com/team/Arsenal/2025'}],
'recordTypes': ['match', 'teamPlayer', 'teamBreakdown'],
'maxItems': 100,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)

Use with Apify MCP

Connect Claude Code directly to this Actor:

claude mcp add --transport http apify \
"https://mcp.apify.com?tools=automation-lab/understat-football-xg-shot-data"

Claude Desktop, Cursor, and VS Code MCP setup

Add this Actor-scoped server to the MCP JSON configuration used by Claude Desktop, Cursor, or VS Code:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com?tools=automation-lab/understat-football-xg-shot-data"
}
}
}

Example prompts:

  • "Export the EPL 2025 team xG table and rank clubs by xG minus xGA."
  • "Get match and shot records from https://understat.com/match/27828 and summarize the largest chances."
  • "Collect Arsenal's 2025 matches, players, and tactical breakdowns, then prepare a scouting table."

MCP returns the Actor run and dataset through Apify's normal permissions.

Reliability and failure behavior

The Actor uses Understat's public structured data requests with a browser-like request shape. It does not run a browser, download media, or use a residential proxy.

Temporary timeouts, rate limits, and selected 5xx responses receive up to three bounded attempts with short backoff. Malformed input, unsupported hosts, invalid paths, and deterministic 4xx responses fail without blind retries.

A challenge page or non-JSON response is treated as an upstream error, not as an empty successful dataset. When a selected record type does not apply to a supplied URL, that type produces no row for that URL.

Legality and responsible use

  • Only public Understat pages are supported.
  • No login, account, private data, or CAPTCHA solving is provided.
  • Historical availability is controlled by Understat.
  • Fixtures and current-season values can change after a later source update.
  • maxItems stops output globally, so a low limit may end before later record types.
  • Shot coordinates use Understat's coordinate convention and may need transformation for a specific visualization.
  • The Actor is not a betting or prediction service.

Use reasonable run frequency and concurrency. Respect Understat's terms, applicable database rights, and the laws governing your use of exported data. Do not use the Actor to overload the source or misrepresent source data as official club data.

Troubleshooting

Why did I get no shot rows from a league URL?

shot records are extracted from a match URL. Use a public /match/<id> URL, or first export match rows and run selected match URLs in a later Task.

Why are some fields missing?

The default dataset contains several entity types. Fields only appear when they apply and when Understat exposes them. Check recordType and inspect data for source-specific values.

Why did the run stop at exactly my limit?

maxItems is global across URLs and types. Raise it if you need later entities in the same run, or split workflows into separate Tasks.

What does season 2025 mean?

It is the season starting in 2025, normally displayed as 2025/2026.

Can I scrape an arbitrary football site?

No. The Actor validates the host and only supports public Understat league, team, player, and match routes.

FAQ

Does it require an Understat account?

No. It uses public football data exposed by Understat.

Can I export CSV or Excel?

Yes. Use the dataset export controls or the corresponding Apify dataset API format.

Can I schedule it?

Yes. Save an input as an Apify Task and attach an Apify schedule.

Does it include shot xG and coordinates?

Yes for public match and player shot records. Select shot for match URLs or playerShot for player URLs.

Are every league and season guaranteed?

No. The selector lists Understat's supported competitions, but the source controls historical and current availability.

Is this an official Understat product?

No. This independent Actor extracts publicly available Understat data and links every row to its source.

For broader sports workflows, browse the automation-lab Actor portfolio. Combine this specialized expected-goals dataset with automation-lab football match, standings, or player-statistics Actors when a workflow needs additional sources. Only link datasets after checking their identifiers, competition coverage, and update timing.

Support

For a reproducible problem, include the Actor run URL, sanitized input, expected record type, and one public Understat URL. Do not include Apify tokens or other credentials.