# Transfermarkt Scraper - Players, Clubs & Market Values (`solidcode/transfermarkt-scraper`) Actor

\[💰 $1.0 / 1K] Scrape football/soccer data from Transfermarkt: player profiles with market value history, club squads, competition tables, and transfer records. Paste any Transfermarkt URL — the scraper detects the page type automatically. Up to 20+ languages supported.

- **URL**: https://apify.com/solidcode/transfermarkt-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** Developer tools, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Transfermarkt Scraper

Pull football data from Transfermarkt at scale — player profiles with market values in EUR, club squads with total and average squad value, competition tables with tier and total league valuation, and paginated transfer-record lists with fee, season, and from/to clubs. Built for scouts, football analysts, sports-media editors, and fantasy-league operators who need a clean structured Transfermarkt dataset across players, clubs, competitions, and transfers in a single run — without stitching four separate scrapers together.

### Why This Scraper?

- **Four record types in one actor — player, club, competition, and transfer** — every competing Transfermarkt scraper on Apify is player-only. Paste a club URL and get the club row; paste a competition URL and get the competition plus its league-table clubs; paste `/statistik/topabloesen` and get paginated transfer rows. The output dataset auto-routes by `recordType`.
- **Auto-detects the page type from the URL** — mix player, club, competition, and transfer-record URLs in the same `startUrls` array. The scraper inspects the path (`/profil/spieler/`, `/startseite/verein/`, `/startseite/wettbewerb/`, `/transfers/transferrekorde/`) and runs the right parser for each.
- **13 regional Transfermarkt mirrors** — pick from `.com`, `.us`, `.de`, `.world`, `.es`, `.fr`, `.it`, `.nl`, `.com.br`, `.pl`, `.com.tr`, `.jp`, and `.co.uk`. Player and club IDs are identical across mirrors, so the scraper rewrites your URLs to the mirror you select — position labels, country names, and competition names come back in the language of that region.
- **Full market-value history per player** — every market-value snapshot Transfermarkt has ever published for a player, with season ID, the club they were at, their age, the compact label ("€180.00m"), and the EUR integer ready for charting.
- **Career transfer history with fee, market value, and direction** — for every transfer in a player's career: date, from-club, to-club, fee in EUR, market value at the time, transfer type (loan / permanent / free), and the "fee description" Transfermarkt prints next to the fee.
- **Achievements (trophies) and injury absences as opt-in enrichments** — toggle `includeAchievements` to get the player's full trophy cabinet (league titles, cups, individual awards) and `includeInjuries` to get every injury absence with type, start/end date, duration in days, and games missed.
- **Nested expansion of leagues into squads** — flip `includeCompetitionClubs` and `includeClubSquad` to walk a whole league: one competition URL becomes 18–20 club rows, and each club row expands into 25–35 player profile rows. Fetch the entire Premier League's player base from a single input URL.
- **Robust EUR fee normalizer** — Transfermarkt prints values in five different formats: `€222.00m`, `€1.50bn`, `€500Th.`, `222,00 Mio. €`, `ablösefrei`. We normalize every fee into a plain integer EUR field (`feeEur`, `marketValueEur`) alongside the compact display string, so downstream pipelines can sort, filter, and aggregate without parsing currency text.

### Use Cases

**Player Scouting & Recruitment Analytics**
- Pull every player on a competitor club's senior squad with current market value, position, contract end date, and nationality
- Build short-lists of out-of-contract players by filtering on `currentClubContractUntil`
- Compare market-value trajectories across an entire age cohort using the per-player MV history

**Transfer Market Research**
- Track all-time top transfer fees in EUR by paginating `/statistik/topabloesen`
- Monitor inbound and outbound moves for a specific club by following its transfers page
- Quantify how often loans convert to permanent deals across a league season

