# Cdiscount Scraper: Products, Marketplace Sellers & Reviews (`abotapi/cdiscount-scraper`) Actor

Scrape product data from Cdiscount.com by keyword, category, or URL. Apply filters and sorting, then enrich results with full product details, marketplace seller information, pricing, availability, specifications, ratings, and customer reviews.

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

## Pricing

from $1.80 / 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

## Cdiscount Scraper: Products, Prices, Sellers & Reviews

Cdiscount Scraper turns Cdiscount into structured product data. Search by keyword and category with the site's own filters and sort, or paste your own product, category or search links. Every product comes with marketplace seller identity, and an optional enrichment step adds the full description, characteristics table, variants and customer reviews. Export to JSON, CSV or Excel, pull results through the API, or run it on a schedule with incremental mode to get only what changed.

### Why This Scraper?

- **Two ways to find products.** Search by keyword and category with Cdiscount's own filters and sort, or paste your own product, category or search links.
- **Marketplace seller identity on every result.** Cdiscount is mostly a marketplace, so each product carries the actual seller's id, name, rating, rating count and sales count, not just "sold by Cdiscount".
- **Optional detail enrichment.** Switch on the full description, the complete characteristics table, variants, shipping and energy details, the customer rating breakdown and the reviews shown on the product page (a handful, not the full set) for the products you actually need it on.
- **Built for schedules.** Incremental mode returns only new and updated products against a remembered baseline on recurring runs, and a genuinely blocked run fails loudly instead of quietly returning an empty dataset.
- **Resume one interrupted crawl.** Continue a large pull from its own previous run or dataset id without paying again for search or listing results it already collected.
- **Resilient enrichment.** If detail-page fetches start failing at a high rate mid-run, the actor stops retrying and falls back to base listings instead of spending the rest of the run on retries.
- **Send results straight into your apps.** Pipe scraped products into Notion, Linear, Airtable or Apify through MCP connectors, no extra step needed.

### Use Cases

- **Price and promotion tracking:** watch a keyword or category's prices, discounts and promo labels over time with Incremental mode.
- **Marketplace seller research:** see who is actually selling a listing, and compare seller ratings and sales volume across competing offers of the same product.
- **Catalog and assortment analysis:** build category-level datasets of products, brands, pricing and availability.
- **Review sampling:** pull the rating breakdown, the total review count and the reviews shown on each product page for a product line.
- **Deal and flash-sale monitoring:** filter for discounted, sponsored or promo-labelled products.

### Data You Get

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

| Field | Example |
| --- | --- |
| `id` | `"14404-AABQN14352"` |
| `productId` / `offerId` | `"14404"` / `"AABQN14352"` |
| `name` | `"DOOGEE Note56 Pro Smartphone 6.56\" 36Go 4+32"` |
| `brand` | `"DOOGEE"` |
| `url` | `"https://www.cdiscount.com/telephonie/telephone-mobile/doogee-note56-pro-smartphone-6-56-36go-4-32-12/f-14404-aabqn14352.html"` |
| `categoryPath` | `"07/0703"` |
| `condition` | `"Neuf"` (also seen: used, refurbished) |
| `price` / `currency` | `89.99` / `"EUR"` |
| `originalPrice` | `109.99` |
| `discountPercent` / `discountAmount` | `18.2` / `20.0` |
| `promoLabel` | `"Vente flash"` |
| `isAvailable` | `true` |
| `sponsored` | `false` |
| `freeShipping` | `true` |
| `media` / `previewImage` | array of image URLs / the first one |
| `rating` / `reviewCount` | `4.3` / `128` |
| `characteristics` | `{"Couleur": "Noir", "Memoire": "32 Go"}` |
| `sellerId` / `sellerName` | `"334455"` / `"TopMobileShop"` |
| `sellerRating` / `sellerRatingsCount` | `92.5` / `3400` |
| `sellerSalesCount` / `sellerCountry` | `18000` / `"FR"` |
| `page` / `rankOnPage` / `scrapedAt` | `1` / `7` / `"2026-10-14T08:00:00Z"` |
| `isCdav` / `isFbc` / `isDownloadable` | `false` / `true` / `false` (Cdiscount marketplace flags) |
| `sourceMode` / `searchWord` / `hasDetail` | `"search"` / `"telephone"` / `true` (detail ran) |
| `ean` | `"6975760890123"` (detail enrichment only) |

