# Marks & Spencer Scraper — UK Clothing, Home & Beauty Prices (`studio-amba/marksandspencer-scraper`) Actor

Scrape Marks & Spencer (marksandspencer.com) category listings for clothing, home, beauty and lingerie: name, brand, price, discount, stock status, rating and images. No login, no cookies, category-URL based.

- **URL**: https://apify.com/studio-amba/marksandspencer-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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Marks & Spencer Scraper

Scrape marksandspencer.com category pages and get back structured product
rows: name, brand, price, discount, stock status, rating and images — no
login, no cookies, no browser required.

### Why use this actor

Marks & Spencer (M\&S) is one of the UK's largest general retailers —
clothing, homeware, beauty and lingerie across menswear, womenswear, kids'
and home ranges — and there was no coverage of it in this catalogue before.
If you're tracking UK high-street pricing, building a competitor price feed,
or comparing M\&S against Next, Debenhams, House of Fraser or Harrods, this
actor gives you a clean, structured read of its catalogue by category.

### marksandspencer.com is a plain fetch — no proxy fight required

M\&S category pages are fully server-rendered by the site's own Next.js
frontend: the complete product list for a page — id, brand, title, price,
"was" price, stock indicator, review score, image asset IDs — is embedded
directly in the HTML as a `__NEXT_DATA__` JSON blob. There's no hidden API
call to reverse-engineer and no JavaScript execution needed to see the data
a visitor sees.

Akamai Bot Manager infrastructure **is** present on marksandspencer.com
(sensor cookies and an `akamai-grn` header show up on every response), but
it was not actively challenging requests when this actor was built —
repeated plain fetches, including with no User-Agent header and no cookies
at all, all returned clean HTTP 200 responses with the full product payload.
This actor therefore defaults to Apify's automatic proxy pool rather than
paying for residential IPs it doesn't need. If Akamai tightens enforcement
later, switch **Proxy Configuration** to `RESIDENTIAL` (country `GB`) in the
input — no code change required.

### How to scrape Marks & Spencer data

1. Find a category page on [marksandspencer.com](https://www.marksandspencer.com)
   — browse the site's own menu (e.g. Beauty → Clinique, Women → Dresses) and
   copy the URL. It will look like
   `https://www.marksandspencer.com/l/beauty/clinique`.
2. Paste that URL into **Category URL**. Leave it empty to scrape the
   default category (Clinique beauty) — useful for a quick test run.
3. Set **Max Results** — products load in pages of 48, and large categories
   (womenswear, menswear) can hold thousands of items, so this cap always
   applies (hard-capped at 2000/run).
4. Run it. The actor requests the category page directly, extracts the
   embedded `__NEXT_DATA__` product list, walks `?page=N` until it has
   enough rows or runs out of stock (using the category's own `totalItems`
   count to know when to stop), and pushes one row per product to the
   dataset.
5. Export the dataset as JSON/CSV/Excel from the Apify Console, or pull it
   via the API.

### Input

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `categoryUrl` | String | No | A marksandspencer.com `/l/{department}/{sub-category}` listing URL. Defaults to the Clinique beauty category if left empty. |
| `maxResults` | Integer | No | Maximum products to return (default: 60, capped at 2000). |
| `proxyConfiguration` | Object | No | Proxy settings. Automatic (no groups) by default — switch to RESIDENTIAL/GB only if you see repeated failures at high volume. |

### Output

Each result contains:

| Field | Type | Example |
|-------|------|---------|
| `name` | String | `"Jumbo Dramatically Different™ Moisturizing Lotion 200ml"` |
| `brand` | String | `"Clinique"` |
| `price` | Number | `44` |
| `currency` | String | `"GBP"` |
| `originalPrice` | Number | `55` |
| `discount` | String | `"-20%"` |
| `sku` | String | `"60745720"` |
| `productId` | String | `"P60745720"` |
| `inStock` | Boolean or null | `true` |
| `imageUrl` | String | Primary product image URL |
| `imageUrls` | Array | All available product images |
| `category` | String | `"Moisturiser"` |
| `rating` | Number | `4.11` |
| `reviewCount` | Number | `388` |
| `url` | String | Canonical product page URL |
| `scrapedAt` | String | ISO 8601 timestamp |

### Example output

```json
{
  "name": "Jumbo Dramatically Different™ Moisturizing Lotion 200ml",
  "brand": "Clinique",
  "price": 44,
  "currency": "GBP",
  "originalPrice": 55,
  "discount": "-20%",
  "sku": "60745720",
  "productId": "P60745720",
  "inStock": true,
  "imageUrl": "https://asset1.cxnmarksandspencer.com/is/image/mands/MS_07_T23_6799G_NC_X_EC_0",
  "imageUrls": [
    "https://asset1.cxnmarksandspencer.com/is/image/mands/MS_07_T23_6799G_NC_X_EC_6",
    "https://asset1.cxnmarksandspencer.com/is/image/mands/MS_07_T23_6799G_NC_X_EC_0"
  ],
  "category": "Moisturiser",
  "rating": 4.11,
  "reviewCount": 388,
  "url": "https://www.marksandspencer.com/jumbo-dramatically-different-moisturizing-lotion-200ml/p/hbp60745720",
  "scrapedAt": "2026-09-08T14:10:48.234Z"
}
```

### Limitations

- Product **descriptions are not included** — the listing payload this
  actor reads doesn't carry the long-form description text (only the
  product detail page does). Every other field above comes straight from
  the listing page.