**Fantasy League & Game Analytics**
- Seed a fantasy database with the full Premier League player set in one run (competition URL + both expansion toggles)
- Refresh weekly market values and injury absences for every fantasy-eligible player
- Detect emerging-talent price spikes via the market-value history delta

**Sports Media & Editorial Pipelines**
- Generate match-preview cards with both clubs' squad sizes, average ages, and total values
- Produce localized transfer-window articles by switching `language` to Italian, German, or Brazilian Portuguese
- Build a "biggest signings of the season" leaderboard from the transfer-records list

**Football Data Science & Modeling**
- Train transfer-fee prediction models against the full historical transfer history
- Study career mobility patterns using `transferHistory` (date, age, fee, market value at the time)
- Benchmark league strength via aggregated `totalMarketValueEur` across competitions

**Agency & Player-Representation Workflows**
- Watch contract expiries across 50+ leagues by pulling competition pages quarterly
- Track injury history (type, days out, games missed) for risk profiling
- Pair `formerClubsNote` with `transferHistory` to reconstruct a complete player career timeline

### Getting Started

#### Single Player Profile

The simplest possible run — one player, full enrichment defaults (market-value history and transfer history on):

```json
{
    "startUrls": [
        "https://www.transfermarkt.com/erling-haaland/profil/spieler/418560"
    ]
}
````

#### Multiple Players With All Enrichments

Pull four players with every optional sub-resource turned on — achievements and injuries included:

```json
{
    "startUrls": [
        "https://www.transfermarkt.com/erling-haaland/profil/spieler/418560",
        "https://www.transfermarkt.com/kylian-mbappe/profil/spieler/342229",
        "https://www.transfermarkt.com/jude-bellingham/profil/spieler/581678",
        "https://www.transfermarkt.com/vinicius-junior/profil/spieler/371998"
    ],
    "includeMarketValueHistory": true,
    "includeTransferHistory": true,
    "includeAchievements": true,
    "includeInjuries": true
}
```

#### Whole Premier League — Competition + Clubs

One competition URL expanded into every club on the league table (20 rows total):

```json
{
    "startUrls": [
        "https://www.transfermarkt.com/premier-league/startseite/wettbewerb/GB1"
    ],
    "includeCompetitionClubs": true,
    "maxResults": 500
}
```

#### Full League Walk — Competition → Clubs → Squads

One competition URL fans out to ~20 clubs and each club's full squad (~500–700 player rows):

```json
{
    "startUrls": [
        "https://www.transfermarkt.com/laliga/startseite/wettbewerb/ES1"
    ],
    "includeCompetitionClubs": true,
    "includeClubSquad": true,
    "language": "es",
    "maxResults": 600
}
```

#### Top All-Time Transfer Fees

Paginate the global transfer-records page with a row cap:

```json
{
    "startUrls": [
        "https://www.transfermarkt.com/statistik/topabloesen"
    ],
    "recordType": "transfers",
    "maxResults": 250
}
```

### Input Reference

#### What to Scrape

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `startUrls` | string\[] | `[Haaland profile, Manchester City club]` | One or more Transfermarkt URLs. Supports player profiles (`/profil/spieler/<id>`), club squad pages (`/startseite/verein/<id>`), competitions (`/startseite/wettbewerb/<code>`), and transfer-records pages (`/transfers/transferrekorde/...`, `/statistik/topabloesen`). The scraper detects the page type automatically. |
| `recordType` | select | `Auto-detect from URL (recommended)` | Optional filter: `Auto-detect from URL (recommended)`, `Players only`, `Clubs only`, `Competitions only`, or `Transfer records only`. Use auto-detect unless you want to ignore URLs of other types in the input. |

#### How Much to Scrape

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxResults` | integer | `1000` | Maximum number of result rows to return across the whole run. For club URLs this caps the number of player rows; for competition URLs it caps club rows; for transfer-list URLs it caps transfer rows. Set to `0` for unlimited. |
| `language` | select | `English (.com)` | Which Transfermarkt regional mirror to use. Options: `English (.com)`, `English (US)`, `German (.de)`, `English (.world)`, `Spanish (.es)`, `French (.fr)`, `Italian (.it)`, `Dutch (.nl)`, `Portuguese - Brazil (.com.br)`, `Polish (.pl)`, `Turkish (.com.tr)`, `Japanese (.jp)`, `English (.co.uk)`. Affects language of position labels, country names, and competition names. |

