# PcComponentes Scraper - Prices, Discounts, Variants & Reviews (`abotapi/pccomponentes-com-scraper`) Actor

Scrape PcComponentes (pccomponentes.com) products: current price plus strike-through reference-price discount, configuration variants with price and availability, brand, category, and reviews with rating. Search by keyword/category or paste product and listing links.

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

## Pricing

from $1.00 / 1,000 product results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## PcComponentes Scraper: Prices, Discounts, Variants and Reviews

PcComponentes Scraper turns pccomponentes.com into structured product data. Search by keyword or category, or paste product and listing links directly, and get the current price alongside the site's own strike-through reference price and computed discount whenever a product is genuinely marked down, plus the product's own rating from every search or category result. Turn on full detail for configuration variants (RAM, storage, colour) each with its own price and availability, and written reviews. Export to JSON, CSV or Excel, pull the results through the API, or pipe them into the apps you already use.

### Why This Scraper?

- **Was-price and discount, structured, never fabricated.** When a product is marked down against the site's own reference price, both prices are captured plus the computed discount amount and percentage. A full-price product simply carries `null`, nothing is guessed.
- **Real narrowing you can trust.** A single brand and a keyword price range narrow through the site's own catalog navigation or search facets; multiple brands, discount-only, and every URL-mode filter are checked against each product's own values instead of guessed at.
- **Configuration variants.** Laptops, PCs and similar products return every configuration, RAM, storage, colour or model, as its own variant, each with its own price and availability.
- **Reviews straight from the product page.** Overall rating, rating count, and the product's own most recent written reviews (author, date, rating, body), reported directly by the site, not a separate review service.
- **Two ways in.** Keyword or category search with real site filters (brand, price range, discount-only, sort), or paste any product or listing link and continue pagination automatically.
- **Optional export to your apps.** Send results into Notion, Linear, Airtable, or any Apify MCP connector alongside the dataset.
- **Keeps going when a connection is refused.** Each request gets several attempts on a different connection before giving up, and a sustained block stops retries for the rest of the run instead of grinding on uselessly, while whatever was already collected is kept.

### Use Cases

- **Price trackers and deal aggregators:** monitor current price against the site's own reference price on the products you care about, and only surface genuine discounts.
- **Retailers and resellers:** benchmark competitor pricing and stock across a whole category or a shortlist of brands.
- **Comparison shopping tools:** pull configuration variants (RAM, storage, colour) with their own price and availability, not just the base model.
- **Market researchers:** collect ratings and written reviews to gauge sentiment on specific product lines.
- **Developers:** feed a downstream app or bot with a live feed of category listings through the API.

### Data You Get

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

