# Cdiscount Scraper (`s-r/cdiscount-scraper`) Actor

- **URL**: https://apify.com/s-r/cdiscount-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Cdiscount Scraper

A Cdiscount scraper that turns a French search term into structured product rows: current price, the reference price it was reduced from, the advertised discount, rating, review count and the product code. No login, no API key, no browser.

It works because it does not ask as a browser. Cdiscount serves a browser user-agent a 14 KB JavaScript shell with no products in it, which is why almost nothing on the Apify Store covers France's second-largest retailer.

### What you get

- **Current price and reference price as separate numbers**, plus the discount percentage Cdiscount advertises and an `on_sale` flag that is only true when the reference price is genuinely higher
- **Rating and review count** split into numbers rather than left as "4,6 / 5 32 avis"
- **Product code** parsed out of the URL, so rows are joinable across runs and against your own catalogue
- **Refurbished detection**, because Cdiscount mixes reconditioned units into ordinary results and they are not comparable on price
- **The "Bon plan" deal badge** as a boolean
- **Up to 940 products per run**, 47 per page, with real pagination
- **Clean titles.** The site's title node also contains the rating line; that is cut off rather than shipped as part of the product name
- **Charged per row, not per compute unit.** A flat $0,002 start fee plus what you actually receive

### Why Cdiscount is missing from most scraping stacks

Cdiscount is the second-largest e-commerce site in France and a genuine price anchor for the French market, yet the Apify Store has essentially no working actor for it. The reason is not that anyone stopped trying. Request cdiscount.com with a normal browser user-agent and you get HTTP 200 with a 14 KB page. It looks like success. It contains no products.

Ask for the same URL as a crawler and Cdiscount returns the fully server-rendered 940 KB page with all 47 product cards in the HTML, because it wants to be indexed and summarised. That is the whole trick, and it is why this actor needs no browser, no captcha solver and no third-party unblocking service.

The second thing most attempts get wrong is the price. Cdiscount renders its price block as a label, a reference price, a discount badge and the actual price, all in one container. Read as a single string it says "Prix le + bas sur 30j | 349,99 € | -14% | 299,99 €", and taking the first number gives you **30** for a 299,99 coffee machine. Each figure here is read from its own element.

### Input

| Field | Type | Required | Default | What it does |
|---|---|---|---|---|
| `query` | string | yes | `iphone` | What to search for. French terms work best |
| `url` | string | no | – | A cdiscount.com search or category URL to read instead. Takes precedence |
| `limit` | integer | no | `47` | Products to return, 1 to 940 |
| `retries` | integer | no | `4` | Retry attempts per page, each with a different crawler user-agent |

### Output

```json
{
  "position": 1,
  "title": "KRUPS Machine à café broyeur à grain, Ecran tactile",
  "url": "https://www.cdiscount.com/electromenager/petit-dejeuner-cafe/krups-.../f-11011-kru0010942216513.html",
  "sku": "kru0010942216513",
  "price": 299.99,
  "was_price": 349.99,
  "discount_percent": 14,
  "on_sale": true,
  "price_text": "299,99 €",
  "currency": "EUR",
  "rating": 4.7,
  "reviews_count": 57,
  "image": "https://www.cdiscount.com/pdt2/...",
  "is_deal": true,
  "is_refurbished": false,
  "query": "machine a cafe"
}
```

### Use cases

**Price benchmarking in the French market.** Cdiscount competes directly with Amazon.fr and Fnac, and it discounts far more aggressively. Because `was_price` and `discount_percent` come from the site's own reference figures, you can tell a genuine markdown from a permanently discounted anchor price, which is the distinction that decides whether you follow it down.

**Finding where a category is on promotion.** Run a category, filter to `on_sale: true`, sort by `discount_percent`. That is a promotional calendar for the French market that nobody publishes, and it takes one run per category per day to build.

**Separating new from reconditioned.** Cdiscount is one of the largest refurbished sellers in France and mixes those listings into ordinary search results. `is_refurbished` lets you split the two before computing an average, which otherwise drags your market price down by a third.

**Feeding a French product catalogue.** `sku` comes out of the URL and is stable, `rating` and `reviews_count` are numbers, and `image` is an absolute URL. That is enough to build a catalogue and diff it weekly without a normalization pass.

### How it compares