#### Player Enrichments

Optional extras fetched only for player URLs. Each toggle adds one request per player.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `includeMarketValueHistory` | boolean | `true` | Full historical market-value timeline per player (date, value, age, club at the time). |
| `includeTransferHistory` | boolean | `true` | Every transfer in the player's career with date, from-club, to-club, fee, and market value at the time. |
| `includeAchievements` | boolean | `false` | Trophies and titles (league titles, cups, individual awards). |
| `includeInjuries` | boolean | `false` | Injury history table (injury type, dates, games missed). |

#### Nested Expansion

Turning these on multiplies result count — a typical first-division squad has 25–35 players and a top-flight league has 18–20 clubs.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `includeClubSquad` | boolean | `false` | For club URLs, also fetch a full profile for every player on the squad — not just the club summary row. |
| `includeCompetitionClubs` | boolean | `false` | For competition URLs, also fetch a full club page for every club in the competition. Combine with `includeClubSquad` to walk an entire league down to player level. |

### Output

Every row carries a `recordType` field — `player`, `club`, `competition`, or `transfer` — so you can split the dataset cleanly downstream. The Apify dataset viewer ships with one tab per record type out of the box.

#### Player (`recordType: "player"`)

```json
{
    "recordType": "player",
    "sourceUrl": "https://www.transfermarkt.com/erling-haaland/profil/spieler/418560",
    "id": 418560,
    "name": "Erling Haaland",
    "shortName": "E. Haaland",
    "displayName": "Erling Haaland",
    "portraitUrl": "https://img.a.transfermarkt.technology/portrait/header/418560-1709108116.jpg",
    "age": 25,
    "dateOfBirth": "2000-07-21",
    "placeOfBirth": "Leeds",
    "countryOfBirthId": 189,
    "nationalityId": 125,
    "secondNationalityId": null,
    "heightMeters": 1.95,
    "preferredFootId": 3,
    "positionGroup": 1,
    "positionGroupName": "Attack",
    "positionId": 7,
    "contractUntil": "2034-06-30",
    "marketValue": { "value": 200000000, "currency": "EUR", "compact": "€200.00m" },
    "currentClubId": 281,
    "currentClubJoinedDate": "2022-07-01",
    "isCaptain": false,
    "nationalTeamCountryId": 125
}
```

##### Player — Core Fields

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | Always `"player"` |
| `sourceUrl` | string | The Transfermarkt URL this row came from |
| `id` | number | Transfermarkt player ID |
| `name` | string | Display name |
| `shortName` | string | Short display name |
| `displayName` | string | Long display name |
| `artistName` | string | Stage name (used for Brazilian players like "Pelé") |
| `portraitUrl` | string | Headshot image URL |
| `relativeUrl` | string | Path on transfermarkt.com |

##### Player — Biography

| Field | Type | Description |
|-------|------|-------------|
| `age` | number | Current age in years |
| `dateOfBirth` | string | ISO date of birth |
| `dateOfDeath` | string | ISO date of death (if applicable) |
| `placeOfBirth` | string | City of birth |
| `countryOfBirthId` | number | Transfermarkt country ID |
| `gender` | string | Gender |
| `passportName` | string | Name as on passport |
| `nationalityId` | number | Primary nationality (Transfermarkt country ID) |
| `secondNationalityId` | number | Second nationality if dual |

##### Player — Physical & Position

