# El Corte Inglés Scraper - Products, Prices, Variants & Reviews (`abotapi/elcorteingles-es-scraper`) Actor

Scrape El Corte Inglés elcorteingles.es products across fashion, electronics, home, beauty, jewellery, toys and books. Extract current and was-prices, discounts, brands, categories, images, colour/size variants, availability, ratings and reviews. Supports keyword, category and URL modes.

- **URL**: https://apify.com/abotapi/elcorteingles-es-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 9 total users, 2 monthly users, 62.7% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 product results

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

## El Corte Inglés Scraper: Prices, Discounts, Variants and Reviews

El Corte Inglés Scraper turns the elcorteingles.es catalog into structured product data. Get the current price and, when a product is genuinely marked down, its original price and discount percentage, plus colour and size variants with their own price and availability, brand, category, marketplace seller, and customer reviews, across moda, electrónica, hogar, perfumería, joyería y relojes, juguetes and libros (the grocery section is not covered). Search by keyword or a real site category with brand, price and on-sale filters, or paste any product, category or search-result link and keep paginating automatically, then export to JSON, CSV or Excel, or pull results straight into your app through the API.

### Why This Scraper?

- **Was-price and discount, read from the site's own data, never guessed.** When a product is marked down, both the original and current price are captured plus the discount percentage; on a full-price item those fields are simply empty rather than invented.
- **Colour and size variants.** Fashion, footwear and similar products return every colour and size as its own variant, each carrying its own price, was-price/discount and availability.
- **Reviews with overall rating and review count.** Total review count and individual reviews (rating, title, body, author, date), gathered whenever reviews are switched on.
- **Two ways in.** Keyword or category search with brand, price and on-sale filters plus the site's own sort, or paste any product or listing link and continue pagination automatically.
- **Marketplace or direct sold, told apart.** Every record says whether it is sold by El Corte Inglés itself or by a marketplace seller, and names that seller when it is.
- **Built for monitoring.** Incremental mode returns only new and updated products on a recurring search by default (reappeared ones need Emit expired too), and a run that could not read the site at all fails loudly rather than finishing as an empty success.

### Use Cases

- **Price and markdown monitoring:** track discounts and price history across a category or brand on a recurring schedule.
- **Competitive retail research:** compare pricing, sellers, stock and assortment across brands and departments.
- **Catalog and content enrichment:** pull descriptions, specifications, images and variant data into your own product database.
- **Customer sentiment tracking:** aggregate ratings and reviews for the products or brands you follow.

### Data You Get

> Sample shape: values below are illustrative placeholders, not from a live product.

| Field | Example |
| --- | --- |
| `productId` | `"A930015820"` |
| `sku` | `"52918473"` |
| `gtin` | `"8412345671236"` |
| `name` | `"Chaqueta acolchada con capucha desmontable"` |
| `brand` | `"NORTHPEAK"` |
| `category` / `categoryPath` | `"Chaquetas"` / `["Moda mujer", "Abrigos y chaquetas", "Chaquetas"]` |
| `url` | `"https://www.elcorteingles.es/moda-mujer/A930015820-8412345671236-pr-sample-slug/"` |
| `price` / `currency` | `54.95` / `"EUR"` |
| `originalPrice` / `discountPercent` | `89.95` / `39.0` |
| `isOnSale` | `true` |
| `color` / `size` | `"Verde botella"` / `"M"` |
| `onlineAvailable` | `true` |
| `seller` / `isMarketplace` | `"Tienda Oficial Ejemplo"` / `true` |
| `image` / `images` | `"https://dam.elcorteingles.es/producto/sample-front.jpg"` / list of image URLs |
| `description` | full product description text |
| `specifications` | `{"Género": "Mujer", "Composición": "80% poliéster, 20% algodón"}` |
| `variants` | `[{"sku": "52918473", "gtin": "8412345671236", "color": "Verde botella", "size": "M", "price": 54.95, "originalPrice": 89.95, "discountPercent": 39.0, "onlineAvailable": true}, {"sku": "52918474", "gtin": "8412345671259", "color": "Verde botella", "size": "L", "price": 54.95, "originalPrice": 89.95, "discountPercent": 39.0, "onlineAvailable": true}]` |
| `reviews.averageRating` / `reviews.totalReviewCount` | `4.3` / `128` |
| `reviews.items[]` | `[{"rating": 5, "title": "Muy abrigada", "body": "Sample review text.", "author": "Cliente", "date": "2026-03-14T00:00:00.000+00:00"}]` |
| `changeType` / `changedFields` / `firstSeenAt` / `lastSeenAt` | `"UPDATED"` / `["price", "isOnSale"]` / ISO timestamps (Incremental mode only) |