When **Fetch product details** is on, each product can also carry `description` (plain text), the full `characteristics` table (every attribute that product's page shows, not a fixed list), `variants` (colour, size or capacity combinations), `breadcrumb` (category path with names and links), `ratingBreakdown` (per-criterion averages) and `reviews` (author, date, rating, title and body for the reviews shown on the product page, usually about five). `reviewCount` is always the product's total number of reviews, never the number of reviews returned. Detail enrichment also adds `manufacturerModelNumber`, `maxOrderQuantity` (the most units one order accepts, not the stock level), `energyClass`, `isTradeInEligible`, `isFreeShipping`, `shippingLabel`, `shippingOrigin` and `questionsCount`. Stock quantity, delivery dates and warranty terms are not published on the product page, so they are not returned. In **Incremental mode**, every returned product also carries `changeType` (`NEW`, `UPDATED`, `UNCHANGED`, `REAPPEARED` or `EXPIRED`), `changedFields`, `firstSeenAt` and `lastSeenAt`.

### How to Use

1. Pick a **mode**: `search` (keyword, category and filters) or `url` (paste your own product, category or search links).
2. Fill in the fields for that mode, and turn on **Fetch product details** if you need the full description, characteristics, variants and reviews.
3. Set **Max items** and, optionally, **Max pages** to control run size and cost, then click **Start**.
4. Download the dataset as JSON, CSV or Excel, or read it through the API. Five ready-made views are available in the Output tab: Overview, Full detail, Marketplace sellers, Reviews (one row per review shown on the product page, with author, date, review rating, title and text) and Changes (incremental mode). A run summary with per-link counts (rows returned, enriched, refused fetches, pages read) and the final status is saved as the `OUTPUT` record of the run's key-value store.

**Search by keyword:**

```json
{
  "mode": "search",
  "searchWord": "aspirateur",
  "maxItems": 30
}
```

**Search scoped to a category, sorted by price, with detail enrichment:**

```json
{
  "mode": "search",
  "searchWord": "telephone",
  "departmentId": "10",
  "sortBy": "priceAsc",
  "fetchDetails": true,
  "maxItems": 50
}
```

**Supported link shapes (url mode):**

| Shape | Example | Behaviour |
|---|---|---|
| Category listing | `https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html` | Forward-paginated |
| Paginated category link | `https://www.cdiscount.com/telephonie/telephone-mobile/l-14404-2.html` (or `l-14404.html?page=2`) | Starts from that page and walks forward |
| Brand, department-hub or seller listing | `https://www.cdiscount.com/telephonie/v-144-0.html`, `.../m/apple/v-1448902-1448902.html` | Forward-paginated |
| Search page | `https://www.cdiscount.com/search/10/telephone.html` | Forward-paginated |
| Product page | `https://www.cdiscount.com/.../f-14404-aabqn14352.html` | One item, always read in full |

Any other link (the home page, a category path without an `l-NNNN` id, a help or shipping page, a non-Cdiscount site) is skipped with a warning in the run log. If you leave **Start URLs** untouched in url mode, the field holds four example links: a category, a search, a product and a page-2 link of the same category. They are read in that order, and with the default **Max items** (20) the run fills from the first link and stops, so the other links are not read. When **Max items** is high enough to reach them, the example category and search links bill per product returned and the example product link is read in full, so it also bills one Detail enrichment. A page-2 or later link whose products were already read earlier in the run is dropped after two pages that add nothing new, so overlapping links do not cost extra pages. The **Department / category ID** field also accepts a pasted category link; a value that is neither a number nor such a link stops the run with an error (category names are not looked up).

**Behaviour change:** leaving **Start URLs** untouched in url mode now reads the four example links (category, search, product, page-2 category link) in order instead of returning nothing; with the default **Max items** (20) the run stops after filling from the first link. Set **Max items** to bound the cost.

**Paste a category link:**

```json
{
  "mode": "url",
  "urls": ["https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html"],
  "maxPages": 3,
  "maxItems": 100
}
```

**Recurring monitoring of the same search, only what changed:**

```json
{
  "mode": "search",
  "searchWord": "telephone",
  "departmentId": "10",
  "incrementalMode": true,
  "maxItems": 200
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/cdiscount-scraper").call(run_input={"mode": "search", "searchWord": "telephone", "maxItems": 30})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(product["name"], product["price"], product["sellerName"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/cdiscount-scraper').call({ mode: 'search', searchWord: 'telephone', maxItems: 30 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

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

#### Filter IDs (advanced)

`filterIds` takes raw facet ids exactly as Cdiscount's own filter sidebar uses them, for example a brand, a price band, a condition, a seller or a colour. These ids are specific to Cdiscount's own filter system and vary by category; the sidebar on the live site is the source of truth for which ids apply to a given search.

#### Resume and recurring updates

- **Resume** (`resumeFromRunId`) continues one interrupted crawl. Paste its run or dataset id and the actor skips every search or listing result that run already collected, so you don't pay twice (individually pasted product links are always re-read and returned).
- **Incremental mode** (`incrementalMode`) is for running the same search or URL set again and again on a schedule. State is kept per mode, search/URL and filter setup (or under your own `stateKey`), so two differently-configured runs never mix baselines. By default (with `emitExpired` and `emitUnchanged` off) a run after the first one returns only `NEW` and `UPDATED` products; unchanged products are tracked internally but not returned or billed. Turning on `emitExpired` also returns products that vanished, marked `EXPIRED`, but only once a run has completed a full scan of every tracked search or URL, never when Max items or Resume cut it short. A product is only ever classified `REAPPEARED` if an earlier completed run with `emitExpired` on had already marked it `EXPIRED`; without that prior tombstone, a product that comes back simply looks `UPDATED` or `UNCHANGED` like any other rescrape, never `REAPPEARED` by default.
- **What counts as a change.** A product is `UPDATED` when a tracked field changes: price, original price and discount, promotion labels, availability, seller, name, brand, rating and review count, and with **Fetch product details** the description, characteristics, variants and reviews. `media`, `previewImage` (rotating image-server addresses), `sponsored` (an ad-slot flag) and `page`, `rankOnPage`, `scrapedAt` are never counted as a change but are still returned. Use **Ignore fields when detecting changes** (`ignoreFieldsForChanges`) to exclude more fields, with a dotted path such as `variants.price` for fields inside a list. `changedFields` never names an ignored field.
- Combining `incrementalMode` with `resumeFromRunId` on the very first run for a state key bootstraps that baseline from the resumed crawl's results. If a baseline already exists for that state key, the run fails immediately instead of mixing the two.

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

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 item pages should be created.

Notion gets one page per product, with a title and the product's key fields flattened to text. Other connectors get a best-effort write of one record per product, or a short digest message if no create-style tool is available. `maxNotifyListings` caps how many products are sent to each connector per run; it never changes what is written to the dataset. 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` (keyword/category + filters) or `url` (your own URLs). |
| `searchWord` | string | none (prefill: `telephone`) | Keyword to search for. Used in search mode. |
| `departmentId` | string | none | Numeric category id to scope the search. Leave empty to search all categories. |
| `filterIds` | array | `[]` | Raw facet filter ids, exactly as the site's own filter sidebar uses them (search mode, advanced). |
| `sortBy` | string | `relevance` | `relevance`, `bestsales`, `priceAsc`, `priceDesc`, or `rating`. |
| `urls` | array | four sample links: a category, a search, a product and a page-2 category link, read in order until Max items is reached (used when the field is left untouched in url mode) | Product, category or search URLs (url mode). Category and search URLs are forward-paginated. |
| `fetchDetails` | boolean | `false` | Add full description, characteristics, variants, seller detail and reviews per product. |
| `maxItems` | integer | `20` | Maximum number of products to return. The run stops once this many items are collected. |
| `includeSponsored` | boolean | `true` | Keep sponsored (advertised) placements. Turn off to drop them before they are returned or billed. |
| `maxPages` | integer | none (omitted or `0` reads until results end or Max items; a hard cap of 100 pages per search or URL always applies) | Maximum number of result pages to read per search or URL. |
| `resumeFromRunId` | string | none | Continue one interrupted crawl without re-returning or re-charging products it already collected. |
| `ignoreFieldsForChanges` | array | none | Extra output fields (dotted paths allowed) that never make a product `UPDATED`. Image lists, `sponsored`, `page`, `rankOnPage` and `scrapedAt` are always ignored. |
| `incrementalMode` | boolean | `false` | Recurring monitoring of the same search/URL set: return only new and changed products against a remembered baseline. |
| `stateKey` | string | none (auto-derived from mode, search/URL and filter settings) | Name a monitoring campaign, or deliberately share state across differently-configured runs. |
| `emitUnchanged` | boolean | `false` | Also return (and bill) `UNCHANGED` products. Off by default. |
| `emitExpired` | boolean | `false` | Also return (and bill) `EXPIRED` products once a run fully scans every tracked search or URL. Off by default. |
| `proxyConfiguration` | object | Apify Proxy, residential group, France | Connection settings. |
| `mcpConnectors` | array | none | Optionally send a summary of each product to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | none | Notion connector only: page under which item pages are created. |
| `maxNotifyListings` | integer | `20` | Cap on items written to each MCP connector per run. Does not affect the dataset. |

### Output Example

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

```json
{
  "id": "14404-AABQN14352",
  "productId": "14404",
  "offerId": "AABQN14352",
  "name": "DOOGEE Note56 Pro Smartphone 6.56\" 36Go 4+32",
  "brand": "DOOGEE",
  "url": "https://www.cdiscount.com/telephonie/telephone-mobile/doogee-note56-pro-smartphone-6-56-36go-4-32-12/f-14404-aabqn14352.html",
  "categoryPath": "07/0703",
  "condition": "Neuf",
  "price": 89.99,
  "currency": "EUR",
  "originalPrice": 109.99,
  "discountPercent": 18.2,
  "discountAmount": 20.0,
  "promoLabel": "Vente flash",
  "isAvailable": true,
  "sponsored": false,
  "freeShipping": true,
  "media": ["https://example.com/img/p1.jpg", "https://example.com/img/p2.jpg"],
  "previewImage": "https://example.com/img/p1.jpg",
  "rating": 4.3,
  "reviewCount": 128,
  "characteristics": { "Couleur": "Noir", "Memoire": "32 Go" },
  "sellerId": "334455",
  "sellerName": "TopMobileShop",
  "sellerRating": 92.5,
  "sellerRatingsCount": 3400,
  "sellerSalesCount": 18000,
  "sellerCountry": "FR",
  "hasDetail": true,
  "sourceMode": "search",
  "searchWord": "telephone",
  "ean": "6975760890123",
  "description": "Smartphone with a 6.56 inch display, 32GB storage and 4GB RAM.",
  "variants": [{ "name": "Noir 32Go", "url": "https://example.com/f-14404-variant.html" }],
  "ratingBreakdown": [{ "criterion": "Qualite", "average": 4.1 }],
  "reviews": [{ "author": "M. Dupont", "date": "2026-06-01", "rating": 5, "title": "Tres bien", "body": "Rapide et fiable." }]
}
```

### Plan Requirement

Cdiscount protects its pages with a browser challenge, so this actor needs a working Apify Proxy connection. The default connection is the Apify residential group in France. It has not been confirmed that cheaper datacenter proxies can load these pages, so do not count on them. Apify free plans do not include residential proxies: on a free plan the run continues on a backup connection, and some pages may still be unavailable. For dependable results use a paid Apify plan, or supply your own proxy URLs under Connection.

What you will see in the run log and in the run's status message:

- When the selected connection is unavailable, the log warns: "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. For residential access, upgrade at https://apify.com/pricing or supply your own proxy URLs."
- When pages were served on the backup connection: "Served over the backup connection (the default connection was unavailable)."
- If the proxy refuses the account, the run fails with: "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: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid."
- If no residential access is available and the backup connection also fails: "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 Cdiscount pages. Upgrade at https://apify.com/pricing or supply your own proxy URLs, then try again."
- If requests simply fail: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

### FAQ

#### How much does it cost?

You pay per product returned, plus a detail-enrichment charge for each returned product that was enriched: every product when **Fetch product details** is on, and always for product links pasted in URL mode (a product page is always read in full). Pricing is pay per event with three events: **Product result** (per product returned), **Detail enrichment** (per enriched product) and **Actor Start** (one-time). Rates are tiered by your Apify plan; the **Pricing** tab shows the current figures. The reviews shown on the product page are included in the detail-enrichment charge, with no separate review fee. Sponsored placements are returned and billed like any product unless you turn off **Include sponsored**. Use **Max items** to cap the cost of any run.

#### Is it legal to scrape Cdiscount?

This actor collects only publicly available marketplace listings. You are responsible for how you use the data: follow Cdiscount's terms and the laws that apply to you, and get legal advice before any commercial redistribution. Product images, brand names and customer reviews may carry their own rights separate from the underlying facts.

#### 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 against a remembered baseline for that search or URL set, and unchanged products are neither returned nor billed unless you turn on **Emit unchanged**. **Emit expired** marks products that vanished, but only once a run has completed a full scan of every tracked search or URL, not when Max items or Resume cut it short; and a product only comes back as `REAPPEARED` after one of those completed runs already marked it `EXPIRED`, not on every reappearance by default.

#### What's the difference between Resume and Incremental mode?

**Resume from a previous run** continues one specific interrupted crawl, skipping products that run already collected, and is meant to be used once. **Incremental mode** is for running the same search or URL set again and again and getting a diff every time. Combining Incremental mode with Resume on the first run for a state key bootstraps the baseline from that resumed crawl; if a baseline already exists for that state key, the run fails immediately instead of silently mixing the two.

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

If the actor could not establish a working connection to the site, or every page it tried came back blocked, the run fails with a message that says so, so "no products found" is never confused with "nothing could be read". A genuinely empty search (a keyword with no matches) still finishes successfully with zero rows. An invalid `resumeFromRunId`, or combining Incremental mode with Resume when a baseline already exists for that state key, also fails the run immediately rather than mixing data.

#### 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 e-commerce data?

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

<table>
<tr><td>🛒 <a href="https://apify.com/abotapi/castorama-fr-scraper"><b>Castorama.fr</b></a><br>Scrape Castorama.fr DIY and home-improvement products by keyword, category, or URL...</td><td>🛒 <a href="https://apify.com/abotapi/tokopedia-scraper"><b>Tokopedia Scraper</b></a><br>Extract product data from Tokopedia, Indonesia’s largest marketplace. Search by keyword...</td></tr>
<tr><td>🛒 <a href="https://apify.com/abotapi/mediamarkt-de-scraper"><b>MediaMarkt Germany Scraper</b></a><br>Scrape MediaMarkt.de products by keyword or URL. Extract current and original prices...</td><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></tr>
<tr><td>🧩 <a href="https://apify.com/abotapi/aliexpress-scraper"><b>AliExpress Scraper</b></a><br>Scrape AliExpress products: search by keyword or category, or process pasted search...</td><td>🛒 <a href="https://apify.com/abotapi/mediamarkt-es-scraper"><b>MediaMarkt.es Scraper</b></a><br>Scrape MediaMarkt Spain (mediamarkt.es) products: current price, strike-through original...</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/cdiscount-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`):

Choose Search to use a keyword, category and filters. Choose URLs to paste Cdiscount product, category or search links. Only the chosen mode is used: in Search mode the Start URLs are ignored, in URL mode the keyword, category and filters are ignored.

## `searchWord` (type: `string`):

Keyword to search for, e.g. "telephone" or "aspirateur". Used in search mode.

## `departmentId` (type: `string`):

Numeric Cdiscount department id to scope the search to one category (e.g. "10" for Téléphonie). You can also paste a category link (.../l-NNNN.html) or search link and the id is taken from it; anything else stops the run with a clear error. Copy it from a Cdiscount category URL (the number after /l- or /search/). Leave empty to search all categories.

## `filterIds` (type: `array`):

Raw Cdiscount facet filter ids to narrow results, exactly as the site's own filter sidebar uses them (e.g. "Neuf ou occasion/"neuf"", "Marque/"samsung"", "categorycodepath/"07/0703""). Run once with maxItems=1 and read the `facets` debug field logged at INFO level to discover the ids for your category, then pass the ones you want here.

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

Order in which search results are returned. Used in search mode.

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

Cdiscount product URLs (.../f-NNNNN-XXXXXXXX.html), category/listing URLs (.../l-NNNNN.html, or a page-2+ link .../l-NNNNN-P.html), brand/hub listing URLs (.../v-N-N.html), or search URLs (/search/{department}/{word}.html). Listing/search URLs are forward-paginated.

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

Open each product's page to add the full description, complete characteristics table, variants, marketplace seller detail, shipping and energy details, the rating breakdown and the reviews shown on the product page (a handful, not the full set). Adds one detail request per product.

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

Maximum number of products to return. The run stops once this many items are collected.

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

Maximum number of result pages to read per search/listing URL. Leave empty (0) to read until the results end or Max items is reached; the run never reads more than 100 pages per search or URL.

## `includeSponsored` (type: `boolean`):

Keep sponsored (advertised) placements in search and listing results. Turn off to drop them before they are returned or billed.

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

For large or sustained runs, use a France-based proxy for best reliability.

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

Paste a previous run ID or dataset ID to continue a large crawl of products without returning or charging for products already collected there. Use this after an interrupted run, or when continuing a product pull in another run. For recurring monitoring of the same search, use Incremental mode below instead.

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

Turn this on for daily or recurring monitoring. The first run returns all matching products as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED products. A product is UPDATED when a tracked field changes: price, original price and discount, promotion labels, availability, seller, name, brand, rating and review count, and (with Fetch product details) description, characteristics, variants and reviews. Never counted as a change (still returned): image lists (media, previewImage), the sponsored flag, and page, rankOnPage, scrapedAt (extend the list with Ignore fields below). Turn on "Emit unchanged" or "Emit expired" only when you also want those products returned (and billed). State is kept separately for each mode/search-or-URL/filter setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

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

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the mode, search/URL and filter settings -- different searches then never mix state with each other.

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

Off by default. Turn on to also return products that have not changed since the last run, marked UNCHANGED. This returns -- and bills -- extra rows you already have, so leave it off unless you specifically want the full snapshot every run.

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

Off by default. Turn on to also return products that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned every tracked search/URL -- not when Max items capped it or when Resume was used. This returns -- and bills -- extra synthetic rows, so leave it off unless you need expiry tracking.

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

Output field names that should NOT make a product count as UPDATED. Always ignored: media and previewImage (the same photos are served from rotating image-server addresses), sponsored (an ad-slot flag), and page, rankOnPage, scrapedAt and fetchedAt (where and when this run saw the product). Add fields such as description or reviews here if changes to them are not relevant to you. Use a dotted path (for example variants.price) to ignore a field inside a list of objects. Ignored fields are still returned in the output.

## `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. Leave empty to skip.

## `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 MCP connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "searchWord": "telephone",
  "filterIds": [],
  "sortBy": "relevance",
  "urls": [
    "https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html",
    "https://www.cdiscount.com/search/10/telephone.html",
    "https://www.cdiscount.com/telephonie/telephone-mobile/samsung-galaxy-a23-5g-64g-bleu/f-14404-sam8806094534115.html",
    "https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html?page=2"
  ],
  "fetchDetails": false,
  "maxItems": 20,
  "includeSponsored": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 20
}
```

# Actor output Schema

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

No description

## `details` (type: `string`):

No description

## `sellers` (type: `string`):

No description

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

No description

## `changes` (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",
    "searchWord": "telephone",
    "urls": [
        "https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html",
        "https://www.cdiscount.com/search/10/telephone.html",
        "https://www.cdiscount.com/telephonie/telephone-mobile/samsung-galaxy-a23-5g-64g-bleu/f-14404-sam8806094534115.html",
        "https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html?page=2"
    ],
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/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 = {
    "mode": "search",
    "searchWord": "telephone",
    "urls": [
        "https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html",
        "https://www.cdiscount.com/search/10/telephone.html",
        "https://www.cdiscount.com/telephonie/telephone-mobile/samsung-galaxy-a23-5g-64g-bleu/f-14404-sam8806094534115.html",
        "https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html?page=2",
    ],
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/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 '{
  "mode": "search",
  "searchWord": "telephone",
  "urls": [
    "https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html",
    "https://www.cdiscount.com/search/10/telephone.html",
    "https://www.cdiscount.com/telephonie/telephone-mobile/samsung-galaxy-a23-5g-64g-bleu/f-14404-sam8806094534115.html",
    "https://www.cdiscount.com/telephonie/telephone-mobile/l-14404.html?page=2"
  ],
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false
}' |
apify call abotapi/cdiscount-scraper --silent --output-dataset

```

## MCP server setup

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