| | this actor | `apify/e-commerce-scraping-tool` |
|---|---|---|
| Per 1.000 products | **$4,00** | $6,00 |
| Actor-start fee | **none** | $0,0001 |
| Covers Cdiscount | **yes** | generic, needs configuring |
| Reference price and discount % | **yes** | no |
| Verified `on_sale` flag | **yes** | no |
| Rating and review count | **yes** | no |
| Refurbished flag | **yes** | no |
| Needs a browser | **no** | no |

Honest about the other side: `apify/e-commerce-scraping-tool` has 575 monthly users and 49 reviews and will point at almost any shop. If you need breadth over depth, that is the better tool. This one knows one retailer's markup and its price-block quirks.

### Pricing

One event. `product` costs $0,0040 per product returned, which is $4,00 per 1.000. All pricing is pay-per-event, so you only pay for products you actually receive. A $0,002 start fee covers the run itself; everything else is charged per row you receive. No per-compute-unit charges.

### Limits and gotchas

- **Search results are French.** Cdiscount serves the French market, prices are in euros, and English search terms return poor results. Use French terms.
- **47 products per page**, and deep pagination thins out as Cdiscount stops returning relevant matches. The run summary reports how many pages were actually read.
- **`was_price` only appears when Cdiscount shows a reference price.** Many products, especially current-generation electronics, carry a single price. That is correct rather than missing.
- **Reconditioned units sit alongside new ones** in the same result set. Check `is_refurbished` before comparing prices.
- **Marketplace sellers are not always named on the card.** `seller` is empty for products sold by Cdiscount itself, which is most of them.
- **Class names on the site are generated hashes** that change on every deploy. Every selector here anchors on the stable semantic suffix or on `data-e2e`, but a large redesign would still need a parser update.

### FAQ

**Why does my Cdiscount scraper return an empty page?**
Because you asked as a browser. Cdiscount serves browser user-agents a small JavaScript shell with no products in the HTML. This actor asks as a crawler and gets the fully rendered page.

**Do I need a proxy or an unblocker?**
No third-party unblocking service and no browser. Requests egress from France so prices and availability match the French market.

**Can I scrape a category rather than a search?**
Yes. Paste any cdiscount.com listing URL into `url` and it is read the same way, including any filters you already applied in the browser.

**Is the discount percentage reliable?**
It is exactly what Cdiscount advertises. The `on_sale` flag is stricter: it is only true when the reference price is genuinely above the current price, so you can filter out badges that do not correspond to a real reduction.

**How do I track price changes over time?**
Schedule the run and store `sku`, `price` and the timestamp. The product code is stable, so a diff between runs is an exact join.

### Related Actors

- [Price Scraper](https://apify.com/s-r/price-scraper---extract-prices-availability-from-any-url) — price and availability from any product URL
- [John Lewis Scraper](https://apify.com/s-r/john-lewis-scraper) — the same treatment for the UK market
- [Google Shopping Scraper](https://apify.com/s-r/free-google-shopping-scraper---extract-offers-from-any-ean-sku) — offers from every merchant for an EAN or SKU

# Actor input Schema

## `query` (type: `string`):

What to search for on cdiscount.com. French terms work best, for example 'machine a cafe'.

## `url` (type: `string`):

A cdiscount.com search or category URL to read instead of a search term. Paste it straight from your browser. Takes precedence over the search term.

## `limit` (type: `integer`):

How many products to return, 1 to 940. A page carries 47 products.

## `retries` (type: `integer`):

Retry attempts per page, each with a different crawler user-agent and TLS fingerprint.

## Actor input object example

```json
{
  "query": "iphone",
  "url": "https://www.cdiscount.com/search/10/casque-bluetooth.html",
  "limit": 47,
  "retries": 4
}
```

# Actor output Schema

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

One row per product in listing order.

## `summary` (type: `string`):

itemCount, pagesFetched, how many rows carried a price and how many carried a URL.

## `errors` (type: `string`):

Failures with a code and a redacted message.

# 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 = {
    "query": "iphone",
    "limit": 47,
    "retries": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/cdiscount-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 = {
    "query": "iphone",
    "limit": 47,
    "retries": 4,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/cdiscount-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 '{
  "query": "iphone",
  "limit": 47,
  "retries": 4
}' |
apify call s-r/cdiscount-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/cdiscount-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/i3kqtVyqUxqik5Nhb/builds/jUXSjTCLERGJgkUza/openapi.json