| Field | Type | Description |
|-------|------|-------------|
| `heightMeters` | number | Height in metres |
| `preferredFootId` | number | Right / left / both |
| `positionGroup` | number | Group ID (Attack, Midfield, Defence, Goalkeeper) |
| `positionGroupName` | string | Group label |
| `positionId` | number | Specific position (e.g. Centre-Forward) |
| `firstSidePositionId` | number | Secondary position |
| `secondSidePositionId` | number | Tertiary position |
| `outfitterId` | number | Boot sponsor |

##### Player — Club & Contract

| Field | Type | Description |
|-------|------|-------------|
| `currentClubId` | number | Current club's Transfermarkt ID |
| `currentClubJoinedDate` | string | When they joined the current club |
| `currentClubContractUntil` | string | Contract expiry at the current club |
| `contractUntil` | string | Overall contract end date |
| `lastContractRenewal` | string | Date of the most recent renewal |
| `isCaptain` | boolean | Captain flag |
| `nationalTeamCountryId` | number | National team country |
| `formerClubsNote` | string | Free-text former-clubs note |
| `consultantAgencyId` | number | Agency representing the player |

##### Player — Market Value

| Field | Type | Description |
|-------|------|-------------|
| `marketValue` | object | `{ value, currency, compact, determined }` — current market value in EUR |
| `previousMarketValue` | object | Previous valuation snapshot |
| `marketValueHistory` | object\[] | Full history `[{ seasonId, clubId, age, value, currency, compact, determined }]` — only when `includeMarketValueHistory` is on |
| `currentMarketValueSnapshot` | object | Latest snapshot from the history endpoint |

##### Player — Transfer History, Achievements, Injuries

| Field | Type | Description |
|-------|------|-------------|
| `transferHistory` | object\[] | All career transfers `[{ id, date, seasonId, fromClubId, toClubId, fromCompetitionId, toCompetitionId, fee, marketValue, age, type, typeName, feeDescription, contractUntilDate }]` |
| `mostRecentTransfer` | object | Single most recent transfer entry |
| `achievements` | object\[] | Trophies `[{ title, group }]` — only when `includeAchievements` is on |
| `absences` | object\[] | All absences (injuries + national-team call-ups) |
| `injuries` | object\[] | Absences with the national-team call-ups filtered out `[{ absenceId, name, competitionId, seasonId, start, end, missedGamesCount, durationDays }]` |

#### Club (`recordType: "club"`)

```json
{
    "recordType": "club",
    "sourceUrl": "https://www.transfermarkt.com/manchester-city/startseite/verein/281",
    "id": 281,
    "name": "Manchester City",
    "shortName": "Man City",
    "abbreviation": "MCI",
    "isNationalTeam": false,
    "countryId": 189,
    "primaryCompetitionId": "GB1",
    "crestUrl": "https://tmssl.akamaized.net/images/wappen/head/281.png",
    "addressStreet": "Etihad Campus, Etihad Stadium",
    "addressCity": "Manchester",
    "addressPostcode": "M11 3FF",
    "addressCountryId": 189,
    "squadSize": 26,
    "squadAverageAge": 26.4,
    "squadMarketValueTotal": { "value": 1110000000, "currency": "EUR", "compact": "€1.11bn" },
    "squadMarketValueAverage": { "value": 42700000, "currency": "EUR", "compact": "€42.70m" },
    "squadAcquisitionValue": { "value": 1230000000, "currency": "EUR", "compact": "€1.23bn" }
}
```

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | Always `"club"` |
| `sourceUrl` | string | The Transfermarkt URL this row came from |
| `id` | number | Transfermarkt club ID |
| `name` | string | Full club name |
| `shortName` | string | Short club name |
| `abbreviation` | string | Three-letter abbreviation |
| `identifier` | string | URL slug |
| `isNationalTeam` | boolean | True for national teams |
| `isSpecialClub` | boolean | Flag for academy / B teams |
| `crestUrl` | string | Crest image URL |
| `relativeUrl` | string | Path on transfermarkt.com |
| `countryId` | number | Transfermarkt country ID |
| `primaryCompetitionId` | string | Primary league code (e.g. `GB1`) |
| `addressStreet` | string | Street address |
| `addressCity` | string | City |
| `addressPostcode` | string | Postcode |
| `addressCountryId` | number | Country ID of the registered address |
| `squadSize` | number | Number of senior squad players |
| `squadAverageAge` | number | Mean age of the squad |
| `squadMarketValueTotal` | object | Total squad market value `{ value, currency, compact }` |
| `squadMarketValueAverage` | object | Average per-player market value |
| `squadAcquisitionValue` | object | Sum of fees paid to assemble the squad |