| Field | Example |
| --- | --- |
| `productId` / `sku` | `"884201"` / `"VNX3-14R7-32-1TB"` |
| `name` | `"UltraNote X3 14in Gaming Laptop, Ryzen 7, 32GB, 1TB SSD"` |
| `brand` | `"Vantrix"` |
| `category` | `"Portátiles"` |
| `url` | `"https://www.pccomponentes.com/ultranote-x3-14-ryzen7-32gb-1tb-ssd"` |
| `price` / `currency` | `799.99` / `"EUR"` |
| `originalPrice` / `discountAmount` / `discountPercent` | `999.99` / `200.00` / `20.0` |
| `isOnSpecial` | `true` |
| `onlineAvailable` | `true` |
| `freeShipping` | `true` |
| `image` / `images` | `"https://thumb.pccomponentes.com/sample/ultranote.jpg"` / `["https://thumb.pccomponentes.com/sample/ultranote-1.jpg"]` |
| `description` | full product description text (only when Fetch full product detail is on) |
| `ean` / `reference` | `"8410000000019"` / `"VNX3REF001"` |
| `conditionType` | `"new"` (`"refurbished"` for a refurbished offer); on every row |
| `condition` / `ratingRecommendPercent` | `"new"` / `92` (`condition` is the site's own grade, such as `"reaconditioned-a"` for a refurbished product, filled from the product page: always for pasted product links, and for search and category results only with Fetch full product detail; `ratingRecommendPercent` needs Fetch full product detail) |
| `articleId` / `objectId` | `"884201"` / `"884201#new"` (`#reac` for a refurbished offer) |
| `priceOld` / `discount` | same values as `originalPrice` / `discountPercent`, for consumers of other PcComponentes datasets |
| `availability` / `seller` / `mpn` | `"IN_STOCK"` (or `"OUT_OF_STOCK"`; empty when the site gives no stock signal for the product, as for most refurbished listings) / `"PcComponentes"` / `"VNX3-14R7"` |
| `availabilityLocations` | `["MURCIA"]` (warehouse or store names the site lists for the product, when it lists any) |
| `specs` | `{"Memoria Ram": "32GB RAM", "Almacenamiento SSD": "1 TB SSD"}` (the site's key specs; keyword search rows) |
| `query` / `scraped_at` | the keyword, category path or URL that produced the row / ISO timestamp |
| `variants` | `[{"axis": "Memoria Ram", "name": "64 GB RAM", "url": "https://www.pccomponentes.com/ultranote-x3-64gb", "price": 899.99, "available": true}]` |
| `rating` / `reviewCount` | `4.6` / `342` |
| `reviews.averageRating` / `reviews.ratingCount` / `reviews.totalReviewCount` | `4.6` / `342` / `58` |
| `reviews.items[]` | `[{"rating": 5.0, "body": "Sample review text describing the product.", "author": "Sample Customer", "date": "2026-03-11"}]` |

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

Detail fields (`description`, `ean`, `reference`, `images` beyond the single card image, `variants`, `ratingRecommendPercent`) appear only when Fetch full product detail is on, and are left out of the record entirely, not set to `null`, when the site has no value for them. `reviews` is always present: an empty shape when Fetch reviews is off, the full averageRating/counts/items shape when it's on. `rating` and `reviewCount` come with every search or category listing result regardless of either toggle; for a pasted single product URL, they are only populated when Fetch reviews is on. `reviews.ratingCount` counts every star rating the product has ever received, while `reviews.totalReviewCount` counts only the ratings that came with written text, a narrower, genuinely different number reported directly by the site.

### How to Use

1. Pick a **mode**: `search` (keyword and/or category) or `url` (paste product or listing links).
2. Fill in the filters you want (brand, price range, discount-only, sort), and switch on full detail or reviews if you need them.
3. Set **Max products total** to control run size and cost, then click **Start**.
4. Download the dataset as JSON, CSV or Excel, or read it through the API.

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

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

**Category browse, filtered to a brand, discounted items only, sorted by price:**

```json
{
  "mode": "search",
  "category": "portatiles",
  "brands": ["Lenovo"],
  "specialsOnly": true,
  "sortBy": "PRICE_ASC",
  "maxItems": 50,
  "maxPages": 5
}
```

**Full product detail (variants and description) and reviews for a pasted product link:**

```json
{
  "mode": "url",
  "urls": ["https://www.pccomponentes.com/portatil-alurin-flex-advance-amd-ryzen-5-7430-15-6-16-gb-512gb-windows-11-home"],
  "fetchDetails": true,
  "fetchReviews": true
}
```

**Paste a category listing and keep paginating forward:**

```json
{
  "mode": "url",
  "urls": ["https://www.pccomponentes.com/categorias/monitores"],
  "maxItems": 100,
  "maxPages": 10
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

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

#### URL shapes

URL mode with the `urls` field left untouched scrapes one example per shape below (the field's default), so a bare `"mode": "url"` run returns products from all three.

| Shape | Example |
|---|---|
| Category listing | `https://www.pccomponentes.com/categorias/portatiles` |
| Category listing, sorted (`?sort=price_asc`, `price_desc`, `discount`, `top_rated`, `activation_date`) | `https://www.pccomponentes.com/categorias/portatiles?sort=price_asc` |
| Keyword search | `https://www.pccomponentes.com/buscar/?query=portatil` |
| Paginated category (continues forward from the page given) | `https://www.pccomponentes.com/categorias/portatiles?page=2` |
| Older category link without `/categorias/` | `https://www.pccomponentes.com/portatiles` |
| Single product page | `https://www.pccomponentes.com/ultranote-x3-14-ryzen7-32gb-1tb-ssd` |

A link in any other shape is skipped with a warning in the run log naming that link, never silently.

#### Multiple URLs and page walking

In URL mode, **Max products total** is split evenly across the URLs you paste, so a short category doesn't hand its unused share to the next one. A client-side filter (multiple brands, discount-only, a price range in URL mode) can walk many pages looking for matches; the walk still stops at an internal safety cap of 200 pages even with Max pages per entry left empty.

#### Dataset views

The dataset has five ready-made views: **Products** (overview), **Product details**, **Variants** (one row per configuration), **Reviews** (one row per written review) and **Changes since the last run** (incremental mode), plus a **Run summary** record in the key-value store (`OUTPUT`). The default dataset items are unchanged by the views.

#### Detail enrichment billing

Each returned product is one **Product result** charge, and the run start is one **Actor start** charge. The `detail-enrichment` event is a separate, per-row charge, applied right after that product is saved to the dataset. A returned full row carries it when its product page loaded and:

- **Fetch reviews** is on: always, including when the product has no written reviews (the row carries an empty reviews list); or
- **Fetch full product detail** is on and the page yielded its detail fields.

It is not charged when the product page could not be loaded (the row still comes back with its listing-card data and only the Product result charge), when both toggles are off, or on **Compact update rows**. A pasted product link always reads the product page to build its row, but the enrichment charge still follows the two conditions above. Products that were not delivered are never charged. The Pricing tab shows the current rates.

#### Incremental changes and resume

For a schedule that watches the same search, turn on **Incremental changes for scheduled runs**. The first run returns every matching product as `NEW`; later runs return only `NEW`, `UPDATED` and `REAPPEARED` products, each with `changeType`, `changedFields`, `firstSeenAt` and `lastSeenAt`. Unchanged products are not returned and not billed. State is kept per search, filter and detail setup (or per **State key** you choose); caps such as Max products, sort order and the review limit never start a new baseline.

- **What counts as a change.** By default any change to the product record returns `UPDATED` (price, reference price, discount, availability, name, rating, rating count, variants, details). The review texts, image addresses, the search label (`query`) and `scraped_at` never do; a new review still shows through `reviewCount` and `rating`. **Price and availability only** limits changes to price, reference price, discount, on-sale flag and availability, including each variant's price and availability. **Ignore fields when detecting changes** adds your own field names or dotted paths such as `variants.name`; they stay in the row.
- **Compact update rows.** With Price and availability only, **Compact update rows** turns `UPDATED` and `EXPIRED` rows into short diffs (`priceChanges`, `variantChanges` with old and new values). `NEW` rows stay complete. Compact rows carry no details or reviews, so the detail and review enrichment is not charged for them.
- **Expired products.** **Emit expired products** returns products that earlier runs found but the tracked listing no longer shows, marked `EXPIRED`. It means the listing dropped them, not that they are out of stock; use the availability fields for stock. It is only produced after a run read the whole listing: never when Max products, Max pages or a failed page cut the run short, when a pasted link starts at page 2 or later, or when Resume was used. **Expire after N missed full scans** waits for that many complete scans in a row.
- **Billing.** Only returned rows are billed. `UNCHANGED` rows are suppressed (and not billed) unless **Emit unchanged products** is on; `EXPIRED` rows are returned, and billed, only with **Emit expired products**. The detail-and-review enrichment event is charged per returned full row, after the row is saved, exactly as described above. When details are off, an unchanged product's product page is not even fetched.
- **Example search.** A search-mode run with no keyword, no More search keywords and no Category searches the example keyword and never reads or saves state, so it cannot change or expire a baseline. It is billed like any run: only the rows it delivers, exactly as described in Detail enrichment billing.
- **Resume.** **Resume from a previous run** takes a run ID or dataset ID and skips the products that run already returned, so an interrupted pull continues without returning or billing them twice.

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

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

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

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

Leave the field empty to skip; it never changes the dataset output.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` (keyword and/or category) or `url` (paste product or listing links). |
| `searchTerm` | string | (none; prefill `"portatil"`) | Keyword for the site's own product search. Leave empty to browse Category instead. If search mode gets no keyword, no More search keywords and no Category, the run searches the example keyword `portatil` instead of returning nothing; it is billed like any run (rows delivered), and with Incremental mode on it neither reads nor saves state. |
| `queries` | array | (none) | More keywords for the same run, searched in order together with Search keyword. Max products total caps the whole run and a product matched twice is returned once. |
| `category` | string | (none) | A real pccomponentes.com category path, e.g. `portatiles`, `monitores`, `placas-base`. Ignored whenever Search keyword is set. |
| `brands` | array | (none; prefill `[]`) | Exact brand names to keep, e.g. `Lenovo`, `HP`. Applies in both search and URL mode. |
| `minPrice` | number | (none) | Only return products priced at or above this amount, in euros. Applies in both search and URL mode. |
| `maxPrice` | number | (none) | Only return products priced at or below this amount, in euros. Applies in both search and URL mode. |
| `specialsOnly` | boolean | `false` | Keep only products currently showing a genuine discount against the site's own reference price. Applies in both search and URL mode. |
| `sortBy` | string | `RELEVANCE` | `RELEVANCE`, `PRICE_ASC`, `PRICE_DESC`, `DISCOUNT`, `TOP_RATED`, or `NEWEST`. Category browsing uses the site's own sort. The site's keyword search has no sort option, so keyword results (up to Max pages per search) are collected and sorted by the actor before the first Max products total are returned; this reads every page up to the limit. In URL mode this is only a fallback: a pasted category URL's own sort wins when present. |
| `urls` | array | one category, one sorted category and one keyword-search link | Product, category listing or keyword-search pages to scrape (URL mode only). Pagination continues forward automatically from any `?page=` already in the URL. An empty list stops the run with an input message. |
| `fetchDetails` | boolean | `false` | Adds full description, reference/EAN, category name, image gallery, and every configuration variant. A pasted single product URL always loads its product page for price, stock and discount either way; description, EAN, gallery and variants still need this toggle on. |
| `fetchReviews` | boolean | `true` | Fetches the product's most recent written reviews (`rating` and `reviewCount` already come with every search or category result regardless of this toggle; for a pasted product URL they need this toggle on). On by default, so most runs fetch this for every returned product unless it is turned off. |
| `maxReviewsPerProduct` | integer | `20` | Cap on written reviews returned per product when Fetch reviews is on. `0` = all reviews the page shows (up to roughly 15). Accepts up to 1000; the site itself shows only about 15 per product. |
| `maxPages` | integer | (none) | Stop after this many result pages per search/category/URL entry. Leave empty for no explicit limit; the run still stops at Max products total, or at the internal hard cap of 200 pages per entry. |
| `maxItems` | integer | `20` | Hard cap on total products returned across every search/category/URL entry. `0` = unlimited, still bounded by the 200-page hard cap per entry. |
| `proxy` | object | `{"useApifyProxy": true}` | Connection settings. Choose the residential group or your own proxy URLs for the most reliable runs; see Plan Requirement. |
| `resumeFromRunId` | string | (none) | Run ID or dataset ID of an earlier run; its products are skipped and not billed again. |
| `incrementalMode` | boolean | `false` | Return only NEW, UPDATED and REAPPEARED products on later runs of the same search. |
| `stateKey` | string | (auto) | Name a monitoring campaign to keep or share its state; empty derives it from the search, filters and detail settings. With Incremental mode on and your own State key, search mode needs a keyword, More search keywords or a Category: with none, the run stops with an input message and collects nothing. |
| `emitUnchanged` | boolean | `false` | Also return UNCHANGED products (returned and billed). |
| `emitExpired` | boolean | `false` | Also return EXPIRED products after a run that read the whole listing (returned and billed). |
| `changeScope` | string | `all` | `all` or `priceAndStock` (only price, reference price, discount and availability decide UPDATED). |
| `compactUpdates` | boolean | `false` | With `priceAndStock`, UPDATED and EXPIRED rows are short diffs. |
| `expireAfterMissedScans` | integer | `1` | Complete scans a product must be missing from, in a row, before it is EXPIRED. |
| `ignoreFieldsForChanges` | array | (none) | Fields whose changes alone never return an UPDATED row (dotted paths allowed). |
| `mcpConnectors` | array | (none) | Optional: 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 | `50` | Cap on items exported to each connector per run. Does not affect the dataset. |

### Output Example

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

```json
{
  "productId": "884201",
  "sku": "VNX3-14R7-32-1TB",
  "name": "UltraNote X3 14in Gaming Laptop, Ryzen 7, 32GB, 1TB SSD",
  "brand": "Vantrix",
  "category": "Portátiles",
  "articleId": "884201",
  "objectId": "884201#new",
  "conditionType": "new",
  "availability": "IN_STOCK",
  "availabilityLocations": ["MURCIA"],
  "seller": "PcComponentes",
  "mpn": "VNX3-14R7",
  "specs": { "Memoria Ram": "32GB RAM", "Almacenamiento SSD": "1 TB SSD" },
  "priceOld": 999.99,
  "discount": 20.0,
  "query": "portatil",
  "scraped_at": "2026-11-03T08:00:00Z",
  "url": "https://www.pccomponentes.com/ultranote-x3-14-ryzen7-32gb-1tb-ssd",
  "price": 799.99,
  "currency": "EUR",
  "originalPrice": 999.99,
  "discountAmount": 200.00,
  "discountPercent": 20.0,
  "isOnSpecial": true,
  "onlineAvailable": true,
  "freeShipping": true,
  "image": "https://thumb.pccomponentes.com/sample/ultranote.jpg",
  "images": ["https://thumb.pccomponentes.com/sample/ultranote-1.jpg"],
  "description": "Sample product description as shown on the site.",
  "ean": "8410000000019",
  "reference": "VNX3REF001",
  "condition": "new",
  "ratingRecommendPercent": 92,
  "variants": [
    { "axis": "Memoria Ram", "name": "64 GB RAM", "url": "https://www.pccomponentes.com/ultranote-x3-64gb", "price": 899.99, "available": true }
  ],
  "rating": 4.6,
  "reviewCount": 342,
  "reviews": {
    "averageRating": 4.6,
    "ratingCount": 342,
    "totalReviewCount": 58,
    "items": [
      { "rating": 5.0, "body": "Sample review text describing the product.", "author": "Sample Customer", "date": "2026-03-11" }
    ]
  }
}
```

### Plan Requirement

pccomponentes.com sits behind a managed bot challenge ("Just a moment..."). Apify datacenter connections are refused by it, and Spanish residential connections are served only intermittently, so a run can return fewer products than requested. A paid Apify plan is required: free plans do not include residential proxies, and this site needs them. The best results come from choosing a residential connection under **Proxy & connection** (or supplying your own proxy URLs); the default connection works on a best-effort basis only.

Each request is retried on a different connection, and the run falls back through a backup connection when the selected one is unavailable. The run log tells you what happened:

- Warning (selected connection unavailable): "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."
- Warning (served on backup): "Served over the backup connection (the default connection was unavailable)."
- Error (proxy refused for the account): "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."
- Error (residential unavailable, backup also failed): "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 PcComponentes pages."
- Error (requests failed): "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."

Whatever was collected before a sustained block is kept. Schedule a retry if a run ends with the connection errors above.

### FAQ

#### How much does it cost?

You pay per product returned, plus a `detail-enrichment` charge, once per product and applied right after that product is saved to the dataset (so a stopped run only pays for rows already delivered), on any returned full product whose page was loaded for full detail and/or reviews (see Detail enrichment billing for the exact conditions), and a run-start fee. Because Fetch reviews is on by default, that enrichment charge applies to most returned products unless you turn Fetch reviews off. The **Pricing** tab shows the current rates. Use **Max products total** to cap the cost of any run.

#### Is it legal to scrape PcComponentes?

This actor collects only publicly available product data. You are responsible for how you use it: follow pccomponentes.com's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Product descriptions, images and reviews may be subject to third-party rights.

#### Why did I get charged for reviews on a product with no written reviews?

With Fetch reviews on, the enrichment charge fires once the product's page has loaded, whether or not that page actually had any written reviews to return; the record still carries an empty reviews list. A product whose page could not be loaded is not charged for enrichment. Turn off Fetch reviews (and leave Fetch full product detail off) if you only need the current price and card-level fields.

#### Can I track price drops on a schedule?

Yes, schedule the actor from the **Schedules** tab with the filters you want, for example Discounted items only. Turn on Incremental changes for scheduled runs to receive only new and price-changed products (see Incremental changes and resume above); with it off, each run returns the current matching products from scratch.

#### Why did my run finish with zero products instead of failing?

An empty dataset can mean nothing matched your filters, or the site refused the connection throughout the run. Check the run log for a "did not load" or "stopping retries" line to tell the two apart, then run it again in a few minutes if it was a connection problem.

#### 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/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/darty-com-scraper"><b>Darty Scraper</b></a><br>Scrape Darty (darty.com) products: current price plus strike-through reference price and...</td><td>🛒 <a href="https://apify.com/abotapi/druni-es-scraper"><b>druni.es</b></a><br>Scrape Druni beauty, cosmetics and perfume products. Search by keyword, category, Ofertas...</td></tr>
<tr><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><td>🛒 <a href="https://apify.com/abotapi/dm-de-scraper"><b>dm.de</b></a><br>Scrape dm-drogerie markt (dm.de) products: current + strike-through Ausverkauf price with...</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/pccomponentes-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 and/or a real pccomponentes.com category (e.g. 'portatiles', 'placas-base'), with real site filters and sort. 'url' scrapes any product or category listing page URL you paste, walking pagination forward automatically.

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

Free-text keyword, e.g. 'portatil gaming' or 'monitor 27 pulgadas'. Uses the site's own product search. Leave empty and use Category below to browse a category instead. With no keyword, no More search keywords and no Category, a search-mode run searches the example keyword portatil instead of returning nothing.

## `queries` (type: `array`):

Several keywords in one run, e.g. 'portatil', 'monitor 27', 'tarjeta grafica'. Each is searched with the site's own product search, in order, together with Search keyword above. Max products total caps the whole run; a product matched by two keywords is returned once.

## `category` (type: `string`):

A real pccomponentes.com category path exactly as it appears in the site's own URLs, e.g. 'portatiles', 'monitores', 'placas-base'. Ignored when Search keyword is set (keyword search and category browsing are two different site features).

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

Only return products from these brands, e.g. 'Lenovo', 'HP', 'Asus'. Match the exact brand name as shown on the site. Leave empty for all brands.

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

Only return products priced at or above this amount, in euros.

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

Only return products priced at or below this amount, in euros.

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

Only return products currently showing a genuine strike-through discount against the site's own reference price (verified live against real price data -- never a guess). Combines with the keyword/category above.

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

Sort order. Category browsing uses the site's own server-side sort. The site's keyword search has no sort option, so for a keyword search the matching products (up to Max pages per search) are collected first and sorted by this actor before the first Max products total are returned; Relevance keeps the site's own ranking. In URL mode this input is only a fallback: a pasted category URL's own sort parameter, if present, always wins.

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

Paste one or more pccomponentes.com product pages, category listing pages (/categorias/<slug>, optionally with ?sort= or ?page=) or keyword search links (/buscar/?query=). Pagination continues forward automatically from any ?page= already in the URL. Filter fields above are ignored in this mode. An empty list stops the run with an input message.

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

Adds full description, EAN/reference, category breadcrumb, complete image gallery, and every configuration variant (each with its own price and availability) from the product page. Current price, was-price/discount, rating and card image are already included without this toggle. Billing: a row whose product page loaded and yielded these details carries one detail-and-review enrichment charge (also charged for Fetch reviews, never twice per product).

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

Fetch the product's own reviews (not a third-party vendor): overall rating, total rating count, and the page's most recent individual written reviews (rating, body, author, date) -- pccomponentes.com itself only ever surfaces up to its 15 most recent written reviews per product; the rating and counts reflect the full history. Products with no reviews simply return an empty list. Billing: when on, each returned full row whose product page loaded carries one detail-and-review enrichment charge, including a product with no written reviews; a page that could not be loaded is not charged.

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

Cap on written reviews fetched per product when 'Fetch reviews' is on, up to the site's own per-page limit.

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

Stop after this many result pages per search/category/URL entry. Leave empty for no explicit limit: the run stops at Max products total or at an internal hard cap of 200 pages per entry.

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

Hard cap on total products returned across every search/category/URL entry. 0 = unlimited (still bounded by the internal 200-page hard cap per entry).

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

This site challenges ordinary datacenter connections; residential connections are served more reliably. If the selected connection is refused, the actor continues on a backup connection when one is available.

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

Paste a previous run ID or dataset ID to continue a large pull without returning or charging for products already collected there. Use this after an interrupted 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 every matching product as NEW. Later runs return only NEW, UPDATED and REAPPEARED products. By default any change to the product record counts as UPDATED (price, reference price, discount, availability, name, rating, rating count, variants, details), while the review texts, the image addresses and the scrape time never do; choose Price and availability only below to react to price and stock moves alone. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately for each search, filter and detail setup; use State key 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 search, filters and detail settings, so different searches never mix state with each other. With Incremental changes on and your own State key, search mode needs a keyword, More search keywords or a Category; otherwise the run stops with an input message.

## `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 want the full snapshot every run.

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

Off by default. Turn on to also return products that were found in earlier runs but are no longer in the tracked listing, marked EXPIRED. This means the listing no longer shows them, not that they are out of stock or delisted; use the availability fields for stock. Only produced once a run has read the whole tracked listing, so never when Max products, Max pages or a failed page cut it short, when a pasted link starts at page 2 or later, or when Resume was used. This returns, and bills, extra rows, so leave it off unless you need expiry tracking.

## `changeScope` (type: `string`):

All fields (default): any change to the product record, except the always-ignored review texts, image addresses and scrape time, returns an UPDATED row. Price and availability only: only price, reference price, discount, on-sale flag and availability changes (including each variant's price and availability) return an UPDATED row; changes to names, ratings, descriptions, images or other details never do.

## `compactUpdates` (type: `boolean`):

Off by default. Works with Price and availability only. When on, UPDATED and EXPIRED rows are short: product id, url, name, current price and availability, plus priceChanges and variantChanges showing the old and new value of each moved field. NEW rows always carry the complete product record. Compact rows carry no details or reviews, so the detail and review enrichment is not billed for them.

## `expireAfterMissedScans` (type: `integer`):

Only used with Emit expired products. A product is marked EXPIRED only after it has been missing from this many complete scans in a row (default 1). Raise it (for example 3) so a product that briefly drops out of a listing is not reported as gone. A product that comes back resets the count.

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

Incremental mode only. Fields whose changes do not count as an update: a change in them alone leaves the product UNCHANGED and they are not listed in changedFields. They are still returned in every row. Use a dotted path for a nested field, for example variants.name. The review texts, the image fields (image, images), the search label (query) and the scrape time (scraped_at) are always ignored; a new review still shows through reviewCount and rating. Add more field names here to ignore them as well, for example rating.

## `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": "portatil",
  "brands": [],
  "specialsOnly": false,
  "sortBy": "RELEVANCE",
  "urls": [
    "https://www.pccomponentes.com/categorias/portatiles",
    "https://www.pccomponentes.com/categorias/portatiles?sort=price_asc",
    "https://www.pccomponentes.com/buscar/?query=portatil",
    "https://www.pccomponentes.com/placas-base/asus",
    "https://www.pccomponentes.com/portatil-apple-macbook-air-13-apple-m5-16-gb-512gb-ssd-gpu-8-nucleos-macos-blanco-estrella"
  ],
  "fetchDetails": false,
  "fetchReviews": true,
  "maxReviewsPerProduct": 20,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "changeScope": "all",
  "compactUpdates": false,
  "expireAfterMissedScans": 1,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

No description

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

No description

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

No description

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

No description

## `runSummary` (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": "portatil",
    "brands": [],
    "urls": [
        "https://www.pccomponentes.com/categorias/portatiles",
        "https://www.pccomponentes.com/categorias/portatiles?sort=price_asc",
        "https://www.pccomponentes.com/buscar/?query=portatil",
        "https://www.pccomponentes.com/placas-base/asus",
        "https://www.pccomponentes.com/portatil-apple-macbook-air-13-apple-m5-16-gb-512gb-ssd-gpu-8-nucleos-macos-blanco-estrella"
    ],
    "proxy": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "changeScope": "all",
    "compactUpdates": false,
    "expireAfterMissedScans": 1,
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/pccomponentes-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": "portatil",
    "brands": [],
    "urls": [
        "https://www.pccomponentes.com/categorias/portatiles",
        "https://www.pccomponentes.com/categorias/portatiles?sort=price_asc",
        "https://www.pccomponentes.com/buscar/?query=portatil",
        "https://www.pccomponentes.com/placas-base/asus",
        "https://www.pccomponentes.com/portatil-apple-macbook-air-13-apple-m5-16-gb-512gb-ssd-gpu-8-nucleos-macos-blanco-estrella",
    ],
    "proxy": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "changeScope": "all",
    "compactUpdates": False,
    "expireAfterMissedScans": 1,
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/pccomponentes-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": "portatil",
  "brands": [],
  "urls": [
    "https://www.pccomponentes.com/categorias/portatiles",
    "https://www.pccomponentes.com/categorias/portatiles?sort=price_asc",
    "https://www.pccomponentes.com/buscar/?query=portatil",
    "https://www.pccomponentes.com/placas-base/asus",
    "https://www.pccomponentes.com/portatil-apple-macbook-air-13-apple-m5-16-gb-512gb-ssd-gpu-8-nucleos-macos-blanco-estrella"
  ],
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "changeScope": "all",
  "compactUpdates": false,
  "expireAfterMissedScans": 1,
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/pccomponentes-com-scraper --silent --output-dataset

```

## MCP server setup

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