# 24S Scraper — Luxury Fashion Prices, Stock & Sizes (`studio-amba/24s-scraper`) Actor

Scrape 24S (24s.com), LVMH's own multi-brand luxury e-commerce site, for designer clothing, bags, shoes and accessories: prices (incl. active discounts), real per-size stock, composition, images and category tree. No login required.

- **URL**: https://apify.com/studio-amba/24s-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/actors/running/actors-in-store.md#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

## 24S Scraper

Search or browse 24S.com — LVMH's own multi-brand luxury e-commerce site — and
get back structured product data: designer, price with active discounts, the
real per-size stock ladder, composition, images and category tree.

### Why use this actor

24S runs its own price events independently of the brands it stocks, so a
garment can be full price at the brand's own store and reduced on 24S. The
useful part of this actor is that it reads the actual post-discount price off
the product page, not the "was" price the category grid shows even during a
sale (verified 2026-09-14: a -40% coat's listing card reports the full
€2,585, the product page reports the real €1,551).

If you are price-monitoring luxury retail, tracking sale depth across
retailers, or maintaining a product database, that distinction is the
difference between a feed that quietly reports the wrong number during every
sale and one that doesn't.

### How to scrape 24S data

1. Put one or more search terms in **Search Queries**, e.g. `gucci bag`,
   `khaite dress`. Pick **Universe** (`women` or `men`).
2. Pick a **Country / Market**. `be` is Belgium in EUR; markets each have
   their own prices and stock.
3. Set **Max Items** and run it.

No login, no cookies to supply, and no proxy. The actor handles 24S's
anti-bot protection itself.

#### Category mode

Set **Category Slugs** to browse a category listing directly instead of
searching.

1. Take the part of a 24S category URL after the locale. For
   `https://www.24s.com/en-be/women/ready-to-wear/dresses` that is
   `women/ready-to-wear/dresses`.
2. Put it in **Category Slugs**: `["women/ready-to-wear/dresses"]`. You can
   list several, and you can also paste the full URL directly — the locale is
   stripped for you.
3. Set **Max Items** and run it. Pagination through the category is handled
   for you.

Other slugs that work the same way: `women/brands/dior`, `women/new-arrivals`,
`women/events/shop-sale`, `men/shoes`. **Category Slugs** takes priority over
**Search Queries** when both are set.

### Input

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `categorySlugs` | Array | No | Browse category listings directly, e.g. `["women/ready-to-wear/dresses"]`. Takes priority over Search Queries. See Category mode above |
| `searchQueries` | Array | No | One or more search terms. Default `["gucci bag"]` |
| `searchQuery` | String | No | Single-term alternative to `searchQueries` |
| `universe` | String | No | `women` (default) or `men`. Ignored in category mode |
| `country` | String | No | Market to read as an ISO 2-letter code, default `be`. `gb` is the UK (GBP) — there is no `uk` locale |
| `maxItems` | Integer | No | Stop after this many products across all queries or categories. Default 50 |
| `fetchProductDetails` | Boolean | No | Fetch the real size ladder, composition and post-discount price. Default `true` |
| `proxyConfiguration` | Object | No | Ignored on purpose, see Limitations |

### Output

| Field | Type | Example |
|-------|------|---------|
| `name` | String | `"Ria maxi dress"` |
| `brand` | String | `"KHAITE"` |
| `sku` | String | `"KHA3579JOWH5N1A100"` |
| `shortSku` | String | `"KHA3579JOWH"`, the colourway-level code |
| `price` | Number | `1551` — post-discount when `fetchProductDetails` is on |
| `currency` | String | `"EUR"` |
| `originalPrice` | Number | `2585`, only when actually reduced |
| `discount` | String | `"-40%"`, only when reduced |
| `color` | String | `"sabbia"` |
| `inStock` | Boolean | `true` when any size is buyable |
| `sizes` | Array | Real per-size stock, one entry per SKU |
| `category` | Array | `["Women", "Ready-to-wear", "Coats", "Short coats"]` |
| `categoryPath` | String | `"Women > Ready-to-wear > Coats > Short coats"` |
| `imageUrl` | String | Main product image |
| `imageUrls` | Array | All available views |
| `url` | String | Product page on the chosen market |
| `description` | String | 24S's editorial copy |
| `composition` | String | `"100% cashmere"` |
| `madeIn` | String | `"Italy"` |
| `gender` | String | `"women"` |
| `seller` | String | `"24s"` on everything sampled — 24S is its own seller, not a marketplace |
| `country` | String | `"BE"` |
| `searchQuery` | String or null | The query that returned this product, null in category mode |
| `categorySlug` | String or null | The category that returned this product, null in search mode |
| `scrapedAt` | String | ISO 8601 timestamp |

