# Idealo Price Comparison Scraper (`scrapyx/idealo-price-comparison-scraper`) Actor

Per-merchant price comparison from Idealo: every shop's item price and total including shipping for a product, plus Idealo's own aggregate low/high range, brand and offer count. Browse by category or by product ID.

- **URL**: https://apify.com/scrapyx/idealo-price-comparison-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.05 / 1,000 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

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

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Idealo Price Comparison Scraper

Per-merchant price comparison from **Idealo**, Germany's largest price
comparison site — every shop's item price *and* the total including shipping
for a product, plus Idealo's own aggregate low/high range, brand and offer
count.

HTTP only, no browser, no login.

### Input

```json
{ "mode": "products", "productIds": ["201146263"], "includeOffers": true }
```

Or browse a category and read each product's offers:

```json
{ "mode": "category", "categoryIds": ["16073"],
  "maxProductsPerCategory": 10 }
```

Both fields also accept full Idealo URLs.

### What you get

| `recordType` | One per | Carries |
| --- | --- | --- |
| `QUERY_SUMMARY` | input | products found vs returned, offers returned, why it stopped |
| `PRODUCT` | product | name, brand, images, canonical URL, and Idealo's aggregate `lowPrice`/`highPrice`/`offerCount`/availability |
| `OFFER` | merchant offer | shop, item price, **total including shipping**, derived shipping cost, offer link |
| `ERROR` | failed input | why |

```jsonc
{
  "recordType": "OFFER",
  "productId": "201146263",
  "shopName": "computeruniverse.net",
  "currency": "EUR",
  "price": 379.0,
  "totalPrice": 379.0,
  "shippingCost": 0.0,
  "isFreeShipping": true
}
```

### Known limits — read these before you rely on the output

**There is no keyword search, deliberately.** Idealo's `robots.txt`
disallows `MainSearchProductCategory.html` — its search endpoint. The
category and offers pages are allowed, so this actor works the way that
surface does: browse a category for product IDs, then read each product's
offers. A search URL passed as input is refused with an explanation rather
than fetched.

**`totalPrice` is the number that matters, and it is not the item price.**
Idealo shows both, and they differ — one offer in testing listed an item
price of €399.00 against a total of €407.99. The total lives in the shipping
block ("407,99 € inkl. Versand"), *not* in the "best total price" element,
which Idealo renders only on the single cheapest offer. `shippingCost` is
derived from the two and left `null` unless both are known — Idealo never
states the delivery charge on its own, so it is never assumed to be zero.

**Prices are German-formatted and are converted explicitly.** `1.142,00 €`
uses `.` for thousands and `,` for decimals, the reverse of English. Parsing
that with an English-locale cleaner turns a €1,142 graphics card into €1.14,
so the separators are swapped deliberately rather than stripped.

**A category run costs one request per product.** The category page lists
about 50 products and is a single request, but every product whose offers you
want is another page fetch. `maxProductsPerCategory` is the real cost control.

**`lowPrice`/`highPrice`/`offerCount` are Idealo's own aggregate**, taken
from its Schema.org data — not recomputed from the offers on the page. They
can legitimately exceed what you see: a product showing 20 offer rows
reported `offerCount: 38`, because the page paginates its merchant list. The
two are kept side by side so you can compare them rather than being silently
reconciled.

**Offers are the live board at fetch time.** Merchant prices on a comparison
site change through the day; treat a row as a timestamped observation, which
is what `_scrapedAt` is for.

### Technical

Category pages are plain HTML with no JSON-LD and no hydration blob — product
IDs come from the `/preisvergleich/OffersOfProduct/<id>` links they render.
Offers pages carry Schema.org `Product` / `ProductGroup` JSON-LD for the
product record, with the per-merchant rows in markup under semantic
BEM-style classes.

No WAF: 5/5 TLS profiles returned 200.

`robots.txt` was checked at **path** level on every URL shape this actor
touches. Full recon trail is in `CRAWLING_METHOD.md`.

# Actor input Schema

## `mode` (type: `string`):

'products' reads each product's offers page directly. 'category' browses a category to enumerate product IDs and then reads each one's offers. There is no keyword search: Idealo's robots.txt disallows its search endpoint, and a search URL is refused with an explanation.

## `productIds` (type: `array`):

Idealo numeric product IDs (e.g. 201146263) or full /preisvergleich/OffersOfProduct/… URLs.

## `categoryIds` (type: `array`):

Idealo numeric category IDs (e.g. 16073) or full /preisvergleich/ProductCategory/… URLs. Used by the 'category' mode.

## `includeOffers` (type: `boolean`):

Fetch the individual merchant offers for each product (shop, item price, total including shipping). Turn off for a product-level run that returns only Idealo's own aggregate price range and offer count.

## `maxProductsPerCategory` (type: `integer`):

How many products to read from each category page. A category page lists about 50 products; every one read costs an extra request for its offers page, so this is the main cost control.

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

Optional cap on total rows (products plus offers) across the whole run.

## `maxConcurrency` (type: `integer`):

How many requests may be in flight at once. Kept low by default — a category run makes one request per product on top of the category page.

## `minRequestInterval` (type: `number`):

The honest speed control: the shortest gap between two request starts. No WAF was observed; this is routine politeness.

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

Residential with no country pin is the cloud default. Idealo.de is the German storefront and prices are EUR, so the proxy country does not change your data.

## Actor input object example

```json
{
  "mode": "products",
  "productIds": [
    "201146263"
  ],
  "categoryIds": [],
  "includeOffers": true,
  "maxProductsPerCategory": 10,
  "maxConcurrency": 2,
  "minRequestInterval": 1.2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/idealo-price-comparison-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/idealo-price-comparison-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 '{}' |
apify call scrapyx/idealo-price-comparison-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/idealo-price-comparison-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/kb1sdod2g4hPoCMPF/builds/kybKcs5feoE6HrU0U/openapi.json
