# NET-A-PORTER Scraper — Luxury Products, Sizes & Style Codes (`studio-amba/net-a-porter-scraper`) Actor

Scrape NET-A-PORTER for designer clothing, bags, shoes and accessories: prices, per-size stock, category tree, images and the manufacturer style code (mfPartNumber) you can join on across retailers. 20+ markets, no login, no proxy needed.

- **URL**: https://apify.com/studio-amba/net-a-porter-scraper.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

## NET-A-PORTER Scraper

Search NET-A-PORTER and get back structured product data: designer, price, the
full size ladder with per-size stock, category tree, images, and the
manufacturer's own style code.

### Why use this actor

Most luxury scrapers hand you a name and a price. The useful part of this one is
`mfPartNumber`, the brand's own style code, which lets you recognise the same
physical garment when it appears on a different retailer's site.

If you are price-monitoring, building a resale pricing tool, or maintaining a
product database across several luxury retailers, that code is the difference
between "two listings that look similar" and "the same item, two prices".

### What makes the style code matter

Luxury has no EAN. Groceries and electronics have a barcode that every retailer
shares, so joining catalogues is trivial. Fashion does not. Each retailer
invents its own SKU, and the same jacket is `P01165736` at one shop and
`1647597289517280` at another. There is nothing to join on.

NET-A-PORTER publishes the manufacturer's code. Example: `834141QMAC44164` on
an Alexander McQueen denim blazer. That is the code McQueen itself uses
(`alexandermcqueen.com/.../stretch-denim-jacket-834141QMAC44164.html`), and it
has the structure printed on the physical hangtag: six-digit style, five-character
collection and fabric, four-digit colour.

Two of the big luxury retailers expose a real manufacturer code. Farfetch does
it as `brandStyleId`, NET-A-PORTER as `mfPartNumber`. NET-A-PORTER is the
cheaper harvest of the two: one ordinary brand query returns 20 to 50 codes in
a single response.

**One honest limitation.** NET-A-PORTER's search index does not tokenise these
codes, so you cannot search *by* a style code. Searching `834141QMAC44164`
returns nothing. The workflow is: search by brand and category, then match on
`mfPartNumber` yourself. A brand query costs the same as any other and hands
back a batch of codes to filter against.

### How to scrape NET-A-PORTER data

1. Put one or more search terms in **Search Queries**. Brand plus category
   works best: `gucci bag`, `mcqueen denim`, `loewe espadrilles`.
2. Pick a **Market**. `nap_be` is Belgium in EUR; there are 19 markets and each
   has its own prices and stock.
3. Set **Max Items** and run it.

Keep queries short. NET-A-PORTER's index ANDs every token and does not stem, so
each extra word can collapse the result set: `mcqueen denim` returns 5 hits
where `alexander mcqueen denim jacket` returns 1, and `prada shoes` returns 0
where `prada` returns 15. The actor handles this for you (it trims stopwords,
shortens long designer names, and re-asks with a shorter query when a result set
comes back near-empty), but you will get better results by asking bluntly in the
first place.

No login, no cookies to supply, and no proxy. The actor does the anti-bot work
itself.

### Input

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `searchQueries` | Array | No | One or more search terms. Default `["gucci bag"]` |
| `searchQuery` | String | No | Single-term alternative to `searchQueries` |
| `storeCode` | String | No | Market to read, default `nap_be`. See the market list below |
| `maxItems` | Integer | No | Stop after this many products across all queries. Default 50 |
| `pageSize` | Integer | No | Products per search request, default 40. 50 is the ceiling |
| `fetchProductDetails` | Boolean | No | Fetch per-size availability. Default `true` |
| `normalizeQueries` | Boolean | No | Trim long queries to the tokens the index matches. Default `true` |
| `proxyConfiguration` | Object | No | Ignored on purpose, see Limitations |

#### Markets

`nap_be` (Belgium), `nap_nl`, `nap_fr`, `nap_de`, `nap_it`, `nap_es`, `nap_at`,
`nap_ie`, `nap_dk`, `nap_se`, `nap_ch`, `nap_gb` (GBP), `nap_us` (USD),
`nap_ca`, `nap_au`, `nap_hk`, `nap_jp`, `nap_kr`, `nap_ae`.

### Output

