Transfermarkt Football Transfers & Fees Scraper avatar

Transfermarkt Football Transfers & Fees Scraper

Pricing

from $1.50 / 1,000 transfer scrapeds

Go to Apify Store
Transfermarkt Football Transfers & Fees Scraper

Transfermarkt Football Transfers & Fees Scraper

Scrape football transfers from Transfermarkt: every arrival and departure for a club, a whole league's transfer window, or the global latest-transfers feed. Fee, market value, position, age and both clubs on every row. Any season. No API key, no login, no proxy needed.

Pricing

from $1.50 / 1,000 transfer scrapeds

Rating

0.0

(0)

Developer

Elena Vance

Elena Vance

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

5 days ago

Last modified

Share

Scrape football transfers from Transfermarkt three ways — a club's window, a whole league's window, or the global latest-transfers feed — and get one row per transfer with the fee, the player's market value at the time, and both clubs named on every row.

No API key, no login, no residential proxy, no browser. It runs on the Apify free plan. Export to JSON, CSV, Excel, XML or pull it from the API.


What you get

One row per transfer. Real, unedited output from {"clubIds": ["281"], "season": 2025}:

FieldValue
transferId6107087
source / directionclub / in
season / seasonStartYear25/26 / 2025
playerId / playerName583255 / Antoine Semenyo
position / ageRight Winger / 26
nationality["Ghana", "England"]
marketValue65000000
fee72000000
feeType / feeTextfee / €72.00m
fromClubId / fromClubName989 / AFC Bournemouth
toClubId / toClubName281 / Manchester City
clubIncome / clubExpenditure107280000 / 301800000
clubBalance-194520000
playerUrlhttps://www.transfermarkt.com/x/profil/spieler/583255

Both ends of the move are on every row. Transfermarkt's own pages name only one — a club's page tells you who arrived and leaves "arrived where" implicit in which table the row was in. Here fromClub* and toClub* are always filled, so a club run and a league run stack into one table without a single join.

A loan is not a zero-euro transfer

fee is null, never 0, for a free transfer, a loan, an end of loan or an undisclosed fee — because none of those is a fee of zero, and averaging a column where they became zero quietly halves every number in it. feeType says which of the five cases it was, and feeText keeps Transfermarkt's own wording so an unusual one is never silently rounded into a number.

feeTypefeeTransfermarkt's wording
feethe amount€72.00m
loanthe loan fee, or nullloan transfer, Loan fee: €2.00m
freenullfree transfer
end_of_loannull, plus loanEndDateEnd of loan 30/06/2025
undisclosednull?

transferId makes repeat runs safe

Every row carries Transfermarkt's own transfer id, so a daily run against the latest feed de-duplicates on one integer instead of on a name-and-fee guess.


Three ways to ask

InputWhat it scrapesRowsRequests
clubIdsone club's arrivals and departures20–45 per club1 per club
competitionCodesevery club in a league, in and out~7401 per code
includeLatestTransfersthe worldwide latest-confirmed feed25 per page, 250 max1 per page

They combine freely in one run, and all three produce exactly the same columns, so the dataset is one table however you asked for it.

⚠️ A league window is around 740 rows

{"competitionCodes": ["GB1"]} is twenty clubs' complete transfer business — around 740 charged rows from one three-character code. That is the single thing to know before setting maxItems, and it is why maxItems defaults to 1000 rather than the smaller default the rest of this suite uses.

You are never charged for the same transfer twice. A move between two clubs of the same league is on Transfermarkt's page twice — the buyer's arrival and the seller's departure — and the Premier League's 25/26 window is 819 table rows for 740 actual transfers. Those 79 are collapsed before billing, keeping the arrival, so direction is in and clubId is the buying club for every move inside the league. fromClubId still names the seller. The same applies across sources: ask for a club and its league and the overlap is charged once.


Input