#### 24S does not publish a manufacturer style code

Unlike NET-A-PORTER (`mfPartNumber`) or Farfetch (`brandStyleId`), 24S's
product pages carry no brand-issued code anywhere in the record — only its
own internal SKU. `sku` and `shortSku` are useful as 24S-internal identifiers
(stable across a run, unique per colourway/size), but they will not match the
same garment's code on another retailer's site or the brand's own store.

#### Size ladder

Each entry in `sizes` is one SKU, populated only when `fetchProductDetails`
is on:

| Field | Meaning |
|-------|---------|
| `sizeLabel` | Brand size label, e.g. `"US 4"`. `"no size"` for bags and most accessories |
| `sizeCode` | 24S's internal size code |
| `longSKU` | Full SKU for this exact size |
| `hasStock` | Buyable right now — this is real per-item stock, not a size schema. Verified 2026-09-14: a dress with 3 sizes had one sold out (`hasStock: false`, `stock: 0`) and two available |
| `stock` | Unit count |

### Example output

```json
{
    "name": "Double-breasted coat",
    "brand": "MAX MARA",
    "sku": "MAXNEW57BEI7E11A00",
    "shortSku": "MAXNEW57BEI",
    "price": 1551,
    "currency": "EUR",
    "originalPrice": 2585,
    "discount": "-40%",
    "color": "sabbia",
    "inStock": true,
    "sizes": [
        { "sizeLabel": "FR 40", "sizeCode": "7E11A", "longSKU": "MAXNEW57BEI7E11A00", "hasStock": true, "stock": 1 }
    ],
    "category": ["Women", "Ready-to-wear", "Coats", "Short coats"],
    "categoryPath": "Women > Ready-to-wear > Coats > Short coats",
    "imageUrl": "https://www.24s.com/static/images/XhWUI8C0j4SEFIcruBwbjQ4aGmM=/fit-in/250x0/4de0a270c9374ceb815a65e55b9d13bd",
    "url": "https://www.24s.com/en-be/double-breasted-coat-max-mara_MAXNEW57BEI?color=beige",
    "description": "A masterpiece of modern elegance from Max Mara...",
    "composition": "100% cashmere",
    "madeIn": "Italy",
    "gender": "women",
    "seller": "24s",
    "country": "BE",
    "searchQuery": null,
    "categorySlug": "women/events/shop-sale",
    "scrapedAt": "2026-09-14T09:23:59.699Z"
}
```

### Speed and cost

The run starts with a one-off browser warm-up of about 5-8 seconds to get
past 24S's anti-bot protection. After that, every listing page and every
product detail page is a plain HTTP fetch at roughly 0.3-0.6 seconds — no
browser needed for the rest of the run. A measured run: 50 products across a
default search in 37.7 seconds including warm-up, with no re-warm needed for
the whole run.

Turning **Fetch Product Detail** off removes one fetch per product, at the
cost of the `sizes` ladder, `description`, `composition`, `madeIn`, and the
real post-discount `price`.

No proxy is used, so there is no proxy cost. Billing is pay-per-result: you
are charged per product row returned, plus a small per-run start fee — usage
cost only settles once a run finishes as **SUCCEEDED**, not while it is still
running.

#### Cost estimate

