# Darty Scraper - Prices, Discounts, Specs & Reviews (`abotapi/darty-com-scraper`) Actor

Scrape Darty (darty.com) products: current price plus strike-through reference price and discount, brand, category breadcrumb, full spec sheet, and the site's own customer reviews with rating breakdown. Search by keyword or paste product/listing links.

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

## Pricing

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

## Darty Scraper: Prices, Discounts, Specs & Reviews

Darty Scraper turns darty.com, the French consumer-electronics and appliance retailer (part of Fnac Darty), into structured product data. Search by keyword or paste product and search-result links, and get the current price, the strike-through reference price with a computed discount whenever a product is genuinely marked down, brand and category, and the site's own customer reviews. Export to JSON, CSV or Excel, or pull results straight into your app through the API.

### Why This Scraper?

- **Was-price and discount, structured, never fabricated.** When a product is marked down against darty.com's own reference price, both prices are captured plus the computed discount amount, percentage, and the site's own promo label (e.g. "Bon Plan", "Soldes"). A full-price product always carries `null` there, never a guessed markdown.
- **Real narrowing, not a filter that quietly does nothing.** Rating floor and free-delivery narrow via the site's own search facets, verified against live results; brand narrows against the site's own card-level brand field; sort reorders the full server-side result set.
- **Reviews straight from the product page.** Overall rating, total review count, recommend-percentage, per-criteria scores (e.g. ease of use, value for money), and the page's own individual reviews, not a third-party review vendor.
- **Flattened spec sheet on demand.** Full detail returns every characteristic the product page itself declares (screen size, energy class, dimensions, EAN, and whatever else that category carries) rather than a fixed field list, so nothing category-specific is silently dropped.
- **Two ways in.** Keyword search with real site filters (brand, price range, discount-only, rating, free delivery, sort), or paste any product or search-result link and continue pagination automatically.
- **Optional export to your apps.** Send results into Notion, Linear, Airtable, or any Apify MCP connector alongside the dataset.
- **Resume and recurring updates.** Turn on Incremental mode for scheduled runs to track NEW and UPDATED products against a remembered baseline; expiry and reappearance tracking are available too, gated behind their own toggle. Or continue one specific interrupted crawl with `resumeFromRunId`.

### Use Cases

- **Price comparison and deal sites:** track was-price/now-price pairs and genuine discounts across TVs, appliances and electronics.
- **Repricing and competitive intelligence:** monitor a brand's or category's Darty pricing on a recurring schedule.
- **Product research and buying guides:** pull full spec sheets, images and reviews before publishing comparisons.
- **Review analytics:** aggregate rating breakdowns and individual written reviews across a catalog.
- **Catalog and availability monitoring:** Incremental mode flags newly listed, updated and (optionally) delisted products.

### Data You Get

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

