Transfermarkt Data: Player Values, Contracts & Transfers avatar

Transfermarkt Data: Player Values, Contracts & Transfers

Pricing

$1.50 / 1,000 results

Go to Apify Store
Transfermarkt Data: Player Values, Contracts & Transfers

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

Sankov Vadim

Maintained by Community

Actor 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

  1. Open the Actor and leave the defaults: What to scrape set to club, with Manchester City's squad prefilled in Start URLs.
  2. Press Start. The default run is one request for about 25 players - a near-free trial.
  3. Open the Overview view of the dataset, or open the REPORT file in the run's key-value store for a sortable dashboard. Then switch to player or league, raise maxPlayers / 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.25 means +25%. Needs includeMarketValueHistory.
  • 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 and contractExpires, 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 needWhat you get here
Market value as a number, not a stringmarketValueEur as an integer, everywhere it appears
Dates you can sort and filterISO yyyy-mm-dd for birth date, joining date and contract expiry
To see where a value is headingvalueMomentum6m / 12m and a 0-100 momentumScore, formula documented
To flag expiring contractscontractMonthsLeft and a 0-100 contractRisk
One request in, not a scraper to buildplayer, club and league modes, plus name search
Every valuation and transfer a player hasmarketValueHistory[] and transferHistory[] straight from the site's own JSON
To track a squad between runsNamed-store snapshots, a monitor block per row, a diff file
A quick visual readBuilt-in HTML report with a value chart and CSV export
Low cost, no browserPlain 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
}
FieldTypeDefaultMeaning
entityTypeselectclubclub, player or league - decides what a row is.
startUrlsarrayManchester City squadAny player, club, league or club-transfers URL. Only the numeric ID / league code matters.
idsstring[][]Numeric player/club IDs or league codes (e.g. GB1, ES1), read according to entityType.
searchQuerystring""Player name to look up through quick search. Only used when entityType is player.
crawlDepthinteger11 = listing page only; 2 = also opens every player profile.
maxClubsinteger20Clubs opened per league. League mode only.
maxPlayersinteger30Ceiling on player rows for the whole run.
maxRequestsinteger200Hard ceiling on HTTP requests, retries included.
includeMarketValueHistorybooleanfalseFull valuation history, peak value and momentum. +1 request per player.
includeTransferHistorybooleanfalseCareer transfers: date, clubs, fee, fee kind, value at the time. +1 request per player.
includeClubRowbooleanfalseAlso write one row per club: squad size, average age, foreigners, total value.
positionsselect[][]Keep only these position groups. Empty means all.
minMarketValueEur / maxMarketValueEurinteger-Drop players outside this value range.
minAge / maxAgeinteger-Drop players outside this age range.
compareWithPreviousbooleanfalseDiff against the previous run's snapshot for the same monitorKey.
monitorKeystringderivedSnapshot slot name. Empty derives it from entity type and inputs.
maxRequestsPerSecondnumber2Request rate cap, 0.5-10. Halved automatically after a 429.
maxConcurrencyinteger4Parallel in-flight requests, 1-10.
proxyConfigurationproxyoffOptional. 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 returns null for 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 null rather 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. proxyConfiguration is 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.com with Accept-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.

Check the author's profile on Apify Store for other sports and football data Actors.