Transfermarkt Data: Player Values, Contracts & Transfers
Pricing
$1.50 / 1,000 results
Transfermarkt Data: Player Values, Contracts & Transfers
Scrapes Transfermarkt player profiles, club squads, league tables and club transfers into normalised rows: market value as a number, ISO dates, height in cm, split positions, plus optional market value and transfer history and run-over-run change tracking.
Pricing
$1.50 / 1,000 results
Rating
0.0
(0)
Developer
Sankov Vadim
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
Transfermarkt Data: player values, contracts and transfers
Point it at a club, a league or a player name and get back rows with numbers as numbers: market value in euros, ISO dates, height in centimetres, split positions. Add the site's own market-value and transfer-history feeds, a momentum score, a contract-risk flag and a run-over-run diff, all from public pages - no login, no browser.
You get three entry modes (player / club / league), search by name, normalised fields next to the site's own raw labels, optional market-value and transfer history, a 0-100 momentum score and a contract-risk indicator, squad monitoring between runs, and a self-contained HTML report. It runs on 256 MB.
🚀 Quick start
- Open the Actor and leave the defaults: What to scrape set to
club, with Manchester City's squad prefilled in Start URLs. - Press Start. The default run is one request for about 25 players - a near-free trial.
- Open the Overview view of the dataset, or open the
REPORTfile in the run's key-value store for a sortable dashboard. Then switch toplayerorleague, raisemaxPlayers/maxClubs, and turn on the history and monitoring options for a full run.
🧭 Who it is for
- Fantasy football and sports analytics. Pull market value, age, position and contract data as clean numbers instead of scraping HTML yourself.
- Scouts and agents. Track a shortlist's market-value momentum and flag players heading into the last year of their contract.
- Sports media and content creators. Get transfer fees, dates and market-value-at-transfer for a club's arrivals and departures, ready for a table or a chart.
- Data engineers and researchers. A flat, documented schema across players, clubs and leagues, with a dataset schema and views already defined - no scraper to build or selectors to maintain.
✨ What it does
Three ways in: player, club, league
entityType decides what a row is. club turns every club you give into its squad, one row per player. player scrapes individual players by URL, ID or name search. league walks a competition: clubs first (maxClubs), then their squads. Any Transfermarkt player, club, league or club-transfers URL works in Start URLs - only the numeric ID (or league code, e.g. GB1) inside it matters, not the slug.
Search by name
Set entityType to player and type a name into searchQuery instead of a URL. The Actor runs it through the site's own quick search and scrapes the players it finds.
Two crawl depths
crawlDepth: 1 reads only the listing page - name, position, age, nationality, market value - one request per club or league page. crawlDepth: 2 also opens every player's profile: date and place of birth, height, foot, agent, contract dates, outfitter. Player start URLs always open the profile regardless of depth.
Numbers instead of strings
Where the source page prints €45.00m, 1,95 m or 21/07/2000 (26), the dataset carries marketValueEur: 45000000, heightCm: 195, dateOfBirth: "2000-07-21" and age: 26. Positions are split into positionMain (Goalkeeper / Defender / Midfield / Attack) and positionSub (e.g. Centre-Forward). The site's own label/value pairs are kept too, in raw{}, for anyone who wants the original text.
Market value and transfer history from the site's own feeds
Turn on includeMarketValueHistory and includeTransferHistory to add, per player, the full valuation series (marketValueHistory[]: date, value, club, age) and the career transfer list (transferHistory[]: date, season, both clubs, fee, fee kind, market value at the time). Each adds one request per player to the site's own JSON endpoints - the same data the market-value graph and transfer table on the page are built from.
Momentum score and contract risk
Two indices computed from the data the site already gives you, not a valuation:
valueMomentum6m/valueMomentum12m: the market value now divided by the last history point at least 6 or 12 months old, minus 1.0.25means +25%. NeedsincludeMarketValueHistory.momentumScore:round(50 + 50 * clamp(mean(available momentums), -1, 1))- 50 is flat, 100 is +100% or more, 0 is -100% or worse.contractMonthsLeft: days between today andcontractExpires, divided by 30.4375.contractRisk:round(100 * clamp((36 - monthsLeft) / 30, 0, 1))- 100 at six months left or less (or an expired contract), 0 at three years or more.
Watch a squad over time
Turn on compareWithPrevious and every player row gets a monitor block comparing it with the snapshot saved under monitorKey by the previous run: new, changed (market value moved 5% or 100,000 EUR or more, club changed, or the contract date changed) or unchanged. A MONITOR_DIFF file in the key-value store lists new, changed and gone players (only meaningful on a complete run). The snapshot is a named key-value store and is only overwritten after a clean, complete run.
Built-in HTML report
Every run saves a self-contained REPORT page in the key-value store: a sortable, filterable player table (text, position, club, age, value range), top-N lists by market value and by momentum (10/25/50), an SVG market-value chart for a chosen player when history is included, the monitoring block, and a CSV export of whatever is filtered. No external scripts.
Polite by default
The default rate is 2 requests per second - deliberately conservative, not a technical ceiling anyone confirmed. It is halved automatically after a 429 and eased back up after a run of clean successes. Proxy is off by default because a direct connection worked in testing; proxyConfiguration is there to switch on if your log shows 403s. The whole Actor runs on 256 MB with plain HTTP requests, no browser.
🆚 Why use this Actor
| You need | What you get here |
|---|---|
| Market value as a number, not a string | marketValueEur as an integer, everywhere it appears |
| Dates you can sort and filter | ISO yyyy-mm-dd for birth date, joining date and contract expiry |
| To see where a value is heading | valueMomentum6m / 12m and a 0-100 momentumScore, formula documented |
| To flag expiring contracts | contractMonthsLeft and a 0-100 contractRisk |
| One request in, not a scraper to build | player, club and league modes, plus name search |
| Every valuation and transfer a player has | marketValueHistory[] and transferHistory[] straight from the site's own JSON |
| To track a squad between runs | Named-store snapshots, a monitor block per row, a diff file |
| A quick visual read | Built-in HTML report with a value chart and CSV export |
| Low cost, no browser | Plain HTTP, 256 MB, polite defaults |
⚙️ Input
{"entityType": "club","startUrls": [{ "url": "https://www.transfermarkt.com/manchester-city/startseite/verein/281" }],"crawlDepth": 1,"maxPlayers": 30,"includeMarketValueHistory": false,"includeTransferHistory": false,"compareWithPrevious": false}
| Field | Type | Default | Meaning |
|---|---|---|---|
entityType | select | club | club, player or league - decides what a row is. |
startUrls | array | Manchester City squad | Any player, club, league or club-transfers URL. Only the numeric ID / league code matters. |
ids | string[] | [] | Numeric player/club IDs or league codes (e.g. GB1, ES1), read according to entityType. |
searchQuery | string | "" | Player name to look up through quick search. Only used when entityType is player. |
crawlDepth | integer | 1 | 1 = listing page only; 2 = also opens every player profile. |
maxClubs | integer | 20 | Clubs opened per league. League mode only. |
maxPlayers | integer | 30 | Ceiling on player rows for the whole run. |
maxRequests | integer | 200 | Hard ceiling on HTTP requests, retries included. |
includeMarketValueHistory | boolean | false | Full valuation history, peak value and momentum. +1 request per player. |
includeTransferHistory | boolean | false | Career transfers: date, clubs, fee, fee kind, value at the time. +1 request per player. |
includeClubRow | boolean | false | Also write one row per club: squad size, average age, foreigners, total value. |
positions | select[] | [] | Keep only these position groups. Empty means all. |
minMarketValueEur / maxMarketValueEur | integer | - | Drop players outside this value range. |
minAge / maxAge | integer | - | Drop players outside this age range. |
compareWithPrevious | boolean | false | Diff against the previous run's snapshot for the same monitorKey. |
monitorKey | string | derived | Snapshot slot name. Empty derives it from entity type and inputs. |
maxRequestsPerSecond | number | 2 | Request rate cap, 0.5-10. Halved automatically after a 429. |
maxConcurrency | integer | 4 | Parallel in-flight requests, 1-10. |
proxyConfiguration | proxy | off | Optional. Switch on if the log shows 403 or repeated 429. |
Filters run before a row is written, so anything they drop is never stored and never charged for. The prefill (one club, maxPlayers 30, depth 1, history off) costs one request for roughly 25 rows.
📦 Output
One row per player, club or transfer, resultType telling you which: player, club, transfer or searchHit. Here is a real player row, produced from this Actor's own profile parser and its own market-value/transfer-history fetchers against a saved Erling Haaland profile page (crawlDepth: 2, both histories on). The history and transfer arrays are shown trimmed - the full row carries every point and every transfer the endpoint returns:
{"resultType": "player","playerId": "418560","url": "https://www.transfermarkt.com/erling-haaland/profil/spieler/418560","name": "Erling Haaland","nameHome": "Erling Braut Håland","shirtNumber": "9","position": "Attack - Centre-Forward","positionMain": "Attack","positionSub": "Centre-Forward","dateOfBirth": "2000-07-21","age": 26,"placeOfBirth": "Leeds","citizenship": ["Norway"],"heightCm": 195,"foot": "left","agent": "Rafaela Pimenta","club": "Man City","clubId": "281","clubUrl": "https://www.transfermarkt.com/manchester-city/startseite/verein/281","joined": "2022-07-01","contractExpires": "2034-06-30","lastContractExtension": "2025-01-17","outfitter": "Nike","marketValueText": "€220.00m","marketValueEur": 220000000,"marketValueUpdated": "2026-07-22","marketValueHistory": [{ "date": "2016-12-18", "valueEur": 200000, "club": "Bryne FK", "age": 16 },{ "date": "2019-11-07", "valueEur": 30000000, "club": "Red Bull Salzburg", "age": 19 },{ "date": "2019-12-16", "valueEur": 45000000, "club": "Red Bull Salzburg", "age": 19 }],"peakMarketValueEur": 45000000,"valueMomentum6m": 3.8889,"valueMomentum12m": 3.8889,"momentumScore": 100,"transferHistory": [{ "date": "2019-01-01", "season": "18/19", "fromClub": "Molde FK", "toClub": "Salzburg", "feeEur": 8000000, "feeKind": "fee", "mvEur": 5000000 },{ "date": "2020-01-01", "season": "19/20", "fromClub": "Salzburg", "toClub": "Dortmund", "feeEur": 20000000, "feeKind": "fee", "mvEur": 45000000 },{ "date": "2022-07-01", "season": "22/23", "fromClub": "Dortmund", "toClub": "Man City", "feeEur": 60000000, "feeKind": "fee", "mvEur": 150000000 }],"contractMonthsLeft": 93.1,"contractRisk": 0,"scrapedAt": "2026-09-27T10:39:36+00:00"}
Note on this specific example: the saved capture used to build this dataset row only returned market-value points through late 2019, so peakMarketValueEur and the momentum figures here are computed from that shorter series, not from a value history running up to today. A live run pulls whatever points the endpoint currently returns.
Club rows (resultType: "club") carry clubId, name, leagueName, squadSize, avgAge, foreigners, avgMarketValueEur, totalMarketValueEur, url. Transfer rows (resultType: "transfer", from a club's transfers page) carry direction (arrival/departure), player, position, age, fromClub, toClub, feeEur, feeKind, season. Search hits (resultType: "searchHit") carry hitType (player/club) plus the matching identity fields.
Dataset views: Overview (identity, position, age, value, contract, momentum, risk), Values (market value, peak, updated date, momentum), Contracts (joined, expires, months left, risk, agent), Transfers. Export as JSON, CSV, Excel, XML, RSS or HTML from the dataset tab, or read it through the Apify API.
⚠️ Limits, stated plainly
- Unofficial endpoints. The market-value history and transfer-history data come from the site's own
/ceapi/JSON endpoints that its own pages call in the browser - not a documented, versioned API. They can change or disappear without notice; a broken endpoint returnsnullfor the affected fields instead of failing the run. - No season statistics. Goals, appearances and minutes played are not collected: they are not present in the page's server-rendered HTML, only loaded separately in the browser, and are out of scope for this Actor.
- Selectors can change. The HTML parsers key off CSS classes on the profile, squad, league and transfer pages. A layout change can turn a field to
nullrather than crash the run, but it can also mean a field goes quiet until the parser is updated. - Rate ceiling not confirmed, and it is a shared site. Testing saw no blocks at a polite pace, which is why the default is 2 requests per second. Running faster (above roughly 2-3 requests per second) or re-running the same targets very frequently from one IP can trigger 403 responses.
proxyConfigurationis available if that happens. - Small, seasonal niche. Squad and market-value activity concentrates around the transfer windows; expect quieter data (and quieter demand) outside them.
- English only. The Actor reads
www.transfermarkt.comwithAccept-Language: en; labels on other-language Transfermarkt domains are not parsed.
💳 Pricing
Pay per event. See the Pricing tab of this Actor for the current event prices. A row is charged when it is added to the dataset - filtered-out rows are not. Momentum, contract risk, history and monitoring cost nothing extra.
❓ FAQ
Does it give live scores or match statistics? No. This Actor covers player, squad, market-value and transfer data. Goals, appearances and minutes are not in the source pages it reads.
Do I need a proxy?
No, not by default - a direct connection worked in testing. Turn on proxyConfiguration only if your run starts seeing 403s.
Can I track a squad over time?
Yes. Turn on compareWithPrevious, keep the same monitorKey, and schedule the Actor. Each run marks players as new, changed or unchanged against the last clean snapshot.
Why is a field null?
The source page did not print it for that player (common for agent, outfitter, lastContractExtension), a history endpoint returned nothing, or a selector missed a layout change. A missing field never fails the run.
Is a Transfermarkt account needed? No. Only public pages and the site's own public JSON endpoints are used.
What does momentumScore measure?
A documented arithmetic mapping of the site's own market-value history onto a 0-100 scale, not a market valuation or a prediction.
🔌 Integrations
Send results on through the Apify API, webhooks, Zapier, Make, n8n or Google Sheets. The flat per-resultType schema loads into a spreadsheet as is.
📝 Changelog
- 0.1 First release: player/club/league entry modes, name search, normalised fields, market-value and transfer history, momentum score, contract risk, run-over-run monitoring, HTML report.
🛟 Support
Something looks off, or you need a field added? Open an issue from the Actor's Issues tab and include the run link and the input you used.
🔗 Related Actors
Check the author's profile on Apify Store for other sports and football data Actors.