| Field | Type | Example |
|-------|------|---------|
| `name` | String | `"Denim blazer"` |
| `brand` | String | `"MCQUEEN"` |
| `mfPartNumber` | String | `"834141QMAC44164"` |
| `price` | Number | `1990` |
| `currency` | String | `"EUR"` |
| `originalPrice` | Number | Only when the item is actually reduced |
| `discount` | String | `"-30%"`, only when reduced |
| `sizes` | Array | Full ladder, one entry per SKU, with availability |
| `inStock` | Boolean | `true` when any size is buyable |
| `stockBadges` | Array | `["LOW STOCK"]`, `["EXCLUSIVE"]`, `["Sold out"]` |
| `lowStock` | Boolean | `true` |
| `category` | Array | `["Clothing", "Jackets", "Blazers"]` |
| `categoryPath` | String | `"Clothing > Jackets > Blazers"` |
| `colour` | String | `"Blue"` |
| `imageUrl` | String | Main image at 920px |
| `imageUrls` | Array | All available views |
| `url` | String | Product page on the chosen market |
| `description` | String | NET-A-PORTER's editorial copy |
| `composition` | String | `"71% Cotton 29% Polyester"` |
| `sizeAndFit` | String | Fit notes and model measurements |
| `sizeSchema` | String | `"RTW - Italy"` |
| `productId` | String | NET-A-PORTER's internal ID |
| `partNumber` | String | Variant code from the product URL |
| `storeCode` | String | `"nap_be"` |
| `searchQuery` | String | The query that returned this product |
| `scrapedAt` | String | ISO 8601 timestamp |

#### Prices are converted for you

NET-A-PORTER's own API quotes money in minor units with a divisor
(`{"amount": 199000, "divisor": 100}`). The `price` and `originalPrice` fields
are already converted to major units, so `1990` means EUR 1990.00. The divisor
is read from the response rather than assumed, so markets that do not use
cents come out right too.

#### Size ladder

Each entry in `sizes` is one SKU:

| Field | Meaning |
|-------|---------|
| `size` | Brand size label. `ONE SIZE` for bags and most jewellery |
| `schemas` | The same size in other scales: IT, UK, US, FR, EU, JP, AU, DE, DK, RU, KR, SML |
| `available` | Buyable right now |
| `soldOut` | Carried in this size, currently out of stock |
| `notStockedOnline` | Never carried online in this size |
| `skuId` | NET-A-PORTER's SKU id |
| `partNumber` | Per-size part number |
| `ean` | Where NET-A-PORTER publishes one, which is not always |

The distinction between `soldOut` and `notStockedOnline` matters if you are
tracking demand. A size that sold out was stocked and sold; a size marked
`notStockedOnline` was never offered.

### Example output

```json
{
    "name": "Denim blazer",
    "brand": "MCQUEEN",
    "mfPartNumber": "834141QMAC44164",
    "price": 1990,
    "currency": "EUR",
    "sizes": [
        {
            "size": "40",
            "schemas": { "IT": "IT 40", "UK": "UK 8", "US": "US 4", "FR": "FR 36", "SML": "S" },
            "available": true,
            "soldOut": false,
            "notStockedOnline": false,
            "skuId": "3074457345629607675",
            "partNumber": "0400664169370",
            "ean": "813894730"
        },
        {
            "size": "42",
            "schemas": { "IT": "IT 42", "UK": "UK 10", "US": "US 6", "SML": "M" },
            "available": false,
            "soldOut": true,
            "notStockedOnline": false,
            "skuId": "3074457345629607677",
            "partNumber": "0400664169387"
        }
    ],
    "inStock": true,
    "stockBadges": ["LOW STOCK"],
    "lowStock": true,
    "category": ["Clothing", "Jackets", "Blazers"],
    "categoryPath": "Clothing > Jackets > Blazers",
    "colour": "Blue",
    "imageUrl": "https://www.net-a-porter.com/variants/images/46376663162865360/in/w920.jpg",
    "url": "https://www.net-a-porter.com/en-be/shop/product/mcqueen/clothing/blazers/denim-blazer/46376663162865360",
    "composition": "98% Cotton 2% Elastane",
    "sizeSchema": "RTW - Italy",
    "productId": "3074457345629607670",
    "partNumber": "46376663162865360",
    "storeCode": "nap_be",
    "searchQuery": "mcqueen denim",
    "scrapedAt": "2026-07-29T09:15:22.104Z"
}
```

### Speed and cost

The run starts with a one-off browser warm-up of about 7 seconds. After that,
every search page and every product detail costs roughly 0.2 seconds.

With per-size availability on, one product is one detail request. A measured
run: 15 products across 3 queries in 12.6 seconds including warm-up. A 500-item
run lands around 2 minutes.

Turning **Fetch Per-Size Availability** off removes one request per product and
roughly halves the time, at the cost of the `sizes` ladder, `description`,
`composition` and `sizeAndFit`.

No proxy is used, so there is no proxy cost.

### Limitations

- **You cannot search by style code.** NET-A-PORTER's index does not tokenise
  `mfPartNumber`. Search by brand and category, then filter on the code.