| Field | Example |
| --- | --- |
| `productId` | `"00000001"` (Darty's own "codic") |
| `name` | `"TV LED Sample Brand X100 80 cm"` |
| `brand` | `"Sample Brand"` |
| `category` | `"TV LED"` |
| `url` | link to the product page |
| `image` | card thumbnail image URL |
| `price` / `currency` | `119.99` / `"EUR"` |
| `originalPrice` | `149.99` (only when genuinely marked down, else `null`) |
| `discountAmount` / `discountPercent` | `30.00` / `20.0` |
| `isOnSpecial` | `true` |
| `promoLabel` | `"Bon Plan"` |
| `rating` | `4.5` |
| `reviewCount` | `26` |
| `inStock` | `true` (every listing card reports this placeholder; refined to the page's own real stock status once Fetch full product detail is on) |
| `condition` | `"new"` (same placeholder-then-refined pattern as `inStock`) |
| `seller` | `"Darty"` |
| `reviews.averageRating` / `reviews.totalReviewCount` | `4.5` / `26` |
| `reviews.recommendPercent` | `93` |
| `reviews.criteria` | `[{"name": "Ease of use", "score": 4.8}]` |
| `reviews.items[]` | `[{"rating": 5, "title": "Sample title", "body": "Sample review text.", "author": "JANE", "level": "confirmed", "postedDate": "01/01/2026", "purchaseDate": "20/12/2025", "purchaseStore": "DARTY SAMPLE"}]` |

Turn on Fetch full product detail (off by default) and a search or listing result also gains `ean`, `breadcrumbPath` (the full category trail), the flattened `specs` object, the full `images` gallery, a free-text `description`, and `availabilityLabel` alongside the refined, real `inStock`/`condition`. A pasted single product URL fetches its own page in full regardless of that toggle, so it always carries the real `ean`, `breadcrumbPath`, `inStock` and `condition`; only `specs`, `images` and the reviews depend on the enrichment toggles there, and unlike an enriched search or listing result, a pasted product URL's own record never carries `description` at all (that field is only ever populated on the search/listing enrichment path).

### How to Use

1. Pick a **mode**: `search` (keyword and site filters) or `url` (paste product or search-result-listing links).
2. Fill in the fields for that mode. `brands`, `minPrice`, `maxPrice` and `specialsOnly` narrow results in both modes, including a pasted product URL.
3. Toggle **Fetch full product detail** and **Fetch reviews** for the depth you need, and set **Max products** / **Max pages** to control run size and cost.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

**Keyword search, first page, with reviews (default):**

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

**Keyword filtered to a brand, discounted items only, 4+ stars, sorted by price:**

```json
{
  "mode": "search",
  "searchTerm": "television",
  "brands": ["Samsung"],
  "specialsOnly": true,
  "minRating": 4,
  "sortBy": "PRICE_ASC",
  "maxItems": 50,
  "maxPages": 5
}
```

**A pasted product link, full detail and reviews:**

```json
{
  "mode": "url",
  "urls": ["https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/sample-brand-x100.html"],
  "fetchDetails": true,
  "fetchReviews": true
}
```

**Recurring monitoring of a search, including delisted products:**

```json
{
  "mode": "search",
  "searchTerm": "lave-linge",
  "incrementalMode": true,
  "emitExpired": true,
  "maxItems": 0,
  "maxPages": 0
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/darty-com-scraper").call(run_input={"mode": "search", "searchTerm": "television", "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/darty-com-scraper').call({ mode: 'search', searchTerm: 'television', 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.

#### Filters that apply to every mode

`brands`, `minPrice`, `maxPrice` and `specialsOnly` narrow results in BOTH search mode and URL mode, including a pasted single product URL: they are applied client-side against the site's own real card or product fields after the fetch, never by changing the request. `minRating`, `freeDeliveryOnly` and `sortBy` only work in search mode, since darty.com only honors them as parameters on its own search URL; a pasted URL keeps whatever sort or rating filter its own query string already carries.

#### Full detail, reviews, and what gets charged

A search or listing result only gets its product page fetched when Fetch full product detail or Fetch reviews is on; leave both off and you stay at listing speed with the base per-result charge only. A pasted single product URL is different: there is no listing card to fall back on, so its product page is always fetched in full regardless of these toggles, and you always get the real EAN, breadcrumb category and true stock/condition. But the Detail & review enrichment surcharge is only ever billed when that fetch actually happens because Fetch full product detail and/or Fetch reviews is on (Fetch reviews defaults to on, so a default pasted-URL run is billed for it); turn both off and the fetch still happens for free, just without the spec sheet, image gallery or reviews in the output.

#### Resume and recurring updates

Two different things, both under the same input section:

- `resumeFromRunId` continues ONE specific interrupted crawl. Paste a previous run ID or dataset ID and this run skips every product that run already collected, picking up where it left off.
- `incrementalMode` is for running the SAME search or URL set again and again (daily, weekly, on a schedule) and getting only what changed. State is kept in a dedicated key-value store, keyed automatically from the mode, the keyword or URL list, `fetchDetails`/`fetchReviews` (since they change the emitted record shape), and, in search mode only, the filter settings (URL mode does not fold filters into the key), or your own `stateKey` if you want to name or share a campaign deliberately.

Every scanned product is classified as `changeType`: `NEW` (first time seen), `UPDATED` (a comparable field changed, see `changedFields`), or `UNCHANGED` (tracked but not returned unless `emitUnchanged` is on). `EXPIRED` is different: it is only ever produced when `emitExpired` is on AND this run reached the natural, uncapped end of every tracked search/URL (not when Max products capped the run, Resume was used, or a result page was refused). An incomplete scan cannot tell "genuinely gone" from "not reached yet", so those runs skip expiry detection and leave the previous state untouched. `REAPPEARED` follows from that: it can only ever fire for a product this same state key previously marked EXPIRED and has now seen again. A state key that has never run with `emitExpired` on can never produce a REAPPEARED product. With Incremental mode off, output is exactly as before.

`incrementalMode` defaults to `false`; a normal run's behavior and output shape are unchanged until you opt in. Combining it with `resumeFromRunId` bootstraps a brand-new monitoring campaign from that resumed crawl's results; if a baseline already exists for the derived (or given) state key, the run fails fast rather than silently mixing the two.

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

Optionally pipe results into the apps you already use through 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 **`mcpConnectors`** 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; it never changes the dataset output.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` (keyword and facets) or `url` (paste product/listing links). |
| `searchTerm` | string | no default (prefill: `television`) | Free-text keyword. Uses darty.com's own product search. Search mode only. |
| `minRating` | integer | `0` | Minimum star rating (1-5), via darty.com's own search facet. `0` = no rating filter. Search mode only; written into the search URL, so a pasted URL keeps whatever it already carries. |
| `freeDeliveryOnly` | boolean | `false` | Only return products showing free home delivery, via darty.com's own search facet. Search mode only. |
| `sortBy` | string | `RELEVANCE` | `RELEVANCE`, `PRICE_ASC`, `PRICE_DESC`, `RATING_DESC`, or `NEWEST`. Verified live to reorder the full server-side result set. Search mode only. |
| `urls` | array | default and prefill: seven sample links covering a search results page (plain, paginated, sorted and filtered), a category listing (plain and paginated) and one product page (used only in URL mode when you leave the list untouched; search mode ignores it, so a search-mode run and its saved incremental baseline are unchanged) | Darty product or search-result-listing links to scrape. Pagination continues forward automatically from any offset already in the URL. URL mode only. |
| `brands` | array | no default (prefill: empty) | Exact brand names to keep, matched against the site's own card-level brand field, case-insensitive. Applies in BOTH search mode and URL mode, including a pasted product URL. |
| `minPrice` | number | no default | Only return products priced at or above this amount, in euros. Applies in BOTH search mode and URL mode. |
| `maxPrice` | number | no default | Only return products priced at or below this amount, in euros. Applies in BOTH search mode and URL mode. |
| `specialsOnly` | boolean | `false` | Keep only products currently showing a genuine strike-through discount against darty.com's own reference price. Applies in BOTH search mode and URL mode. |
| `fetchDetails` | boolean | `false` | Fetch full product detail: description, EAN, breadcrumb category, the complete flattened spec sheet, and the full image gallery. Current price, discount, rating and card image are already included without this toggle. |
| `fetchReviews` | boolean | `true` | Fetch the product's own customer reviews: overall rating, total review count, recommend-percent, per-criteria scores, and the page's own most recent written reviews. |
| `maxReviewsPerProduct` | integer | `20` | Cap on written reviews fetched per product when Fetch reviews is on (values above 100 are capped at 100), up to the number of reviews the product page itself shows. Reviews are not billed separately; they ride on the existing Detail & review enrichment charge. |
| `maxPages` | integer | no default (unlimited) | Stop after this many result pages per search/URL entry. Leave empty for no page limit; the run still stops at Max products total. |
| `maxItems` | integer | `20` | Hard cap on total products returned across every search/URL entry. `0` = unlimited. |
| `resumeFromRunId` | string | no default | Previous run ID or dataset ID to continue ONE interrupted crawl without re-returning or re-charging products it already collected. |
| `incrementalMode` | boolean | `false` | Recurring monitoring of the same search/URL set: returns only NEW and UPDATED products (plus REAPPEARED/EXPIRED once you opt into those) against a remembered baseline. |
| `stateKey` | string | no default | Name a monitoring campaign, or deliberately share state across differently-configured runs. Leave empty to derive one automatically. Incremental mode only. |
| `emitUnchanged` | boolean | `false` | Also return UNCHANGED products. Off by default; returns and bills rows you already have. Incremental mode only. |
| `emitExpired` | boolean | `false` | Also return EXPIRED products, and only once a run has fully scanned every tracked search/URL. Off by default; returns and bills extra synthetic rows. Incremental mode only. |
| `ignoreFieldsForChanges` | array | empty | Field names (dotted paths for nested fields, e.g. `reviews.count`) that must not make a product UPDATED. They stay in the output and are left out only of the comparison and `changedFields`. Incremental mode only. |
| `proxy` | object | Residential (FR) | Proxy configuration. Leave the default as provided; this source needs it. Change only the region if you need a different one. |
| `mcpConnectors` | array | no default | Optional MCP connectors to export results into (Notion, Linear, Airtable, Apify). |
| `notionParentPageUrl` | string | no default | 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. Shown with Fetch full product detail and Fetch reviews both on.

```json
{
  "productId": "00000001",
  "ean": "0000000000000",
  "url": "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/sample-brand-x100.html",
  "image": "https://image.darty.com/darty?type=image&source=/sample/000000000.jpg",
  "name": "TV LED Sample Brand X100 80 cm",
  "brand": "Sample Brand",
  "category": "TV LED",
  "price": 119.99,
  "currency": "EUR",
  "originalPrice": 149.99,
  "discountAmount": 30.00,
  "discountPercent": 20.0,
  "isOnSpecial": true,
  "promoLabel": "Bon Plan",
  "rating": 4.5,
  "reviewCount": 26,
  "inStock": true,
  "availabilityLabel": "En stock",
  "condition": "new",
  "seller": "Darty",
  "description": "Sample product description as shown on the product page.",
  "breadcrumbPath": ["TV, Video, Home cinema", "Television", "TV LED"],
  "specs": { "Screen size (inches)": "32 \"", "Definition": "HD (720p)", "Energy class": "E" },
  "images": [
    "https://image.darty.com/darty?type=image&source=/sample/000000000.jpg",
    "https://image.darty.com/darty?type=image&source=/sample/000000001.jpg"
  ],
  "reviews": {
    "averageRating": 4.5,
    "totalReviewCount": 26,
    "recommendPercent": 93,
    "criteria": [{ "name": "Ease of use", "score": 4.8 }],
    "items": [
      { "rating": 5, "title": "Sample title", "body": "Sample review text.", "author": "JANE", "level": "confirmed", "postedDate": "01/01/2026", "purchaseDate": "20/12/2025", "purchaseStore": "DARTY SAMPLE" }
    ]
  }
}
```

### Plan Requirement

The default proxy configuration (Apify's residential group, France) ships as the default and is required; leave it as provided. Change only the region if you need a different one. The actor works through its own connection ladder automatically when a request is refused, so most runs need no manual retry.

### FAQ

#### How much does it cost?

Three events apply. Actor start is charged once per run. Product result is charged once per product row pushed to the dataset. Detail & review enrichment is charged once per product whose page is actually fetched for full detail and/or reviews (on by default, since Fetch reviews defaults to on); the written reviews (20 per product by default, up to 100) ride on that charge and are not billed separately. Products that are filtered out, skipped or not delivered are not charged. The **Pricing** tab shows the current rates for all three events. Use **Max products** to cap the cost of any run.

#### Is it legal to scrape Darty?

This actor collects only publicly available product data from darty.com. You are responsible for how you use it: follow darty.com's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices and specifications are generally facts, but images, descriptions and review text 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 against a remembered baseline; UNCHANGED products are tracked but not billed unless you turn on Emit unchanged.

#### Why is `originalPrice` null on most products?

It reflects darty.com's own reference price and is only ever populated when it is genuinely higher than the current price. A full-price product always carries `null` there, never a fabricated discount.

#### Why does a pasted product link not include a `description` field?

A pasted product URL fetches its own page in full and returns the real EAN, breadcrumb category, and true stock/condition, plus the spec sheet and image gallery when Fetch full product detail is on, but its own extraction path does not populate `description`. A search or listing result enriched with Fetch full product detail on does include it, since it comes from a different extraction path on the same page. If you need the description for a specific product, run it through search or a listing link instead of pasting its product URL directly.

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

A run that genuinely matches nothing still succeeds with an empty dataset; widen the keyword or relax the filters. A run only fails when every attempted page was refused and nothing could be read at all, so "no products today" is never confused with "nothing could be read". If some pages read fine and only a later page or pasted URL was refused, the run still succeeds and its status message starts with "Partial results:" so a truncated harvest never reads as a complete one. Run it again in a few minutes and leave the default proxy configuration in place.

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

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

### 🔗 Want more electronics data?

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

<table>
<tr><td>🔌 <a href="https://apify.com/abotapi/fnac-com-scraper"><b>Fnac Scraper</b></a><br>Scrape Fnac (fnac.com) products: current price plus strike-through discount, colour/model...</td><td>🔌 <a href="https://apify.com/abotapi/boulanger-com-scraper"><b>Boulanger.com</b></a><br>Scrape Boulanger (boulanger.com) electronics and home-appliance products: current price...</td></tr>
<tr><td>🔌 <a href="https://apify.com/abotapi/dienmayxanh-scraper"><b>Dienmayxanh Scraper</b></a><br>Scrape dienmayxanh.com home appliances and electronics with full specifications, current...</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/currys-co-uk"><b>Currys UK Scraper</b></a><br>Scrape Currys UK electronics by keyword or URL. Extract prices, brands, stock status...</td><td>🔌 <a href="https://apify.com/abotapi/appliancesonline-com-au-scraper"><b>Appliances Online Scraper</b></a><br>Scrape appliancesonline.com.au by category, keyword, or URL. Extract title, brand, AUD...</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/darty-com-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 using darty.com's own search. 'url' scrapes any product or search-result-listing page URL you paste, walking pagination forward automatically.

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

Free-text keyword, e.g. 'television' or 'lave-linge'. Uses darty.com's own product search.

## `minRating` (type: `integer`):

Only return products rated at least this many stars (1-5). Narrows via darty.com's own search facet server-side. 0 or empty = no rating filter. Search mode only: it is written into darty.com's own search URL, so a pasted URL keeps whatever it already carries.

## `freeDeliveryOnly` (type: `boolean`):

Only return products showing free home delivery, via darty.com's own search facet. Search mode only: it is written into darty.com's own search URL, so a pasted URL keeps whatever it already carries.

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

darty.com's own sort order, verified live to reorder the full server-side result set. Search mode only: it is written into darty.com's own search URL, so a pasted URL keeps whatever it already carries.

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

Paste one or more darty.com product pages or search-result-listing pages. Pagination continues forward automatically from any offset already in the URL. Search-mode fields are ignored here. The fields in the Filters section still apply, including to a pasted product URL.

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

Only return products from these brands, e.g. 'Samsung'. Matched against the site's own brand field on every card, client-side, case-insensitive. Leave empty for all brands. Applies in BOTH search mode and URL mode, including a pasted product URL.

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

Only return products priced at or above this amount, in euros. Applies in BOTH search mode and URL mode, including a pasted product URL.

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

Only return products priced at or below this amount, in euros. Applies in BOTH search mode and URL mode, including a pasted product URL.

## `specialsOnly` (type: `boolean`):

Only return products currently showing a genuine strike-through discount against darty.com's own reference price (verified live against real price data -- never a guess). Applies in BOTH search mode and URL mode, including a pasted product URL.

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

Adds full description, EAN, breadcrumb category path, and the complete flattened spec sheet (every characteristic the product page shows, not a fixed list) plus the full image gallery. Current price, was-price/discount, rating and card image are already included without this toggle.

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

Fetch the product's own customer reviews (not a third-party vendor): overall rating, total review count, recommend-percent, per-criteria scores (e.g. ease of use, value for money), and the page's own most recent individual written reviews (rating, title, body, author, dates, purchase store). Products with no reviews simply return an empty list.

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

Cap on written reviews fetched per product when 'Fetch reviews' is on, up to the site's own per-page limit. Values above 100 are capped at 100.

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

Stop after this many result pages per search/URL entry. Leave empty for no page limit -- the run stops at Max products total.

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

Hard cap on total products returned across every search/URL entry. 0 = unlimited (still bounded by Max pages per search).

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

Proxy configuration. Leave the default as provided -- this source needs it. Change only the region if you need a different one.

## `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. 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 products 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`):

Optional. Field names that must NOT make a product count as UPDATED, for example "rating" or "reviews.count" (dotted paths reach nested fields). Ignored fields stay in the output and the saved baseline; they are only left out of the comparison and of changedFields. Leave empty to compare every field.

## `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": "television",
  "minRating": 0,
  "freeDeliveryOnly": false,
  "sortBy": "RELEVANCE",
  "urls": [
    "https://www.darty.com/nav/recherche?text=television",
    "https://www.darty.com/nav/recherche?text=television&o=30",
    "https://www.darty.com/nav/recherche?s=prix_asc&text=television",
    "https://www.darty.com/nav/recherche?text=television&avis=400&free_darty_delivery=true",
    "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/index.html",
    "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/index.html?o=30",
    "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/lg_43qned81b_2026.html"
  ],
  "brands": [],
  "specialsOnly": false,
  "fetchDetails": false,
  "fetchReviews": true,
  "maxReviewsPerProduct": 20,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

No description

## `specs` (type: `string`):

No description

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

No description

## `changes` (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": "television",
    "urls": [
        "https://www.darty.com/nav/recherche?text=television",
        "https://www.darty.com/nav/recherche?text=television&o=30",
        "https://www.darty.com/nav/recherche?s=prix_asc&text=television",
        "https://www.darty.com/nav/recherche?text=television&avis=400&free_darty_delivery=true",
        "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/index.html",
        "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/index.html?o=30",
        "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/lg_43qned81b_2026.html"
    ],
    "brands": [],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "FR"
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/darty-com-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": "television",
    "urls": [
        "https://www.darty.com/nav/recherche?text=television",
        "https://www.darty.com/nav/recherche?text=television&o=30",
        "https://www.darty.com/nav/recherche?s=prix_asc&text=television",
        "https://www.darty.com/nav/recherche?text=television&avis=400&free_darty_delivery=true",
        "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/index.html",
        "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/index.html?o=30",
        "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/lg_43qned81b_2026.html",
    ],
    "brands": [],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "FR",
    },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/darty-com-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": "television",
  "urls": [
    "https://www.darty.com/nav/recherche?text=television",
    "https://www.darty.com/nav/recherche?text=television&o=30",
    "https://www.darty.com/nav/recherche?s=prix_asc&text=television",
    "https://www.darty.com/nav/recherche?text=television&avis=400&free_darty_delivery=true",
    "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/index.html",
    "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/index.html?o=30",
    "https://www.darty.com/nav/achat/hifi_video/televiseurs-led/grand_ecran_led/lg_43qned81b_2026.html"
  ],
  "brands": [],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false
}' |
apify call abotapi/darty-com-scraper --silent --output-dataset

```

## MCP server setup

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