{
"clubIds": ["281", "https://www.transfermarkt.com/real-madrid/startseite/verein/418"],
"competitionCodes": ["GB1"],
"includeLatestTransfers": false,
"season": 2025,
"maxItems": 1000
}
InputWhat it does
clubIdsNumeric IDs or any Transfermarkt club URL. The squad, profile and transfers tabs all work — the name in the URL is ignored.
competitionCodesLeague codes (GB1, ES1, L1, IT1, FR1) or any Transfermarkt competition URL. ~820 rows each.
includeLatestTransfersThe global feed, newest first. It is ten pages — 250 transfers — deep, and stops on its own when a page repeats.
seasonThe year a season starts2025 is the 2025/26 window. Leave empty for the current one. Does not apply to the latest feed.
maxItemsHard cap on charged rows across every source. Default 1000.
proxyConfigurationLeave it off — see below.

Cups have no transfer window

Transfermarkt publishes transfer windows per league, not per cup. Ask for CL or EL and you get an unbilled COMPETITION_HAS_NO_TRANSFERS row saying so, rather than an empty dataset you have to diagnose yourself.

To get Champions League clubs' transfers, take their clubIds from the Transfermarkt League Table & Club Values Scraper and pass those here.


What this Actor does NOT return

  • Transfer dates. Transfermarkt's transfer tables do not carry them — not the club page, not the league page, not the latest feed. Transfers are grouped by season, and the only date anywhere on them is loanEndDate on an end-of-loan row. Per-player dated transfer history exists on a different endpoint, and it is what the Transfermarkt Player & Market Value Scraper returns.
  • Rumours. Transfermarkt's rumour pages are not reachable at any documented URL; treat the Rumour Mill as unavailable rather than missing.
  • All-time transfer records, which are a different table with a different shape.
  • Contract details or wages. Not published.
  • Anything requiring a Transfermarkt login.

Why this is cheap to run

Transfermarkt is fronted by AWS WAF, and the usual answer — a residential proxy at $8/GB — is what makes scrapers of this site expensive. It turns out Apify's own egress is not challenged, so this Actor calls Transfermarkt directly and pays nothing for proxy. A residential IP is fetched only if a request is genuinely challenged, and most runs never touch one.

A league window is one request for ~820 rows, which is the best rows-per-request ratio anywhere in this suite.

The Actor start fee is $0.00005 and the default memory is 512 MB — under the 1 GB line, so Apify's per-gigabyte start fee is charged once. Several Transfermarkt scrapers on the Store run at 4 GB with a $0.10 start fee, which bills $0.40 before returning a single row.

Do not turn on Apify's datacenter proxy. Transfermarkt's WAF challenges Apify's datacenter pool while leaving its direct egress alone — verified, same URLs, same second — so switching it on takes a working run and breaks it.


What makes this different

  • Both clubs on every row, from three sources that each name only one.
  • A loan is null, not zero. The difference is invisible until someone averages the column.
  • Market value alongside the fee, so "did they overpay" is a subtraction rather than a second scrape. The club view only carries it in Transfermarkt's detailed layout, which this Actor always requests.
  • The season returned is the season reported. season is read back off the page, never echoed from your input, and requestedSeason sits beside it — Transfermarkt silently serves its newest season for a future year.
  • A cup, a missing club and a missing code are three different answers, each an unbilled row that says which, rather than silence.
  • You are never billed for a failure, or for the same transfer twice, and bad input returns an INVALID_INPUT row instead of failing the run.
  • A weekly canary runs the deployed build against live Transfermarkt across all three sources and opens a GitHub issue if field coverage drops.

Example runs

One club's window:

{ "clubIds": ["281"] }

A whole league, past season:

{ "competitionCodes": ["GB1"], "season": 2024, "maxItems": 1000 }

Who did Europe's big five buy from:

{ "competitionCodes": ["GB1", "ES1", "L1", "IT1", "FR1"], "maxItems": 4000 }

A daily feed of the world's confirmed transfers:

{ "includeLatestTransfers": true, "maxItems": 200 }

Part of a Transfermarkt suite:

  • Transfermarkt Player & Market Value Scraper — one player in depth, with the full market-value and dated transfer histories.
  • Transfermarkt Club Squad Scraper — every player in a club's squad, with the fee each was signed for.
  • Transfermarkt League Table & Club Values Scraper — league tables merged with what every club's squad is worth.
  • Transfermarkt Football Transfers & Fees Scraper — this one.

They chain: the competition scraper's clubId is this Actor's input, and the playerId this Actor returns is the player scraper's input.