#### Competition (`recordType: "competition"`)

```json
{
    "recordType": "competition",
    "sourceUrl": "https://www.transfermarkt.com/premier-league/startseite/wettbewerb/GB1",
    "id": "GB1",
    "name": "Premier League",
    "shortName": "Premier League",
    "identifier": "premier-league",
    "logoUrl": "https://tmssl.akamaized.net/images/logo/header/gb1.png",
    "typeId": 1,
    "currentSeasonId": 2025,
    "currentSeason": "25/26",
    "countryId": 189,
    "confederationId": 6,
    "tier": 1,
    "gameDayCount": 38,
    "isOngoing": true,
    "isTournament": false,
    "totalMarketValue": { "value": 11400000000, "currency": "EUR", "compact": "€11.40bn" }
}
```

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | Always `"competition"` |
| `sourceUrl` | string | The Transfermarkt URL this row came from |
| `id` | string | Competition code (e.g. `GB1`, `ES1`, `IT1`, `L1`, `FR1`) |
| `name` | string | Competition full name |
| `shortName` | string | Short name |
| `identifier` | string | URL slug |
| `relativeUrl` | string | Path on transfermarkt.com |
| `logoUrl` | string | Competition logo URL |
| `typeId` | number | League / cup / international type ID |
| `currentSeasonId` | number | Numeric season ID (e.g. `2025`) |
| `currentSeason` | string | Season label (e.g. `25/26`) |
| `countryId` | number | Host-country Transfermarkt ID |
| `confederationId` | number | UEFA / CONMEBOL / etc. ID |
| `associationId` | number | Football association ID |
| `tier` | number | League tier (1 = top flight) |
| `gameDayCount` | number | Match days in a season |
| `isOngoing` | boolean | True if the season is in progress |
| `isTournament` | boolean | True for knockout tournaments |
| `totalMarketValue` | object | Aggregate market value of every club in the league `{ value, currency, compact }` |

#### Transfer (`recordType: "transfer"`)

```json
{
    "recordType": "transfer",
    "rank": "1",
    "playerId": "342229",
    "playerName": "Kylian Mbappé",
    "position": "Centre-Forward",
    "season": "17/18",
    "joinedClubId": "583",
    "joinedClubName": "Paris Saint-Germain",
    "joinedCompetitionCode": "FR1",
    "joinedCompetitionName": "Ligue 1",
    "feeText": "€180.00m",
    "feeEur": 180000000
}
```

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | Always `"transfer"` |
| `rank` | string | Position in the transfer-records list |
| `playerId` | string | Transfermarkt player ID |
| `playerName` | string | Player name as displayed |
| `position` | string | Playing position |
| `season` | string | Season label (e.g. `17/18`) |
| `joinedClubId` | string | Destination club's Transfermarkt ID |
| `joinedClubName` | string | Destination club name |
| `joinedCompetitionCode` | string | Destination league code (e.g. `FR1`) |
| `joinedCompetitionName` | string | Destination league name |
| `feeText` | string | Raw Transfermarkt fee string (e.g. `€180.00m`, `ablösefrei`) |
| `feeEur` | number | Fee normalized to integer EUR (`0` for free transfers, `null` when unknown) |