Every record is one colour card, matching how the site itself splits colourways into separate listing cards. `originalPrice` and `discountPercent` are only ever populated when `isOnSale` is true, read straight off the site's own markdown data, never computed. `seller` is only populated when `isMarketplace` is true; a product sold directly by El Corte Inglés carries `isMarketplace: false` and `seller: null`. `description`, `specifications` and the complete colour x size `variants` matrix are only added once a Fetch full product detail fetch lands (a pasted single product link always fetches this); without it, `variants` still lists this colour's own sizes from the listing itself. `reviews` is always present, with an empty shape when Fetch reviews is off or the product has none. `changeType`, `changedFields`, `firstSeenAt` and `lastSeenAt` are only added when Incremental mode is on.

#### Additional product fields

Each record also carries, when the site provides them for that product: `shortDescription` (the short text on the listing card; the full `description` stays the detail text and is added only when a detail fetch lands), `categories`, `hierarchy`, `media_objects`, `badges`, `promotional_actions`, `provider`, `is_sold_by`, `is_gift_card`, `status`, `size_guide`, `size_guide_type`, `size_guide_details`, `default_image` and `canonical`. These descriptive site fields are excluded from incremental change detection (promo texts and badges rotate daily), so a change in them alone never produces an UPDATED row; `description` is NOT in that list and still drives UPDATED whenever a detail fetch lands.

### How to Use

1. Pick a **mode**: `search` (a keyword, or a real site category, with filters; if both are set, the category is used and the keyword is ignored) or `url` (paste product, category or search-result links).
2. Fill in the fields for that mode, and switch on **Fetch full product detail** / **Fetch reviews** if you want the full variant matrix, description, specifications and reviews.
3. Set **Max products total** and **Max pages per search** to control run size and cost, then click **Start**.
4. Download the dataset as JSON, CSV or Excel, or read it through the API.

**Keyword search, first page:**

```json
{
  "mode": "search",
  "searchTerm": "zapatillas running",
  "maxItems": 20
}
```

**Category browse, filtered to a brand and price band, sorted by discount, on sale only:**

```json
{
  "mode": "search",
  "categoryPath": "moda-hombre/zapatillas",
  "brands": ["Skechers"],
  "minPrice": 20,
  "maxPrice": 100,
  "onSaleOnly": true,
  "sortBy": "DISCOUNT_DESC",
  "maxItems": 50,
  "maxPages": 5
}
```

**Full detail and reviews for a pasted product link:**

```json
{
  "mode": "url",
  "urls": ["https://www.elcorteingles.es/electronica/A900001234-0000000012345-pr-sample-television-55-pulgadas/"],
  "fetchDetails": true,
  "fetchReviews": true
}
```

**Recurring monitoring: run the same search on a schedule, get only what changed:**

