# Carrefour Spain Scraper — Grocery Prices & EAN Data (`studio-amba/carrefour-es-scraper`) Actor

Scrape products, prices, unit prices, EAN barcodes, and images from carrefour.es, Carrefour's Spanish grocery storefront. Search any grocery keyword and export clean structured supermarket data.

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

## Carrefour Spain Scraper — Grocery Prices & EAN Data

Scrape grocery products, prices, unit prices, and EAN barcodes from **carrefour.es**, Carrefour's Spanish supermarket storefront. Search any grocery keyword and export clean, structured data.

### Why use this actor?

Carrefour is one of the biggest grocery chains in Spain, and its prices, promotions, and product catalogue are valuable for price monitoring, competitor benchmarking, product matching, and market research. This actor turns a grocery keyword into a structured dataset you can drop straight into a spreadsheet, database, or price-comparison pipeline.

### How to scrape Carrefour Spain data

1. Enter a **search query** in Spanish (for example `leche`, `pan`, `cafe`, or `huevos`).
2. Set **Max Results** to how many products you want.
3. Provide a **Bright Data API key** (see "Anti-bot" below).
4. Run the actor. Results stream into the dataset and can be exported as JSON, CSV, Excel, or via the API.

Optionally enable **Fetch product details** to visit each product page and confirm the brand, EAN, rating, review count, and full description from structured data. This is slower and more expensive because it makes one extra request per product.

#### About the search field

carrefour.es has no working free-text search page of its own — its search box is a client-side widget with no public results URL (confirmed live, see Limitations). So **Search Query** is matched against carrefour.es's own category list, and the best-matching category is scraped. `leche` resolves to the "Leche" category, `pan` to bread, and so on. If you already know the exact category you want, pass its URL directly in **Category URL** instead (e.g. `https://www.carrefour.es/supermercado/la-despensa/lacteos/leche/cat20093/c`) — that always wins over Search Query.

### Input

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `searchQuery` | String | No | Spanish grocery keyword, matched to the closest carrefour.es category (default: `leche`) |
| `categoryUrl` | String | No | Exact carrefour.es category URL — overrides `searchQuery` when set |
| `maxResults` | Integer | No | Maximum products to return, 1–10000 (default: 100) |
| `fetchDetails` | Boolean | No | Visit each product page for a confirmed brand/EAN/rating/description (default: false) |
| `brightDataApiKey` | String | Yes | Bright Data Web Unlocker API key (or set `BRIGHT_DATA_API_KEY` env var) |
| `proxyConfiguration` | Object | No | Kept for schema compatibility; fetching is handled by Bright Data |

### Output

Each result contains:

| Field | Type | Example | Coverage |
|-------|------|---------|----------|
| `productName` | String | `"Leche entera Pascual brik 1 l."` | 100% |
| `brand` | String | `"PASCUAL"` | ~85–90% from the listing tile; 100% with Fetch product details |
| `price` | Number | `1.29` | 100% |
| `currency` | String | `"EUR"` | 100% |
| `unitPrice` | String | `"1,29 €"` | 100% |
| `originalPrice` | Number | `1.43` (only when on promotion) | — |
| `discount` | String | `"-10%"` (only when on promotion) | — |
| `category` | String | `"Leche"` | 100% |
| `productId` | String | `"8410128010096"` | 100% |
| `ean` | String | `"8410128010096"` | ~10–15% from the listing tile; 100% with Fetch product details |
| `inStock` | Boolean | `true` | 100% (never guessed — see Limitations) |
| `rating` | Number | `4.63` | 0% from the listing (carrefour.es never shows it there); populated with Fetch product details |
| `reviewCount` | Integer | `22` | Only with Fetch product details |
| `imageUrl` | String | Primary product image URL | 100% |
| `productDescription` | String | Full description | Only with Fetch product details |
| `url` | String | Full product page URL | 100% |
| `scrapedAt` | String | ISO 8601 timestamp | 100% |

### Example output

```json
{
    "productName": "Leche entera Pascual brik 1 l.",
    "price": 1.29,
    "currency": "EUR",
    "unitPrice": "1,29 €",
    "originalPrice": 1.43,
    "discount": "-10%",
    "category": "Leche",
    "productId": "8410128010096",
    "ean": "8410128010096",
    "inStock": true,
    "imageUrl": "https://static.carrefour.es/hd_350x_/img_pim_food/003629_00_1.jpg",
    "url": "https://www.carrefour.es/supermercado/leche-entera-pascual-brik-1-l/R-521006986/p",
    "scrapedAt": "2026-08-27T09:43:52.807Z"
}
```

With `fetchDetails: true`, the same product also carries a confirmed `brand`, `rating`, `reviewCount`, and `productDescription`:

```json
{
    "productName": "Leche semidesnatada Carrefour pack de 9 briks de 1 l.",
    "brand": "CARREFOUR",
    "price": 7.65,
    "currency": "EUR",
    "unitPrice": "0,85 €",
    "category": "Leche",
    "productId": "VC4AECOMM-481229",
    "ean": "8431876357585",
    "inStock": true,
    "rating": 5,
    "reviewCount": 10,
    "imageUrl": "https://static.carrefour.es/hd_350x_/img_pim_food/481229_00_1.jpg",
    "productDescription": "Comprar Leche semidesnatada Carrefour pack de 9 briks de 1 l. Descubre las mejores ofertas del supermercado online Carrefour ¡15€ de descuento en tu primera compra online!",
    "url": "https://www.carrefour.es/supermercado/leche-semidesnatada-carrefour-pack-de-9-briks-de-1-l/R-VC4AECOMM-481229/p",
    "scrapedAt": "2026-08-27T09:36:45.201Z"
}
```