### Tips for Best Results

- **Mix record types in one run.** `startUrls` can hold player, club, competition, and transfer-list URLs at the same time — the auto-detector routes each one to the right parser. Pay for one start, get four datasets.
- **Set `maxResults` before flipping nested toggles.** A single competition URL with `includeCompetitionClubs` and `includeClubSquad` both on can produce 500–700 player rows. Cap your spend by setting `maxResults` to the figure you actually need.
- **Use competition codes you already know.** Premier League is `GB1`, La Liga is `ES1`, Serie A is `IT1`, Bundesliga is `L1`, Ligue 1 is `FR1`. Paste the URL ending in those codes to skip search.
- **Switch `language` to localize labels.** Picking `German (.de)` returns position labels like "Mittelstürmer" and country names in German — handy for regional sports-media pipelines. Player and club IDs stay identical across all 13 mirrors.
- **Combine `includeCompetitionClubs` with `includeClubSquad`** to fetch an entire top-flight league down to every player in one input URL. The output dataset then carries all three record types and joins cleanly on `currentClubId` and `primaryCompetitionId`.
- **Leave achievements and injuries off unless you need them.** Each adds one extra request per player. For a squad-wide refresh of market values, the defaults (MV history + transfer history) already give you the most-requested fields.
- **For transfer-records lists, prefer competition-scoped URLs.** A URL like `/transfers/transferrekorde/statistik/topabloesen?wettbewerb_id=GB1` returns Premier-League-only transfers — much more targeted than the global all-time list.

### Pricing

**$1.00 per 1,000 results** — flat rate, billed per row in the output dataset.

| Results | Total cost |
|---------|------------|
| 100 | $0.10 |
| 1,000 | $1.00 |
| 10,000 | $10.00 |
| 100,000 | $100.00 |

A "result" is any row in the output dataset — a `player`, `club`, `competition`, or `transfer`. **No compute charges — you only pay per result returned.**

### Integrations

Export data in JSON, CSV, Excel, XML, or RSS. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation
- **Google Sheets** — Direct spreadsheet export
- **Slack** / **Email** — Notifications on new results
- **Webhooks** — Trigger custom APIs on run completion
- **Apify API** — Full programmatic access

### Legal & Ethical Use

This actor is designed for legitimate football research, scouting, sports analytics, and editorial use against publicly available Transfermarkt pages. Users are responsible for complying with applicable laws and Transfermarkt's terms of service, including attributing Transfermarkt as the data source where appropriate and making reasonable-rate requests. Do not use extracted data for spam, harassment, or any illegal purpose.

# Actor input Schema

## `startUrls` (type: `array`):

Paste one or more Transfermarkt URLs. Supported page types: player profile (`/.../profil/spieler/<id>`), club squad (`/.../startseite/verein/<id>`), competition (`/.../startseite/wettbewerb/<code>`), and transfer records (`/transfers/transferrekorde/...`, `/statistik/topabloesen`). The scraper detects the page type automatically and routes to the right parser.

## `recordType` (type: `string`):

Override automatic page-type detection. Use `Auto-detect` unless you specifically want to ignore URLs of other types in the input.

## `maxResults` (type: `integer`):

Maximum number of result rows to return across the whole run (shared across every input URL, not per URL). For club URLs this caps the number of player rows; for competition URLs it caps club rows; for transfer-list URLs it caps transfer rows. Set to 0 for unlimited. Note: Transfermarkt's all-time transfer-records list contains roughly 100,000 rows — when set to unlimited on transfer URLs, pagination stops there and the run completes early.

## `language` (type: `string`):

Which Transfermarkt regional site to scrape from. Affects language of position labels, country names, and competition names. `English (.com)` is the global default.

## `includeMarketValueHistory` (type: `boolean`):

For player pages, include the full historical market value timeline (date, value, age, club at the time). Adds one extra request per player.