This actor charges per result rather than per compute unit. Budget roughly
**$0.002 per product** plus a small per-run start fee — for a 1,000-item run
that's about $2, most of it well under a minute of Camoufox warm-up and
sub-second HTTP fetches after that.

### Limitations

- **No manufacturer style code.** See above — `sku`/`shortSku` are 24S's own
  identifiers, not a cross-retailer join key.
- **Leave the proxy off.** A direct connection is what gets past 24S's
  Akamai protection; the whole luxury cluster this actor sits alongside
  (NET-A-PORTER, Mytheresa, Farfetch) measures residential exits performing
  worse than direct. The setting is honoured if you turn it on, but it is an
  escape hatch for a burned IP range, not a default.
- **The listing price can be stale during a sale.** With `fetchProductDetails:
  false`, `price` is whatever the category grid shows, which 24S renders as
  the pre-discount figure even on a reduced item. Turn `fetchProductDetails`
  on for an accurate current price.
- **One colourway is one record.** A bag in three colours returns three
  records with three different SKUs, which is correct.
- Data is scraped from the public website and may change without notice.
  Respect the website's terms of service and use responsibly.

### Related scrapers

- [NET-A-PORTER Scraper](https://apify.com/studio-amba/net-a-porter-scraper) —
  publishes a real manufacturer style code (`mfPartNumber`), useful for
  cross-retailer matching that this actor cannot do on its own.
- [Farfetch Scraper](https://apify.com/studio-amba/farfetch-scraper) — the
  multi-boutique luxury marketplace, `brandStyleId` on the product detail.
- [Mytheresa Scraper](https://apify.com/studio-amba/mytheresa-scraper) — the
  other big European full-price luxury retailer.
- [Vinted Scraper](https://apify.com/studio-amba/vinted-scraper) — Europe's
  largest secondhand fashion marketplace, useful for comparing retail against
  resale.

### 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.

# Actor input Schema

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

One or more search terms, e.g. 'gucci bag'.

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

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

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

Browse 24S category listings directly instead of searching. Paths are relative to the locale, e.g. 'women/ready-to-wear/dresses', 'women/brands/dior', 'women/new-arrivals', 'men/shoes'. You can also paste a full category URL, e.g. 'https://www.24s.com/en-be/women/ready-to-wear/dresses' — the locale is stripped automatically. When this is set, Search Queries are ignored.

## `universe` (type: `string`):

Which storefront section to search under when using Search Queries. Ignored when Category Slugs is set (the universe is already part of the path there).

## `country` (type: `string`):

Which 24S storefront to read, as an ISO 2-letter country code (be, fr, de, it, gb, ...). Prices and currency follow the market. Default 'be' (Belgium, EUR). Note: 'gb' is the correct code for the UK storefront (GBP) — there is no 'uk' locale on 24S.

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

Stop after this many products across all queries/categories.

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

Fetch each product's detail page to get the real size ladder with per-size stock, composition and the ACTUAL current price. Without this, the price field can be the pre-discount price during a sale (the listing page itself only ever shows the full price, verified 2026-09-14). Costs one extra page fetch per product (~0.3-0.5s). Turn off for a faster, thinner listing-only scrape.

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

Leave this OFF. A direct connection is what gets past 24s.com's Akamai protection; measured 2026-09-14, a direct Camoufox warm-up got HTTP 200 on the first attempt, matching the whole luxury cluster (net-a-porter.com, mytheresa.com, farfetch.com) where residential exits perform WORSE than direct. 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"
  ],
  "universe": "women",
  "country": "be",
  "maxItems": 10,
  "fetchProductDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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"
    ],
    "universe": "women",
    "country": "be",
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/24s-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"],
    "universe": "women",
    "country": "be",
    "maxItems": 10,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/24s-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).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"
  ],
  "universe": "women",
  "country": "be",
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call studio-amba/24s-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/24s-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/owaXGCl5pte2Ghmks/builds/989VCKev0myp9KXHm/openapi.json