### Anti-bot: Bright Data Web Unlocker required

carrefour.es is protected by Cloudflare Bot Management. Plain HTTP requests receive a 403 and a `__cf_bm` cookie instead of the real content. To fetch pages reliably, this actor uses the [Bright Data Web Unlocker](https://brightdata.com) (zone `web_unlocker1`).

You need a Bright Data account with a Web Unlocker zone. Provide the API key either:

- in the input field **Bright Data API Key**, or
- as the environment variable `BRIGHT_DATA_API_KEY`.

Bright Data bills per request. carrefour.es's listing pages only server-render about 8 real products per request (the rest are placeholders that need client-side scrolling — see Limitations), so the anti-bot cost per product is still low: roughly one request per 8 products in the default mode.

### Cost estimate

- **Listing only (default):** roughly one Bright Data request (~$0.0015) per 8 products, plus Apify compute — around $0.0002 in Bright Data cost per product. Scraping 100 products is about 13 page requests.
- **With Fetch product details:** one extra request per product, so a 100-product run costs roughly 13 + 100 = 113 requests. Only enable it when you need a confirmed brand, EAN, rating, or description on every row.

A run's usage cost only settles after it reaches the SUCCEEDED state — a run you abort partway through is billed for what it already used, not a flat per-item rate.

### How search and pagination work

carrefour.es doesn't expose a working free-text search results page (its search box is a client-side widget with no public JSON API, and the classic `?q=` query route returns a genuine server error, not a Cloudflare block). So **Search Query** is matched against a snapshot of carrefour.es's own category list to find the closest category, which is then scraped directly. Within that category, carrefour.es paginates via an `offset` step; the actor keeps requesting further offsets until it reaches **Max Results** or runs out of products.

For long runs with **Fetch product details** enabled, the actor persists its progress (the offset cursor and every product URL already seen). If Apify migrates the run to another host, it resumes where it left off instead of restarting, so you never get duplicate rows or a half-finished catalogue.

### Limitations

- **No free-text search.** `searchQuery` picks the closest matching category rather than running a live keyword search — for full control, pass an exact `categoryUrl` instead.
- **`brand` and `ean` are inconsistently exposed on the listing.** carrefour.es's own listing tiles carry these attributes for some products and not others (confirmed live — not a scraper bug, the site's own markup). Enable **Fetch product details** for a confirmed value on every row.
- **`rating`/`reviewCount`/`productDescription`** only exist on the product detail page, never on the listing — they require **Fetch product details**.
- **`inStock`** is only ever `true` (an active "add to cart" control) or `false` (an explicit "Agotado"/sold-out marker) — never guessed when genuinely unclear.
- Prices reflect the national online catalogue and may differ from a specific physical store.
- Data is scraped from the public website and may change without notice.
- Respect the website's terms of service and use responsibly.

### Related Scrapers

Build a complete view of Spanish and European grocery retail with these sibling scrapers from Studio AMBA:

- **[Mercadona Scraper](https://apify.com/studio-amba/mercadona-scraper)** — Spain's largest supermarket (mercadona.es).
- **[Dia Spain Scraper](https://apify.com/studio-amba/dia-es-scraper)** — Spanish discount grocery chain (dia.es).
- **[Alcampo Spain Scraper](https://apify.com/studio-amba/alcampo-es-scraper)** — Spanish hypermarket chain (alcampo.es).
- **[Eroski Spain Scraper](https://apify.com/studio-amba/eroski-es-scraper)** — Spanish/Basque supermarket chain (eroski.es).
- **[Carrefour France Scraper](https://apify.com/studio-amba/carrefour-fr-scraper)** — Carrefour's French storefront, a separate build on a different tech stack (carrefour.fr).

### 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 sources into one feed.

See [studioamba.dev/services](https://studioamba.dev/services/) or email
<hello@studioamba.dev> for a free data sample.
We maintain 300+ European web scrapers and answer within one business day.

# Actor input Schema

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

A Spanish grocery keyword (e.g. 'leche', 'pan', 'cafe', 'huevos'). carrefour.es has no working free-text search endpoint, so this is matched against the site's own category list and the best-matching category is scraped. For precise control, use "Category URL" instead.

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

An exact carrefour.es category URL, e.g. https://www.carrefour.es/supermercado/la-despensa/lacteos/leche/cat20093/c. When set, this is scraped directly instead of resolving Search Query to a category.

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

Maximum number of products to return.

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

Visit each product page to enrich results with a confirmed brand, EAN, rating, review count, and full description from structured data. This makes one extra request per product, so runs take longer and cost more. Without this, brand/EAN are only present when carrefour.es's listing tile exposes them (mainly Carrefour-exclusive lines), and rating/review count are never present in the listing.

## `brightDataApiKey` (type: `string`):

Your Bright Data API key for the Web Unlocker zone (web\_unlocker1). Required to bypass carrefour.es's Cloudflare Bot Management. Get one at https://brightdata.com. Can also be provided via the BRIGHT\_DATA\_API\_KEY environment variable.

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

Proxy settings. Kept for schema compatibility — page fetching is handled by Bright Data Web Unlocker, so this does not affect scraping.

## Actor input object example

```json
{
  "searchQuery": "leche",
  "maxResults": 20,
  "fetchDetails": false,
  "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 = {
    "searchQuery": "leche",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/carrefour-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 = {
    "searchQuery": "leche",
    "maxResults": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/carrefour-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 '{
  "searchQuery": "leche",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call studio-amba/carrefour-es-scraper --silent --output-dataset

```

## MCP server setup

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