# Mytheresa Scraper — Per-Size Stock, Composition & Prices (`studio-amba/mytheresa-scraper-v2`) Actor

Scrape mytheresa.com luxury fashion by category, designer or sale. Full size ladder with real per-size availability, prices, markdowns, colour, images and category tree. Full mode adds composition, care, fit, measurements and the designer's own colourway name.

- **URL**: https://apify.com/studio-amba/mytheresa-scraper-v2.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 result scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Mytheresa Scraper

Scrape [mytheresa.com](https://www.mytheresa.com), the Munich luxury e-tailer, and get back designer products with their **full size ladder and real per-size availability** — which sizes are actually buyable right now, not the size chart the garment theoretically comes in.

Browse by category, by designer, or across the sale. Eleven markets. No login, no cookies to supply, no proxy needed.

### What you get

Every product, in every mode:

| | |
|---|---|
| Name, designer, description | Mytheresa's own copy |
| Price, original price, discount | Converted to major units, markdown only when there really is one |
| **Sizes with per-size stock** | `[{size: "38", sizeHarmonized: "M", sku: "P01181397-3", inStock: true, lowStockHint: 4}, …]` |
| Colour, category tree, images | Full breadcrumb, every image |
| Product code, designer ID, season code | Mytheresa's identifiers |
| VAT rate and whether it is included | Per market |

Set `mode: "full"` and each product also carries composition, care instructions, country of manufacture, lining, closure, fit notes, garment measurements per size, sustainability claims, and the **designer's own colourway name**.

### Depth: fast search vs full crawl

Mytheresa does **not** use a hosted search service (no Algolia, Typesense, Constructor.io, Bloomreach or Klevu). It runs its own GraphQL gateway, and that gateway serves both the listing pages and the product pages. This actor reads both, and you choose how deep:

| | Fast (`mode: "index"`) | Full (`mode: "full"`) |
|---|---|---|
| Speed | up to 120 products per request, under a second | roughly 1 product per second |
| Requests | 1 per 120 products | 1 per 120 products **plus 1 per product** |
| Fields | name, designer, price, markdown, **per-size stock**, colour, category tree, images, description, product code, season code, VAT | everything in fast mode, plus the below |
| Not included | `designerColourName`, `materials`, `composition`, `careInstructions`, `madeIn`, `lining`, `closure`, `features`, `sizeAndFit`, `measurements`, `sustainability` | — |
| Best for | price monitoring, availability tracking, catalogue snapshots, assortment analysis | product records, matching against other retailers, compliance, enrichment |

Those missing fields are not a limitation of this actor. They are genuinely absent from Mytheresa's listing payload: measured over 360 listing records, `features` and `sizeAndFit` came back empty on 100% of them and are populated on 100% of product records. Everything else — including the per-size stock — is already there at listing level, which is why fast mode is a complete commercial record rather than a teaser.

Every output row carries `detailFetched`, so you can always tell which depth a record came from.

### Per-size stock is real stock

This is the point of the actor, so it is worth being precise about.

Some retailers return a size *schema* — every size the scale defines, whether or not any of it exists. Mytheresa does not. Measured across 360 products:

- average in-stock ratio **0.85**, not 1.0
- **164 of 360** products had at least one sold-out size
- `lastStockQuantityHint` runs 0–5, and 0 always coincides with `inStock: false`

A real record:

```json
"sizeLadder":   ["36", "38", "40", "42", "44", "46", "48", "50"],
"sizesInStock": ["44", "48"],
"sizes": [
  { "size": "44", "sizeHarmonized": "M",  "sku": "P01181397-6", "inStock": true,  "lowStockHint": 1 },
  { "size": "46", "sizeHarmonized": "L",  "sku": "P01181397-7", "inStock": false },
  { "size": "48", "sizeHarmonized": "XL", "sku": "P01181397-8", "inStock": true,  "lowStockHint": 2 }
]
```

`lowStockHint` caps at 5, so treat 5 as "five or more". It is Mytheresa's low-stock warning, not an inventory feed.

### How to scrape Mytheresa data

1. Pick a **section**: `women`, `men` or `kids`.
2. Pick what to browse. Any one of:
   - **`categorySlugs`** — `clothing`, `clothing/dresses`, `shoes`, `bags`, `accessories`, `sale`, `sale/clothing`, `new-arrivals`, `designers/gucci`, `designers/gucci/bags`. Relative to the section, no locale, no leading section. `/women/clothing` will not work.
   - **`designer`** — plain language: `Gucci`, `Saint Laurent`, `Dolce&Gabbana`. Resolved against Mytheresa's own designer index, so you do not have to know that Dolce\&Gabbana's slug is `dolce-gabbana`.
   - nothing at all, which browses the section's whole clothing catalogue.
3. Pick a **market** (`BE`, `DE`, `GB`, `US`, `INT`, …). Currency *and* assortment differ.
4. Pick a **depth** (`index` or `full`) and a **maxItems**.
5. Run.

Example input:

```json
{
  "mode": "full",
  "section": "women",
  "market": "BE",
  "categorySlugs": ["clothing/dresses"],
  "onlyInStock": true,
  "maxItems": 500
}
```

Example output row (fast mode, trimmed):

```json
{
  "name": "VLogo cotton tweed minidress",
  "brand": "Valentino",
  "price": 1980,
  "currency": "EUR",
  "originalPrice": null,
  "sizeLadder": ["36","38","40","42","44","46","48","50"],
  "sizesInStock": ["44","48"],
  "inStock": true,
  "sizeType": "IT",
  "colour": "white",
  "category": "Day",
  "categories": ["Clothing","Dresses","Day"],
  "sku": "P01181397",
  "seasonCode": "26/2",
  "vatIncluded": true,
  "vatPercentage": 21,
  "url": "https://www.mytheresa.com/euro/en/women/valentino-cotton-tweed-minidress-white-p01181397",
  "detailFetched": false
}
```

And what full mode adds to the same product:

```json
{
  "designerColourName": "Milky/Nerp",
  "materials": "100% cotton",
  "composition": ["Material: 100% cotton", "Trim: 55% cotton, 45% viscose", "Lining: 100% silk"],
  "careInstructions": "dry clean",
  "madeIn": "Italy",
  "closure": "concealed zipped side",
  "sizeAndFit": ["True to size", "Designed for a loose fit", "Non-stretchy fabric"],
  "measurements": { "Chest circumference": { "38": "84,0" }, "Length": { "38": "87,0" } },
  "detailFetched": true
}
```

### Markets

| Input | Store | Currency |
|---|---|---|
| `BE` `NL` `FR` `IE` `IT` `ES` | euro | EUR |
| `DE` `AT` | de | EUR |
| `GB` | gb | GBP |
| `US` | us | USD |
| `INT` | int | EUR |

Assortment differs per market — women's clothing runs 16,765 items on International and 18,342 on US — so pick the one you actually care about rather than assuming a currency conversion.

### Limitations, stated plainly

**There is no manufacturer style code.** Luxury has no EAN, so a brand style code is the only reliable way to match the same physical product across retailers. Farfetch publishes one (`brandStyleId`) and NET-A-PORTER publishes one (`mfPartNumber`). **Mytheresa publishes none.** This was checked against Mytheresa's own complete product-page field selection across 70 products spanning every department: no MPN, no GTIN, no EAN anywhere in their data. `sku` (`P01167433`) is Mytheresa's internal code and `designerId` is Mytheresa's internal designer id.

The best available substitute is `designerColourName` — the brand's own colourway name, like "Caramel Cognac" or "Nero/Ottone Vintage" — present on about 81% of products in full mode. Brand + product name + designer colour name is a much stronger join key than brand + "brown". Use full mode if cross-retailer matching is what you are here for.

**There is no free-text search.** Mytheresa's search endpoint exists but checks the client's TLS fingerprint in a way its listing endpoint does not, and a Node actor cannot reproduce a browser fingerprint without native libraries. Rather than ship a feature that works intermittently, this actor browses the category tree, which is not gated and reaches the same products: the full category hierarchy, 267 women's / 142 men's / 65 kids' designer pages, and a sale listing of roughly 49,000 items. The `keywords` input filters what has been browsed and is not a query to Mytheresa.

**Prices reflect one market at a time.** Run once per market if you need a comparison.

**`sizeType`** (FR / IT / UK) is populated on about half of records. `sizeHarmonized` (XS/S/M/L) is on most.

### Cost and speed

Fast mode fetches 120 products per request in well under a second, with no browser and no proxy, so a 10,000-product catalogue snapshot is on the order of 85 requests and a couple of minutes. Full mode adds one request per product; budget roughly a second each.

Mytheresa's gateway stalls on about 4% of requests under load — the connection hangs rather than returning an error. The actor retries with backoff and logs how many stalls it absorbed, so a clean run reporting zero stalls is normal and a run reporting many is a signal worth watching.

### Proxy

Leave it off. Mytheresa's API answers a direct request in about half a second with no cookies. Residential proxy exits are badly scored against Akamai-fronted luxury sites and measured worse than a direct connection, so `proxyConfiguration` is ignored on purpose and the default prefill has it disabled. Turning it on costs money and adds failure modes for nothing.

### Related scrapers

- **NET-A-PORTER Scraper** — the other luxury e-tailer with per-size stock, and one of only two that publish a real manufacturer style code
- **Yoox Scraper** — YNAP's outlet, and the only luxury source that states a supplier RRP next to the discounted price
- **Farfetch Scraper** — marketplace breadth plus `brandStyleId`
- **Zalando Scraper** — mass-market comparison point
- **Vinted Scraper** — resale prices for the same brands

### Support

Open an issue on the actor page. If a run fails, include the run ID and the input — the actor's error messages name the specific cause (bad slug, filters excluding everything, gateway stall) rather than failing silently.

# Actor input Schema

## `mode` (type: `string`):

Fast (index) reads Mytheresa's listing API only — up to 120 products per request, under a second each. It already includes real per-size stock. Full adds one product-page request per item to pick up composition, care instructions, fit notes, garment measurements and the designer colour name, at roughly one product per second.

## `categorySlugs` (type: `array`):

Mytheresa category paths, relative to the section and WITHOUT a locale or leading section. Valid: 'clothing', 'clothing/dresses', 'shoes', 'bags', 'accessories', 'sale', 'sale/clothing', 'new-arrivals', 'designers/gucci', 'designers/gucci/bags'. Not valid: '/women/clothing' or '/euro/en/women/clothing'. Leave empty and specify nothing else to browse the section's whole catalogue.

## `keywords` (type: `array`):

Keep only products whose name, designer, description, category or colour contains one of these words, e.g. 'cashmere', 'loafer'. This is a filter over what the actor browses, NOT a query to Mytheresa's search engine — their search endpoint checks the client's TLS fingerprint and is unreachable from a Node actor, so this scraper browses the category tree instead. Pair it with a category and enough Max items, because a narrow keyword against a small category returns nothing.

## `designer` (type: `string`):

Filter to one designer, in plain language ('Gucci', 'Saint Laurent', 'Dolce\&Gabbana'). Resolved to Mytheresa's own designer page, so you get that designer's whole assortment for the chosen section.

## `section` (type: `string`):

Which side of the catalogue to read. This is a required header on Mytheresa's API, and a product only resolves under its own section — a women's product looked up as men's comes back as not found.

## `market` (type: `string`):

Which Mytheresa storefront to read. Assortment AND currency differ per market, so this is a real choice and not just a currency switch — the women's clothing catalogue runs 16,765 items on International and 18,342 on US.

## `maxItems` (type: `integer`):

Maximum number of products to return across all categories.

## `sort` (type: `string`):

Mytheresa accepts exactly these four. Anything else makes their gateway return a server error, so other values are rejected here rather than passed through.

## `onlySale` (type: `boolean`):

Keep only products that carry a real markdown. With no category specified this also switches the default browse to Mytheresa's sale listing (around 49,000 items).

## `onlyInStock` (type: `boolean`):

Drop products where every size is sold out. Mytheresa lists sold-out sizes rather than hiding them, which is exactly why this actor reports per-size stock — turn this on if you only want buyable products.

## `minPrice` (type: `integer`):

Only return products at or above this price, in the market's own currency.

## `maxPrice` (type: `integer`):

Only return products at or below this price, in the market's own currency.

## `filtersQueryParams` (type: `string`):

Raw facet filter string passed to Mytheresa, e.g. 'colors=black' or 'materials=Cashmere\&sizesHarmonized=M'. Facet names are categories, colors, designers, materials, sizesHarmonized, fit and rise. Values are case-sensitive: 'materials=Silk' matches, 'materials=silk' returns nothing.

## `pageSize` (type: `integer`):

Mytheresa clamps this to a maximum of 120 and a minimum of 12. Leave at the maximum unless you are deliberately slowing the crawl down.

## `requestDelayMs` (type: `integer`):

Pacing between API calls. Mytheresa's gateway stalls on roughly 4% of requests under load, so a small delay makes long runs noticeably more reliable. The actor retries stalled requests regardless.

## `proxyConfiguration` (type: `object`):

Deliberately ignored, and off by default. Mytheresa's API answers a direct request in about half a second with no cookies at all, while residential exits are badly scored against Akamai-fronted luxury sites and measured worse than direct. Kept for Apify Store compatibility.

## Actor input object example

```json
{
  "mode": "index",
  "categorySlugs": [
    "bags"
  ],
  "section": "women",
  "market": "BE",
  "maxItems": 20,
  "sort": "recommendation",
  "onlySale": false,
  "onlyInStock": false,
  "pageSize": 120,
  "requestDelayMs": 250,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "mode": "index",
    "categorySlugs": [
        "bags"
    ],
    "section": "women",
    "market": "BE",
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/mytheresa-scraper-v2").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 = {
    "mode": "index",
    "categorySlugs": ["bags"],
    "section": "women",
    "market": "BE",
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/mytheresa-scraper-v2").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 '{
  "mode": "index",
  "categorySlugs": [
    "bags"
  ],
  "section": "women",
  "market": "BE",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call studio-amba/mytheresa-scraper-v2 --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/UgrMrdqr4s7r2dJ4Q/builds/pXQ4eQj7RcpsKAOf7/openapi.json