```json
{
  "mode": "search",
  "categoryPath": "moda-hombre/zapatillas",
  "onSaleOnly": true,
  "incrementalMode": true
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/elcorteingles-es-scraper").call(
    run_input={"mode": "search", "searchTerm": "zapatillas running", "maxItems": 20}
)
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(product["name"], product["price"], product["currency"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/elcorteingles-es-scraper').call({
  mode: 'search', searchTerm: 'zapatillas running', maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Output tabs and run summary

The dataset has these tabs: Products (overview), Colour/size variants, Reviews, Changes (Incremental mode) and Product detail. Every tab reads the same records, so nothing is charged twice. When a run ends, a run summary (rows returned, pages walked, whether the end of the results was reached) is saved under the key `OUTPUT` in the key-value store.

#### Resume and incremental mode (recurring monitoring)

- **Resume** (`resumeFromRunId`) continues one interrupted run: paste its run or dataset id and the actor skips everything already collected there, so you don't pay twice.
- **Incremental mode** (`incrementalMode`) is for a search or category you run repeatedly (e.g. an Apify schedule). Each record is classified `NEW`, `UPDATED` (with `changedFields`), `UNCHANGED` (suppressed and not billed unless `emitUnchanged` is on), `REAPPEARED` (a product marked `EXPIRED` on a previous run, now back) or `EXPIRED` (only emitted when `emitExpired` is on, and only after this run scanned the tracked search to its natural end, with no cap and no resume). `stateKey` names or shares the stored state. With Incremental mode off, every matching product is returned and no change fields are added. `UPDATED` is driven by price, original price, discount, on-sale flag, online availability, marketplace seller, name, brand, category, images, the per-size `variants` (price and availability) and, when a detail fetch lands, the `description`, `specifications` and full `categoryPath`; and, when Fetch reviews is on, the review count, average rating and latest review rows (a genuinely new review is a real change). Always excluded from change detection (they stay in the output): `shortDescription`, `categories`, `hierarchy`, `media_objects`, `badges`, `promotional_actions`, `provider`, `is_sold_by`, `is_gift_card`, `status`, `size_guide`, `size_guide_type`, `size_guide_details`, `default_image` and `canonical`. The monitor's identity does not depend on the review cap or on the example link list, so changing `maxReviewsPerProduct` keeps your tracked products. `ignoreFieldsForChanges` lets you exclude more: a name matches at any depth (e.g. `size` inside every variant, `body` inside every review), the field stays in the output, and editing the list never re-bills tracked products as UPDATED.
- The two can be combined only once, to bootstrap the very first incremental run from an already-collected dataset; combining them again after a baseline already exists is rejected, since a resumed run only returns a delta and would otherwise wipe out everything already tracked.

#### How the price, brand and on-sale filters are bounded

A price band is handed to the site's own price filter first, so the run pages only through results already inside it rather than the whole department (on a large department, a high minimum price can cut the pages walked by an order of magnitude). Brand and on-sale-only have no equivalent on the site, so those are checked after each page is fetched; to stop a very selective combination from paging through an entire department looking for survivors, the walk stops a search after 5 consecutive result pages that contain no match at all. The run's status message on the run page always says which happened: the search was read to its natural end, or it was stopped early and more matches may exist further down.

#### URL mode

Paste any of these link shapes (the `www.` host and the mobile `m.` host are both accepted):

- Search results: first page, a paginated page (`/search-nwx/2/?s=...`), sorted (`?sorting=priceAsc`), with a price filter segment, and the legacy `/search/?s=...` link (served from the current search route).
- Category pages: sub-category (`/electronica/gaming/`), a later page (`/electronica/gaming/2/`), two-level paths (`/moda-hombre/zapatillas/`), sorted (`?sorting=priceAsc`) and with a price filter segment.
- Product detail pages, with or without an extra query string such as `?parentCategoryId=1`.

The `supermercado` (grocery) section is not supported: such a link is skipped with a warning in the log, returns no rows and is never billed.

Behaviour change: the `urls` field now ships with one example link per shape above. A run in URL mode that leaves the field untouched scrapes those examples (sharing the Max products budget) instead of a single category page.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape; the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable summary of each product, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

1. Authorize a connector once under **Apify, Settings, Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. If the picker is empty, you haven't authorized a connector yet.
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` finds products by a keyword, or a real category path (if both are set, the category wins and the keyword is ignored), with brand, price and on-sale filters and the site's own sort; `url` scrapes any pasted product, category or search-result link and walks pagination forward automatically. |
| `searchTerm` | string | `zapatillas running` | Free-text keyword (search mode). Defaults to a sample keyword so a run started with no input still returns real products. |
| `categoryPath` | string | (none) | A real elcorteingles.es category path exactly as it appears in the site's own URL, e.g. `moda-hombre/zapatillas` (search mode). The `supermercado` (grocery) section is not supported. |
| `onSaleOnly` | boolean | `false` | Keep only products currently marked down (a genuine strike-through price on the site itself). Applies in both search and URL mode. |
| `brands` | array | (none; prefilled empty) | Exact brand names to keep. The site has no brand filter of its own, so this is checked after each result page is fetched. Applies in both modes. |
| `minPrice` | number | (none) | Minimum price in EUR. Applied by the site's own price filter first, so the run pages only through results already inside the band. |
| `maxPrice` | number | (none) | Maximum price in EUR. Applied by the site's own price filter first, so the run pages only through results already inside the band. |
| `minDiscountPercent` | number | (none) | Minimum discount in percent. Applied by the site's own discount filter first, then checked again on each row. |
| `sortBy` | string | `RELEVANCE` | The site's own sort order (now also `FEATURED`; the site's own sort keys such as `discountPerDesc` are accepted too). The alternative input names `keyword`, `max_items_per_url` and `sort_by` are accepted as aliases. Applies in both modes; in URL mode, a pasted link's own encoded sort order takes priority when it has one. |
| `urls` | array | one example link per supported shape (see URL mode below) | Product, category or search-result page links to scrape (URL mode). Pagination continues automatically from any page segment already in the URL. |
| `fetchDetails` | boolean | `false` | Adds the full breadcrumb category path, description, specifications and the complete colour x size variant matrix. A pasted single product link always fetches this regardless of this setting. |
| `fetchReviews` | boolean | `true` | Fetches the product's reviews: overall rating, total review count and individual reviews. |
| `maxReviewsPerProduct` | integer | `20` | Cap on individual reviews fetched per product when Fetch reviews is on. Values above 1000 are clamped to 1000; reviews are fetched in pages until the cap or the product's last review. |
| `maxPages` | integer | `0` | Cap on result pages per search/category/URL entry. `0` = unlimited, walk every page until the site's own page count or Max products total is hit. |
| `maxItems` | integer | `20` | Hard cap on total products returned across every search/category/URL entry. `0` = the maximum of 1,000,000 (still bounded by Max pages per search). |
| `resumeFromRunId` | string | (none) | Continue one interrupted run: paste its run or dataset id and already-collected products are skipped. For a recurring/scheduled search, use Incremental mode instead. |
| `incrementalMode` | boolean | `false` | Recurring monitoring: track this search across scheduled runs and, by default, return only NEW and UPDATED products (REAPPEARED needs Emit expired too, see "Resume and incremental mode" above). |
| `stateKey` | string | (none) | Optional stable name for the tracked search when Incremental mode is on. Left empty, one is derived automatically from your search and filters. |
| `emitUnchanged` | boolean | `false` | Incremental mode only: also return UNCHANGED products. Billed like any other result. |
| `emitExpired` | boolean | `false` | Incremental mode only: also return products no longer found, when this run reached a complete scan. Billed like any other result. |
| `ignoreFieldsForChanges` | array | (none) | Incremental mode only: field names that never count as a change (matched at any depth, kept in the output). |
| `proxy` | object | Apify Proxy | Connection settings for the run. |
| `mcpConnectors` | array | (none) | Optional MCP connectors to export results into (Notion, Linear, Airtable, Apify). |
| `notionParentPageUrl` | string | (none) | Notion connector only: page under which item pages are created. |
| `maxNotifyListings` | integer | `50` | Cap on items exported to each connector per run. Does not affect the dataset. |