- `inStock` reflects M\&S's own coded stock-level indicator. The site only
  distinguishes "out of stock" unambiguously in that code; anything else is
  treated as in stock. When the indicator is missing entirely, `inStock` is
  `null` — never guessed as `false`.
- This actor scrapes by **category URL**, not free-text search — there's
  no public search endpoint on marksandspencer.com that returns the same
  server-rendered product data the category pages do.
- Currency is always GBP — marksandspencer.com is the UK storefront only.

### Cost estimate

No residential proxy or browser rendering is needed for the default setup,
so runs are fast and cheap — mostly Apify platform compute, no per-request
proxy fee. A 1000-item run typically completes in well under a minute of
actor runtime.

**Note:** a run's usage cost only settles after it reports SUCCEEDED — if
you check the dataset mid-run, the cost shown will be lower than the final
total.

### Related scrapers

Part of Studio AMBA's UK department-store / general-retail cluster:

- [Debenhams Scraper](https://apify.com/studioamba/debenhams-scraper) — UK department store
- [Liberty London Scraper](https://apify.com/studioamba/libertylondon-scraper) — UK luxury department store
- [Harrods Scraper](https://apify.com/studioamba/harrods-scraper) — UK luxury department store
- [House of Fraser Scraper](https://apify.com/studioamba/houseoffraser-scraper) — UK department store

# Actor input Schema

## `categoryUrl` (type: `string`):

A marksandspencer.com category/listing page URL, taken straight from the site's own navigation, e.g. https://www.marksandspencer.com/l/beauty/clinique or https://www.marksandspencer.com/l/women/womens-dresses. Leave empty to scrape the default category (Clinique beauty).

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

Maximum number of products to return. Results load in pages of 48 — large categories can hold thousands of products.

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

Proxy settings. marksandspencer.com has no active anti-bot challenge on plain requests (Akamai Bot Manager infrastructure is present but not currently blocking) — Apify's automatic proxy is enough. Switch to RESIDENTIAL (country GB) if you see repeated failures at high volume.

## Actor input object example

```json
{
  "categoryUrl": "https://www.marksandspencer.com/l/beauty/clinique",
  "maxResults": 60,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "categoryUrl": "https://www.marksandspencer.com/l/beauty/clinique",
    "maxResults": 60,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/marksandspencer-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 = {
    "categoryUrl": "https://www.marksandspencer.com/l/beauty/clinique",
    "maxResults": 60,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/marksandspencer-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 '{
  "categoryUrl": "https://www.marksandspencer.com/l/beauty/clinique",
  "maxResults": 60,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call studio-amba/marksandspencer-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/marksandspencer-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/bWnywXUwW2KmME6Jg/builds/A0FJdsoSYwLihlUho/openapi.json