## `includeTransferHistory` (type: `boolean`):

For player pages, include every transfer in the player's career with date, from-club, to-club, fee, and market value at the time.

## `includeAchievements` (type: `boolean`):

For player pages, include trophies and titles (league titles, cups, individual awards). Adds one extra request per player.

## `includeInjuries` (type: `boolean`):

For player pages, include the injury history table (injury type, dates, games missed). Adds one extra request per player.

## `includeClubSquad` (type: `boolean`):

For club URLs, also fetch a full profile for every player on the squad (not just the squad-row summary). WARNING: a typical first-division squad has 25-35 players — this multiplies your result count and run cost roughly 25-35x per club URL. Leave off if you only need the squad summary.

## `includeCompetitionClubs` (type: `boolean`):

For competition URLs, also fetch a full club page for every club in the competition (not just the league-table summary). WARNING: a typical top-flight league has 18-20 clubs — this multiplies your result count by roughly 18-20x per competition URL. If you also enable 'Expand Club Squad to Player Profiles', the multipliers stack (18 clubs x 25-35 players = 450+ rows per competition). Leave off if you only need the competition summary.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.transfermarkt.com/erling-haaland/profil/spieler/418560",
    "https://www.transfermarkt.com/manchester-city/startseite/verein/281"
  ],
  "recordType": "auto",
  "maxResults": 1000,
  "language": "com",
  "includeMarketValueHistory": true,
  "includeTransferHistory": true,
  "includeAchievements": false,
  "includeInjuries": false,
  "includeClubSquad": false,
  "includeCompetitionClubs": false
}
```

# Actor output Schema

## `players` (type: `string`):

Player profiles with market value, position, nationality, club, and contract.

## `clubs` (type: `string`):

Club records with squad size, average age, total market value, and league.

## `competitions` (type: `string`):

League / cup competition records with country, tier, and aggregated market value.

## `transfers` (type: `string`):

Transfer records — player moves with from/to clubs, fee, and date.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        "https://www.transfermarkt.com/erling-haaland/profil/spieler/418560",
        "https://www.transfermarkt.com/manchester-city/startseite/verein/281"
    ],
    "recordType": "auto",
    "maxResults": 1000,
    "language": "com",
    "includeMarketValueHistory": true,
    "includeTransferHistory": true,
    "includeAchievements": false,
    "includeInjuries": false,
    "includeClubSquad": false,
    "includeCompetitionClubs": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/transfermarkt-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [
        "https://www.transfermarkt.com/erling-haaland/profil/spieler/418560",
        "https://www.transfermarkt.com/manchester-city/startseite/verein/281",
    ],
    "recordType": "auto",
    "maxResults": 1000,
    "language": "com",
    "includeMarketValueHistory": True,
    "includeTransferHistory": True,
    "includeAchievements": False,
    "includeInjuries": False,
    "includeClubSquad": False,
    "includeCompetitionClubs": False,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/transfermarkt-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.transfermarkt.com/erling-haaland/profil/spieler/418560",
    "https://www.transfermarkt.com/manchester-city/startseite/verein/281"
  ],
  "recordType": "auto",
  "maxResults": 1000,
  "language": "com",
  "includeMarketValueHistory": true,
  "includeTransferHistory": true,
  "includeAchievements": false,
  "includeInjuries": false,
  "includeClubSquad": false,
  "includeCompetitionClubs": false
}' |
apify call solidcode/transfermarkt-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=solidcode/transfermarkt-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Transfermarkt Scraper - Players, Clubs & Market Values",
        "description": "[💰 $1.0 / 1K] Scrape football/soccer data from Transfermarkt: player profiles with market value history, club squads, competition tables, and transfer records. Paste any Transfermarkt URL — the scraper detects the page type automatically. Up to 20+ languages supported.",
        "version": "1.0",
        "x-build-id": "k7JzSnE4gZdqusp1N"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/solidcode~transfermarkt-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-solidcode-transfermarkt-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/solidcode~transfermarkt-scraper/runs": {
            "post": {
                "operationId": "runs-sync-solidcode-transfermarkt-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/solidcode~transfermarkt-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-solidcode-transfermarkt-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "startUrls": {
                        "title": "Transfermarkt URLs",
                        "type": "array",
                        "description": "Paste one or more Transfermarkt URLs. Supported page types: player profile (`/.../profil/spieler/<id>`), club squad (`/.../startseite/verein/<id>`), competition (`/.../startseite/wettbewerb/<code>`), and transfer records (`/transfers/transferrekorde/...`, `/statistik/topabloesen`). The scraper detects the page type automatically and routes to the right parser.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "recordType": {
                        "title": "Page Type",
                        "enum": [
                            "auto",
                            "player",
                            "club",
                            "competition",
                            "transfers"
                        ],
                        "type": "string",
                        "description": "Override automatic page-type detection. Use `Auto-detect` unless you specifically want to ignore URLs of other types in the input.",
                        "default": "auto"
                    },
                    "maxResults": {
                        "title": "Maximum Results",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of result rows to return across the whole run (shared across every input URL, not per URL). For club URLs this caps the number of player rows; for competition URLs it caps club rows; for transfer-list URLs it caps transfer rows. Set to 0 for unlimited. Note: Transfermarkt's all-time transfer-records list contains roughly 100,000 rows — when set to unlimited on transfer URLs, pagination stops there and the run completes early.",
                        "default": 1000
                    },
                    "language": {
                        "title": "Site Language",
                        "enum": [
                            "com",
                            "us",
                            "de",
                            "en",
                            "es",
                            "fr",
                            "it",
                            "nl",
                            "pt-br",
                            "pl",
                            "tr",
                            "jp",
                            "co.uk"
                        ],
                        "type": "string",
                        "description": "Which Transfermarkt regional site to scrape from. Affects language of position labels, country names, and competition names. `English (.com)` is the global default.",
                        "default": "com"
                    },
                    "includeMarketValueHistory": {
                        "title": "Include Market Value History",
                        "type": "boolean",
                        "description": "For player pages, include the full historical market value timeline (date, value, age, club at the time). Adds one extra request per player.",
                        "default": true
                    },
                    "includeTransferHistory": {
                        "title": "Include Transfer History",
                        "type": "boolean",
                        "description": "For player pages, include every transfer in the player's career with date, from-club, to-club, fee, and market value at the time.",
                        "default": true
                    },
                    "includeAchievements": {
                        "title": "Include Achievements (Trophies)",
                        "type": "boolean",
                        "description": "For player pages, include trophies and titles (league titles, cups, individual awards). Adds one extra request per player.",
                        "default": false
                    },
                    "includeInjuries": {
                        "title": "Include Injury History",
                        "type": "boolean",
                        "description": "For player pages, include the injury history table (injury type, dates, games missed). Adds one extra request per player.",
                        "default": false
                    },
                    "includeClubSquad": {
                        "title": "Expand Club Squad to Player Profiles",
                        "type": "boolean",
                        "description": "For club URLs, also fetch a full profile for every player on the squad (not just the squad-row summary). WARNING: a typical first-division squad has 25-35 players — this multiplies your result count and run cost roughly 25-35x per club URL. Leave off if you only need the squad summary.",
                        "default": false
                    },
                    "includeCompetitionClubs": {
                        "title": "Expand Competition to Club Pages",
                        "type": "boolean",
                        "description": "For competition URLs, also fetch a full club page for every club in the competition (not just the league-table summary). WARNING: a typical top-flight league has 18-20 clubs — this multiplies your result count by roughly 18-20x per competition URL. If you also enable 'Expand Club Squad to Player Profiles', the multipliers stack (18 clubs x 25-35 players = 450+ rows per competition). Leave off if you only need the competition summary.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