### Output Example

> Sample shape: values below are illustrative placeholders, not from a live product.

```json
{
  "productId": "A930015820",
  "name": "Chaqueta acolchada con capucha desmontable",
  "brand": "NORTHPEAK",
  "category": "Chaquetas",
  "categoryPath": ["Moda mujer", "Abrigos y chaquetas", "Chaquetas"],
  "url": "https://www.elcorteingles.es/moda-mujer/A930015820-8412345671236-pr-sample-slug/",
  "sku": "52918473",
  "gtin": "8412345671236",
  "price": 54.95,
  "currency": "EUR",
  "originalPrice": 89.95,
  "discountPercent": 39.0,
  "isOnSale": true,
  "color": "Verde botella",
  "size": "M",
  "onlineAvailable": true,
  "seller": "Tienda Oficial Ejemplo",
  "isMarketplace": true,
  "image": "https://dam.elcorteingles.es/producto/sample-front.jpg",
  "images": ["https://dam.elcorteingles.es/producto/sample-front.jpg", "https://dam.elcorteingles.es/producto/sample-back.jpg"],
  "description": "Sample product description text as shown on the site.",
  "specifications": { "Género": "Mujer", "Composición": "80% poliéster, 20% algodón" },
  "variants": [
    { "sku": "52918473", "gtin": "8412345671236", "color": "Verde botella", "size": "M", "price": 54.95, "currency": "EUR", "originalPrice": 89.95, "discountPercent": 39.0, "isOnSale": true, "onlineAvailable": true, "isMarketplace": true, "seller": "Tienda Oficial Ejemplo" },
    { "sku": "52918474", "gtin": "8412345671259", "color": "Verde botella", "size": "L", "price": 54.95, "currency": "EUR", "originalPrice": 89.95, "discountPercent": 39.0, "isOnSale": true, "onlineAvailable": true, "isMarketplace": true, "seller": "Tienda Oficial Ejemplo" }
  ],
  "reviews": {
    "averageRating": 4.3,
    "totalReviewCount": 128,
    "items": [
      { "rating": 5, "title": "Muy abrigada", "body": "Sample review text.", "author": "Cliente", "date": "2026-03-14T00:00:00.000+00:00" }
    ]
  }
}
```

### Plan Requirement

The default connection (Apify Proxy, automatic group) works on a datacenter connection: it was measured returning real pages, so no residential proxy is needed. Apify proxy access itself needs a paid Apify plan. The actor reads the connection your account is actually entitled to: if the selected connection is refused, it retries on other connections and, when none of the Apify groups is available, continues on a backup connection, logging "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable." and, on pages served that way, "Served over the backup connection (the default connection was unavailable)." Each page has a short time budget, so a slow connection is abandoned and retried rather than stalling the run. For a very large or sustained run, residential traffic can help and is billed to your Apify plan.