- **Leave the proxy off.** Residential exits score worse on this site than a
  direct connection: measured 403 through a residential exit where direct
  returned 200. The setting is honoured if you turn it on, but it is an escape
  hatch for a burned IP range, not a default.
- **The occasional run needs a second attempt.** NET-A-PORTER's protection
  scores the exit IP, and consecutive runs from the same range do not always
  get the same answer. The actor retries the browser warm-up up to four times
  with a fresh fingerprint each time, so this normally costs you 10 to 20
  seconds rather than a failed run.
- **Search relevance is weak.** The index ANDs tokens and does not stem, so
  `dress` finds 2,450 items but `prada shoes` finds none. Ask bluntly.
- **Per-size availability needs the detail fetch.** With
  `fetchProductDetails: false`, `sizes` comes back empty and `inStock` falls
  back to the sold-out badge.
- **One colourway is one record.** A shoe in three colours returns three
  records with three different style codes, which is correct: each colourway
  has its own manufacturer code.
- **NET-A-PORTER is a full-price retailer.** `originalPrice` and `discount`
  are usually absent because most items are not reduced.
- Data is scraped from the public website and may change without notice.
  Respect the website's terms of service and use responsibly.

### Related scrapers

- [Mytheresa Scraper](https://apify.com/studio-amba/mytheresa-scraper) — the
  other big European full-price luxury retailer. No manufacturer style code,
  so it cannot be joined the same way.
- [Vinted Scraper](https://apify.com/studio-amba/vinted-scraper) — Europe's
  largest secondhand fashion marketplace. Pair it with this actor to compare
  retail against resale.
- [Primark Scraper](https://apify.com/studio-amba/primark-scraper) — the other
  end of the fashion price ladder.
- [Rituals Scraper](https://apify.com/studio-amba/rituals-scraper) — luxury
  cosmetics and home fragrance.
- [ICI PARIS XL Scraper](https://apify.com/studio-amba/iciparisxl-scraper) —
  Belgian beauty and perfume.

### Need this data on a schedule, or a custom version?

We run this scraper as a managed service for businesses: scheduled runs,
deduplication, delta detection, and delivery to your inbox, Google Sheets,
or API — maintenance included. We can also build a custom version with your
exact fields and filters, or combine multiple luxury sources into one feed
joined on the manufacturer style code.

# Actor input Schema

## `searchQueries` (type: `array`):

One or more search terms. NET-A-PORTER's index is relevance-poor and rewards short, blunt terms: 'mcqueen denim' returns 5 hits where 'alexander mcqueen denim jacket' returns 1. Brand-plus-category is the sweet spot.

## `searchQuery` (type: `string`):

Convenience alternative to Search Queries when you only want one term.

## `storeCode` (type: `string`):

Which NET-A-PORTER storefront to read. Prices and stock are per market. Default nap\_be (Belgium, EUR).

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

Stop after this many products across all queries.

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

Products per search API request. 60 is the verified ceiling; higher values are clamped.

## `fetchProductDetails` (type: `boolean`):

Fetch each product's detail record to get the real size ladder with per-size stock, composition and description. Costs one extra API call per product (~0.2s). Turn off for a faster, thinner listing-only scrape.

## `normalizeQueries` (type: `boolean`):

Trim long queries down to the blunt tokens NET-A-PORTER's index actually matches (drops stopwords, shortens 'alexander mcqueen' to 'mcqueen', keeps 3 tokens). Turn off to send your query verbatim.

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

Leave this OFF. A direct connection is what gets past net-a-porter.com's Akamai protection; measured 2026-07-29, residential exits returned HTTP 403 where direct returned 200. It is here as an escape hatch: if the actor starts failing its warm-up, Akamai may be scoring the outbound IP range badly, and routing the browser through a different exit is the one thing that can fix that.

## Actor input object example

```json
{
  "searchQueries": [
    "gucci bag",
    "mcqueen denim"
  ],
  "storeCode": "nap_be",
  "maxItems": 10,
  "pageSize": 40,
  "fetchProductDetails": true,
  "normalizeQueries": true,
  "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 = {
    "searchQueries": [
        "gucci bag",
        "mcqueen denim"
    ],
    "storeCode": "nap_be",
    "maxItems": 10,
    "pageSize": 40,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/net-a-porter-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 = {
    "searchQueries": [
        "gucci bag",
        "mcqueen denim",
    ],
    "storeCode": "nap_be",
    "maxItems": 10,
    "pageSize": 40,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/net-a-porter-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 '{
  "searchQueries": [
    "gucci bag",
    "mcqueen denim"
  ],
  "storeCode": "nap_be",
  "maxItems": 10,
  "pageSize": 40,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call studio-amba/net-a-porter-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/51o4eo8dMbI0CUfHe/builds/ci5rg6vsCnSfeTovW/openapi.json