If a category path does not exist on the site (404, a redirect to a different landing page, or a page with no listing), the run names that value in a warning and in the final message instead of returning a silent empty result; use the category path as it appears in the site's own address (for example electronica/tv), not a display name. If nothing could be loaded you get a clear failure instead of an empty result: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required" (account has no proxy access), "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested El Corte Inglés pages" (residential chosen without entitlement), or "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search." (any other cause). The Pricing tab shows current per-product and enrichment rates.

### FAQ

#### How much does it cost?

You pay a run start fee, then a charge for every product returned in the dataset, plus a per-product detail/review enrichment charge whenever the detail fetch and/or the review lookup actually completes for that product, whether or not the product turns out to have any reviews. Fetch reviews is on by default, so most returned products carry this charge unless you turn both toggles off. Pasting a single product link always fetches its full detail (and is billed that enrichment charge once), regardless of the Fetch full product detail toggle, because a standalone product page has no listing card to build a base record from. For products found by searching, browsing a category, or pasting a listing link, that same enrichment charge only applies when Fetch full product detail and/or Fetch reviews is switched on. The enrichment charge is applied per product right after that product is written to the dataset (not once at the end of the run), so a run that times out or is aborted has already been billed for exactly the enriched products it delivered, and never for products that were skipped, unchanged or failed to save. Reviews do not add a separate charge. See the **Pricing** tab for current rates.

#### Is it legal to scrape El Corte Inglés?

This actor collects only publicly available product data. You are responsible for how you use it: follow El Corte Inglés's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices and product facts are generally not protected, but product photos, descriptions and reviews may be subject to third-party rights.

#### Can I get only new or changed products on a schedule?

Yes. Schedule the actor from the **Schedules** tab and turn on **Incremental mode**. Each run then returns only new and updated products for that tracked search by default (plus reappeared ones once an Emit expired pass has marked them gone), and unchanged ones are not billed unless you turn that on too.

#### Why does a supermercado (grocery) category or link return nothing?

The grocery section sits behind a materially harder verification step than the rest of the catalog and is not currently scraped by this actor. A `categoryPath` or pasted URL under that section is skipped with a clear log message rather than failing the whole run. Every other department (moda, electrónica, hogar, perfumería, joyería y relojes, juguetes, libros) is fully supported.

#### Why did a run stop before reaching the end of the results?

Brand and on-sale filters have no equivalent on the site, so a very selective combination can page through many results with nothing matching; the run stops a search after 5 consecutive pages with no match, and says so in the status message rather than claiming that was the end of the results. If that 5-page stop happens on every search in the run and nothing at all was returned, the run is marked failed rather than a plain empty success, since it has not actually proven there are no matches; add `maxItems` or `maxPages`, or narrow the filters, and try again. Max products and Max pages caps behave the same way: raise them, or narrow the category or filters, to see more.

#### Why did my run fail instead of returning an empty dataset?

If every page this run tried to load failed to load at all, the run stops with an error instead of finishing as an empty success, because that is a connection problem, not evidence that there are no matching products. Run it again in a few minutes. A run that read pages and reached the real end of the results, even with zero matches, finishes normally and reports what it found. If the walk instead gave up after 5 pages in a row with no match and returned nothing, the run is also marked failed, for the same reason: it has not proven there are no matches, see "Why did a run stop before reaching the end of the results?" above.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

### 🔗 Want more grocery data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>🔌 <a href="https://apify.com/abotapi/leroymerlin-es-scraper"><b>LeroyMerlin.es Scraper</b></a><br>Scrape Leroy Merlin Spain (leroymerlin.es) DIY and home-improvement products: price...</td><td>🥦 <a href="https://apify.com/abotapi/lidl-es-scraper"><b>Lidl.es Products, Weekly Offers, Prices &amp; Reviews Scraper</b></a><br>Scrape Lidl.es grocery and non-food products across weekly offers, tools, home, garden...</td></tr>
<tr><td>🥦 <a href="https://apify.com/abotapi/mercadona-es-scraper"><b>Mercadona Scraper</b></a><br>Scrape Mercadona products by delivery-area postal code. Search by keyword or category, or...</td><td>🥦 <a href="https://apify.com/abotapi/carrefour-es-scraper"><b>Carrefour Spain Scraper</b></a><br>Scrape Carrefour Spain (carrefour.es) products. Search by keyword, browse a category, or...</td></tr>
<tr><td>🔌 <a href="https://apify.com/abotapi/currys-co-uk"><b>Currys UK Scraper</b></a><br>Scrape Currys UK products, including electronics, home appliances, computers, TVs and...</td><td>🔌 <a href="https://apify.com/abotapi/biccamera-com-scraper"><b>Bic Camera Scraper</b></a><br>Scrape Bic Camera (biccamera.com) products: JPY price, list price and discount, Bic Point...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/elcorteingles-es-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

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

'search' finds products by keyword and/or a real elcorteingles.es category path (e.g. 'moda-hombre/zapatillas', exactly as it appears in the site's own URL), with brand/price/on-sale filters and the site's own sort. 'url' scrapes any product, category, or search-result page URL you paste, walking pagination forward automatically.

## `searchTerm` (type: `string`):

Free-text keyword, e.g. 'zapatillas running' or 'television'. Leave empty and use Category path only below to browse a whole category instead. Defaults to 'zapatillas running' so a run started with no input still returns real products instead of nothing.

## `categoryPath` (type: `string`):

A real elcorteingles.es category path exactly as it appears in the site's own URL, e.g. 'moda-hombre/zapatillas', 'electronica/tv', 'perfumeria'. Browses the whole category when the keyword above is empty. Note: the supermercado (grocery) section is not supported by this actor -- see the README.

## `onSaleOnly` (type: `boolean`):

Keep only products currently marked down (a genuine strike-through original price on the site itself), dropping full-price items from the results.

## `brands` (type: `array`):

Only return products from these brands, e.g. 'Samsung', 'Skechers', 'La Mer'. Match the exact brand name as shown on the site. Leave empty for all brands. The site has no brand filter of its own, so this is checked after each result page is fetched. A very rare brand in a very large category can stop the run early (see the run's status message and the README).

## `minPrice` (type: `number`):

Only return products priced at or above this amount, in euros. Applied by the site's own price filter, so the run pages only through results already inside the band instead of walking the whole category.

## `maxPrice` (type: `number`):

Only return products priced at or below this amount, in euros. Applied by the site's own price filter, so the run pages only through results already inside the band instead of walking the whole category.

## `minDiscountPercent` (type: `number`):

Only return products discounted by at least this percentage. Applied by the site's own discount filter, so the run pages only through already-discounted results. Leave empty for no discount filter.

## `sortBy` (type: `string`):

The site's own sort order, verified live to reorder the full server-side result set (so it stays correct across pagination, not just within one fetched page). Applies in both search and URL mode. In URL mode, though, this only kicks in when the pasted category or search-result URL has no sort order of its own encoded in it -- an already-sorted pasted URL keeps its own ordering regardless of this setting.

## `urls` (type: `array`):

Paste one or more elcorteingles.es product pages, category listing pages, or search-result pages (search, paginated, sorted, price-filtered, legacy /search/ and mobile m. links all work). Pagination continues forward automatically from any page segment already in the URL. The supermercado (grocery) section is not supported and is skipped with a warning. Filter fields above are ignored in this mode. Left untouched, this list scrapes one example per link shape.

## `fetchDetails` (type: `boolean`):

Adds the full breadcrumb category path, complete description, flattened specifications, and every colour x size variant (each with its own price, was-price/discount and availability) from the product page. Current price, was-price/discount and card image are already included without this toggle.

## `fetchReviews` (type: `boolean`):

Fetch the product's reviews: overall rating, total review count, and individual reviews (rating, title, body, author, date). Products with no reviews simply return an empty list.

## `maxReviewsPerProduct` (type: `integer`):

Cap on individual reviews fetched per product when 'Fetch reviews' is on (maximum 1000).

## `maxPages` (type: `integer`):

Stop after this many result pages per search/category/URL entry. 0 (default) = unlimited -- walk every page until the site's own page count or Max products total is hit.

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

Hard cap on total products returned across every search/category/URL entry. 0 = the maximum of 1,000,000 (still bounded by Max pages per search).

## `proxy` (type: `object`):

Leave the default proxy configuration as-is for normal runs. You may optionally switch to a different proxy group for very large or sustained runs.

## `resumeFromRunId` (type: `string`):

Paste a previous run id (or its dataset id) to continue that run: products already collected there are skipped, so this run only returns new products (a delta). Leave empty for a normal run. For a recurring/scheduled search, use Incremental mode below instead -- it remembers the previous run itself, without pasting an id every time.

## `incrementalMode` (type: `boolean`):

For a search/category you run on a schedule: the actor remembers the products it saw last time (in a dedicated key-value store, keyed by this search) and, by default, only returns products that are NEW, UPDATED or REAPPEARED. UPDATED is driven by price, original price, discount, on-sale flag, online availability, marketplace seller, name, brand, category, images, the per-size variants (their price and availability), and, when Fetch reviews is on, the review count, average rating and the latest review rows (a genuinely new review is a real change). UPDATED also reacts, when a detail fetch lands, to the description, specifications and full category path. Always excluded from change detection (they stay in the output): shortDescription, categories, hierarchy, media_objects, badges, promotional_actions, provider, is_sold_by, is_gift_card, status, size_guide, size_guide_type, size_guide_details, default_image and canonical. You can exclude more with 'Ignore fields when detecting changes' below (the fields stay in the output). Unlike Resume above, you never need to paste a run or dataset id. Off by default: a normal run always returns every matching product.

## `stateKey` (type: `string`):

Optional label for the tracked search when Incremental mode is on, e.g. 'zapatillas-running-es'. Leave empty to let the actor derive one automatically from your search/category/URL and filters -- two different searches never share a baseline either way. Set this if you want a stable, human-readable name, or want to run the exact same search twice as two separate monitoring campaigns.

## `emitUnchanged` (type: `boolean`):

When Incremental mode is on, also return products with no changes since last time (changeType 'UNCHANGED'), not just NEW/UPDATED/REAPPEARED. Off by default. Returning unchanged rows bills like any other product result -- turn this on only if you need the full current snapshot every run, not just what changed.

## `emitExpired` (type: `boolean`):

When Incremental mode is on AND this run scans the search to its natural end (no Max products/Max pages cap reached, no Resume from a previous run), also return one row per previously-seen product no longer found (changeType 'EXPIRED'), using its last-known data. Off by default. Returning expired rows bills like any other product result.

## `ignoreFieldsForChanges` (type: `array`):

Incremental mode only: field names that must NOT make a product count as UPDATED, e.g. \['images', 'reviews']. A name matches at any depth, so 'size' also ignores it inside every variant and 'body' inside every review row. The fields stay in the output rows; they are only left out of change detection and 'changedFields'. Beyond the always-excluded descriptive fields named under Incremental mode, nothing is ignored by default. Changing this list never re-bills your tracked products as UPDATED.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify -> Settings -> Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON; the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "searchTerm": "zapatillas running",
  "onSaleOnly": false,
  "brands": [],
  "sortBy": "RELEVANCE",
  "urls": [
    "https://www.elcorteingles.es/search-nwx/?s=television",
    "https://www.elcorteingles.es/search-nwx/2/?s=television",
    "https://www.elcorteingles.es/search-nwx/?s=television&sorting=priceAsc",
    "https://www.elcorteingles.es/search-nwx/price%3A%3A900.0-%3E1000.0/?s=televisor",
    "https://www.elcorteingles.es/search/?s=television",
    "https://www.elcorteingles.es/electronica/gaming/",
    "https://www.elcorteingles.es/electronica/gaming/2/",
    "https://www.elcorteingles.es/moda-hombre/zapatillas/",
    "https://www.elcorteingles.es/electronica/?sorting=priceAsc",
    "https://www.elcorteingles.es/electronica/price%3A%3A900.0-%3E1000.0/",
    "https://www.elcorteingles.es/perfumeria/",
    "https://www.elcorteingles.es/electronica/tv/price%3A%3A300.0-%3E800.0/2/?sorting=priceAsc",
    "https://www.elcorteingles.es/lg/electronica/tv/tv-oled/",
    "https://www.elcorteingles.es/electronica/A200860158-8806099120955-pr-tv-neo-qled-mini-led-163cm-65-samsung-tq65qn73hauxxc-4k-smart-tv-con-vision-ai-football-mode-negro/",
    "https://www.elcorteingles.es/deportes/A201384926-negro-pr-zapatillas-de-running-de-hombre-nike-air-winflo-12-nike/",
    "https://elcorteingles.es/electronica/tv/"
  ],
  "fetchDetails": false,
  "fetchReviews": true,
  "maxReviewsPerProduct": 20,
  "maxPages": 0,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `variants` (type: `string`):

No description

## `reviews` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `detail` (type: `string`):

No description

## `summary` (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 = {
    "mode": "search",
    "searchTerm": "zapatillas running",
    "brands": [],
    "urls": [
        "https://www.elcorteingles.es/search-nwx/?s=television",
        "https://www.elcorteingles.es/search-nwx/2/?s=television",
        "https://www.elcorteingles.es/search-nwx/?s=television&sorting=priceAsc",
        "https://www.elcorteingles.es/search-nwx/price%3A%3A900.0-%3E1000.0/?s=televisor",
        "https://www.elcorteingles.es/search/?s=television",
        "https://www.elcorteingles.es/electronica/gaming/",
        "https://www.elcorteingles.es/electronica/gaming/2/",
        "https://www.elcorteingles.es/moda-hombre/zapatillas/",
        "https://www.elcorteingles.es/electronica/?sorting=priceAsc",
        "https://www.elcorteingles.es/electronica/price%3A%3A900.0-%3E1000.0/",
        "https://www.elcorteingles.es/perfumeria/",
        "https://www.elcorteingles.es/electronica/tv/price%3A%3A300.0-%3E800.0/2/?sorting=priceAsc",
        "https://www.elcorteingles.es/lg/electronica/tv/tv-oled/",
        "https://www.elcorteingles.es/electronica/A200860158-8806099120955-pr-tv-neo-qled-mini-led-163cm-65-samsung-tq65qn73hauxxc-4k-smart-tv-con-vision-ai-football-mode-negro/",
        "https://www.elcorteingles.es/deportes/A201384926-negro-pr-zapatillas-de-running-de-hombre-nike-air-winflo-12-nike/",
        "https://elcorteingles.es/electronica/tv/"
    ],
    "proxy": {
        "useApifyProxy": true
    },
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/elcorteingles-es-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 = {
    "mode": "search",
    "searchTerm": "zapatillas running",
    "brands": [],
    "urls": [
        "https://www.elcorteingles.es/search-nwx/?s=television",
        "https://www.elcorteingles.es/search-nwx/2/?s=television",
        "https://www.elcorteingles.es/search-nwx/?s=television&sorting=priceAsc",
        "https://www.elcorteingles.es/search-nwx/price%3A%3A900.0-%3E1000.0/?s=televisor",
        "https://www.elcorteingles.es/search/?s=television",
        "https://www.elcorteingles.es/electronica/gaming/",
        "https://www.elcorteingles.es/electronica/gaming/2/",
        "https://www.elcorteingles.es/moda-hombre/zapatillas/",
        "https://www.elcorteingles.es/electronica/?sorting=priceAsc",
        "https://www.elcorteingles.es/electronica/price%3A%3A900.0-%3E1000.0/",
        "https://www.elcorteingles.es/perfumeria/",
        "https://www.elcorteingles.es/electronica/tv/price%3A%3A300.0-%3E800.0/2/?sorting=priceAsc",
        "https://www.elcorteingles.es/lg/electronica/tv/tv-oled/",
        "https://www.elcorteingles.es/electronica/A200860158-8806099120955-pr-tv-neo-qled-mini-led-163cm-65-samsung-tq65qn73hauxxc-4k-smart-tv-con-vision-ai-football-mode-negro/",
        "https://www.elcorteingles.es/deportes/A201384926-negro-pr-zapatillas-de-running-de-hombre-nike-air-winflo-12-nike/",
        "https://elcorteingles.es/electronica/tv/",
    ],
    "proxy": { "useApifyProxy": True },
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/elcorteingles-es-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 '{
  "mode": "search",
  "searchTerm": "zapatillas running",
  "brands": [],
  "urls": [
    "https://www.elcorteingles.es/search-nwx/?s=television",
    "https://www.elcorteingles.es/search-nwx/2/?s=television",
    "https://www.elcorteingles.es/search-nwx/?s=television&sorting=priceAsc",
    "https://www.elcorteingles.es/search-nwx/price%3A%3A900.0-%3E1000.0/?s=televisor",
    "https://www.elcorteingles.es/search/?s=television",
    "https://www.elcorteingles.es/electronica/gaming/",
    "https://www.elcorteingles.es/electronica/gaming/2/",
    "https://www.elcorteingles.es/moda-hombre/zapatillas/",
    "https://www.elcorteingles.es/electronica/?sorting=priceAsc",
    "https://www.elcorteingles.es/electronica/price%3A%3A900.0-%3E1000.0/",
    "https://www.elcorteingles.es/perfumeria/",
    "https://www.elcorteingles.es/electronica/tv/price%3A%3A300.0-%3E800.0/2/?sorting=priceAsc",
    "https://www.elcorteingles.es/lg/electronica/tv/tv-oled/",
    "https://www.elcorteingles.es/electronica/A200860158-8806099120955-pr-tv-neo-qled-mini-led-163cm-65-samsung-tq65qn73hauxxc-4k-smart-tv-con-vision-ai-football-mode-negro/",
    "https://www.elcorteingles.es/deportes/A201384926-negro-pr-zapatillas-de-running-de-hombre-nike-air-winflo-12-nike/",
    "https://elcorteingles.es/electronica/tv/"
  ],
  "proxy": {
    "useApifyProxy": true
  },
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/elcorteingles-es-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/elcorteingles-es-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/sZSqgcSBzDHZCKI5G/builds/NsWsDxmC1fKNEbToH/openapi.json
