# MediaMarkt Germany Scraper - Products, Prices, Specs & Reviews (`abotapi/mediamarkt-de-scraper`) Actor

Scrape MediaMarkt.de products by keyword or URL. Extract current and original prices, discounts, brands, EANs, category paths, availability, images, full specifications, marketplace seller offers, ratings, and customer reviews.

- **URL**: https://apify.com/abotapi/mediamarkt-de-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Automation, Developer tools, E-commerce
- **Features:** Limited permissions
- **Stats:** 12 total users, 5 monthly users, 98.5% 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

## MediaMarkt.de Scraper: Prices, Discounts, Specs & Reviews

MediaMarkt.de Scraper turns MediaMarkt Germany into structured product data. Search by keyword or category id with the site's own brand, price range and native sort, or paste product, category or search listing links directly. Every record carries the current price, and when a product genuinely carries a reduced original price, the struck through price plus the site's own discount amount and percentage. Switch on full spec sheets, delivery and pickup detail, and customer reviews when you need them, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

### Why This Scraper?

- **Was price and discount, gated on the site's own signal, never guessed.** `originalPrice` is filled in whenever the site shows a strike price, and is `null` otherwise. `isOnSpecial` is true only when the site actually strikes the price through, so a product can carry `originalPrice` without `isOnSpecial`.
- **Real customer reviews.** Average rating, total review count, and each product's most recent reviews with rating, title, full text, date and a verified purchaser flag.
- **Full spec sheet on demand.** The flattened characteristics MediaMarkt itself shows per product, memory and processor for a notebook, panel type for a TV, and so on, never hardcoded to one category's fields.
- **Marketplace aware.** Distinguishes MediaMarkt's own retail offers from third party marketplace sellers, including seller name and rating when a listing is a marketplace offer.
- **Real site filters, plus one of our own.** Brand, price range and MediaMarkt's own sort order (price, rating, topseller, newest, availability) go straight to the site's own query parameters. Minimum rating has no equivalent site filter, so it is applied locally after each page loads, which can mean more pages are walked to fill the result.
- **Two ways in.** Keyword or category id search, or paste any product, category or listing link and continue pagination automatically.
- **Resume without paying twice.** Continue an interrupted run, or skip products already collected by a previous run you name.

### Use Cases

- **Price trackers and deal alerts:** monitor current price, original price and discount percentage, and use `strikePriceType` to tell RRP-style reference prices from real price drops.
- **E-commerce market research:** compare pricing, brands and specs across categories in the German electronics market.
- **Review and sentiment analysis:** collect ratings and full review text to gauge customer opinion on specific products.
- **Marketplace intelligence:** track which listings are sold by MediaMarkt directly versus third party marketplace sellers.
- **Catalog and comparison feeds:** build a structured product feed with specs, images and availability for a comparison site or app.

### Data You Get

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

| Field | Example |
| --- | --- |
| `productId` / `sku` | `3141592` |
| `ean` | `4012345678905` |
| `name` | `"UltraView Pro 15 Notebook"` |
| `brand` | `"Voltek"` |
| `category` / `categoryPath` | `"15 Zoll Notebooks"`, `["Computer & Zubehör", "Notebooks & Laptops", "15 Zoll Notebooks"]` |
| `url` | `"https://www.mediamarkt.de/de/product/_p-3141592.html"` |
| `price` / `currency` | `899`, `"EUR"` |
| `originalPrice` / `discountAmount` | `1299`, `400` |
| `discountPercent` / `isOnSpecial` | `31`, `true` |
| `strikePriceType` | `"RRP"` |
| `onlineAvailable` / `availabilityStatus` | `true`, `"ONLINE"` |
| `isMarketplace` / `marketplaceSeller` | `true`, `{"sellerId": "SEL-88421", "sellerName": "Nordwind Elektronik GmbH", "sellerRating": 4.6}` |
| `shippingCost` / `installment` | `0`, `null` |
| `image` / `images` | `["https://assets.mmsrg.com/isr/sample/ASSET_PLACEHOLDER"]` |
| `rating` / `reviewCount` | `4.2`, `86` |
| `specs` | `{"Bildschirmdiagonale": "15,6 Zoll", "Arbeitsspeicher (RAM)": "16 GB"}` (flattened, varies per category, when Fetch full product detail is on) |
| `delivery` / `pickup` | `{"status": "AVAILABLE", "earliestDate": "2026-10-02"}`, `{"status": "AVAILABLE", "isPickable": true}` (when Fetch full product detail is on) |
| `energyEfficiencyClass` / `energyLabel` | `"D"`, `"EU energy label"` (when Fetch full product detail is on) |
| `badges` | `["Bestseller", "Top Angebot"]` (when Fetch full product detail is on) |
| `otherOffers` | other marketplace sellers' offers for the same product, when present and Fetch full product detail is on |
| `reviews.averageRating` / `reviews.totalReviewCount` | `4.2`, `86` |
| `reviews.items[]` | `[{"id": "R-0001", "rating": 5, "title": "Guter Kauf", "text": "Läuft schnell und leise, absolut empfehlenswert.", "reviewerName": "Julia K.", "date": "2026-03-14T10:22:00.000Z", "isVerifiedPurchaser": true, "syndicationSource": null}]` |

### How to Use

1. Pick a **mode**: `search` (keyword or category id; if both are set, the category wins and the keyword is ignored) or `url` (paste product, category or listing links).
2. Fill in the fields for that mode, and turn on full product detail and/or reviews if you need them.
3. Set brand, price, rating and sort filters if you want to narrow the result set, then set **Max products total** 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 20 products, with reviews (on by default):**

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

**Category browse, filtered to a brand and price range, sorted by price:**

```json
{
  "mode": "search",
  "categoryId": "515",
  "brands": ["ASUS"],
  "minPrice": 300,
  "maxPrice": 900,
  "sortBy": "PRICE_ASC",
  "maxItems": 50,
  "maxPages": 5
}
```

**Full product detail and reviews for pasted product links:**

```json
{
  "mode": "url",
  "urls": ["https://www.mediamarkt.de/de/product/_p-3141592.html"],
  "fetchDetails": true,
  "fetchReviews": true,
  "maxReviewsPerProduct": 10
}
```

**Continue a previous run, collecting only new products:**

```json
{
  "mode": "search",
  "categoryId": "515",
  "resumeFromRunId": "<a previous run id or dataset id>"
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

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

#### Pages, budgets and resuming

**Max pages per search** and **Max products total** together bound the size and cost of a run: pages are walked from the start (or from any `page=` already in a pasted URL) until either cap is hit, or the site stops returning new products. Set **Max pages per search** to `0` to walk every page.

**Resume from run/dataset id** continues one interrupted run: paste its run or dataset id and this run skips every product already in that run's dataset, so you only get and pay for products not already there (a delta), not necessarily products added since that run. The run also checkpoints itself automatically as it goes, so if the platform restarts or migrates it mid-run, resuming with the same input picks up right where it left off, with no duplicate products and no double charges.

#### Incremental mode (scheduled runs)

Turn on **Incremental mode** and the actor remembers the products it saw, so a scheduled run returns only what changed. Every row then carries `changeType` (`NEW`, `UPDATED`, `REAPPEARED` or `EXPIRED`, plus `UNCHANGED` if you ask for it), `changedFields` (the names of the fields that differ), `firstSeenAt` and `lastSeenAt`. All row fields are compared except the scrape timestamp and the review list; a new review still shows up through `rating` and `reviewCount`. Use **Ignore fields when detecting changes** for fields you do not want to count, for example `shippingCost`.

- Unchanged products are not emitted and not billed (a row is only billed when it is delivered). The product page may still be read to compare it.
- `EXPIRED` rows (products that disappeared from the results) are only reported after a run that walked the whole result list: set **Max products total** and **Max pages per search** to `0`. A run cut short by a cap, a resume id or an unavailable page never marks anything EXPIRED. Each EXPIRED row is a normal delivered result row and counts toward Max products total.
- The remembered state belongs to your search, filters and detail/review options. A different search gets its own baseline; set **State key** to keep one baseline for a task you edit. Changing caps or proxy never starts a new baseline.
- With incremental mode off, output is exactly as before. Combining it with a resume id works but skips the EXPIRED report.

#### Supported link shapes (url mode)

| Link shape | Example | What you get |
| --- | --- | --- |
| Search | `/de/search.html?query=notebook` | Search results; a search the site redirects to a category is followed automatically |
| Search, paginated | `...?query=...&page=2` | Pagination continues forward from that page |
| Search, sorted | `...?query=...&sort=price` | The pasted `sort` is carried through |
| Category | `/de/category/laptops-notebooks-362.html` | Category listing |
| Category, paginated | `.../laptops-notebooks-362.html?page=2` | Pagination continues forward from that page |
| Category, filtered | `...?sort=price&brand=APPLE` | The pasted `sort`, `brand` and `currentprice` are carried through and win over the matching inputs for that link |
| Category, numeric id | `/de/category/c-362.html` | Category listing |
| Search, brand-filtered | `/de/search.html?query=iphone&brand=APPLE` | The pasted `brand` is carried through |
| Category, no-www host | `https://mediamarkt.de/de/category/laptops-notebooks-362.html` | Treated the same as the www host |
| Category with `searchParams` | `.../laptops-notebooks-362.html?searchParams=/Search.ff?query=notebook` | The category is scraped; the query inside `searchParams` is not applied |
| Product | `/de/product/_name-3008418.html` or `/de/product/_p-3008418.html` | One record for that product |

The **URLs** field is pre-filled with 13 example URLs. When the `urls` key is left out of the input (an API call, or a task that never set it), the run uses a default list of seven examples that each return their own rows. The six pre-fill-only forms point at products or categories already covered by the default, so they are not in it: the search that redirects to a category (`query=notebook`), the `c-<id>` category link, the `_p-<id>` product link, the brand-filtered search (`query=iphone&brand=APPLE`), the no-www host category link and the category link with a `searchParams` parameter. An explicitly empty list (`"urls": []`, for example a cleared Console field or a saved task with an empty list) is not replaced: the run logs `URL mode needs at least one pasted URL` and returns nothing. Links on other hosts (for example m.mediamarkt.de), paths without `/de/` and brand pages are skipped, and the log says `Unsupported URL, skipped (0 items from it)` for each.

In `url` mode, each pasted URL (product, category or search) in turn gets a whole-number share of what remains of **Max products total** (remaining divided by the URLs still to go, rounded up, at least 1). A share an earlier URL does not use passes to the later ones, and the total never exceeds Max products total, so with fewer products than URLs the last URLs may get none.

### 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 have not authorized a connector yet.
3. For **Notion**, also set `notionParentPageUrl` to the page where item pages should be created.

The connection is mediated by Apify's own MCP proxy, so this actor never sees your third party credentials. Leave the field empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` (keyword or category id, with the site's own filters and sort; if both are set, the category wins and the keyword is ignored) or `url` (paste links). |
| `searchTerm` | string | prefill: `notebook` | Free text keyword, e.g. `notebook` or `kaffeemaschine`. Search mode only. |
| `categoryId` | string | (none) | Numeric MediaMarkt category id (from `.../laptops-notebooks-362.html` giving `362`) or a category name as typed on the site (for example `Laptops`), resolved through the site's search; a name that cannot be resolved fails the run. Search mode only. |
| `brands` | array | prefill: `[]` | Only return products from these exact brand names. Applies in both search and URL mode. |
| `minRating` | integer | (none) | Only return products rated at or above this many stars, 1 to 5. Applied locally after each page loads (the site has no equivalent server-side filter), so more pages may be walked to fill the result. Applies in both search and URL mode. |
| `inStockOnly` | boolean | `false` | Only return products currently available to buy online. Checked locally on each product's availability flag, so pages keep being walked to fill the result. 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. |
| `sortBy` | string | `RELEVANCE` | MediaMarkt's own sort order. Applies in both search and URL mode. In URL mode a pasted listing URL's own `sort`, `brand` and `currentprice` parameters win over these inputs for that URL. |
| `urls` | array | seven distinct-target examples when the key is omitted; the Console pre-fill holds 13 URLs, six of them pre-fill-only forms; an explicit empty list scrapes nothing | Product, category or search listing URLs to scrape. URL mode only; pagination continues forward from any `page=` already present. |
| `fetchDetails` | boolean | `false` | Fetch the full flattened spec sheet, delivery and pickup detail, energy label, promo badges and marketplace offers. |
| `fetchReviews` | boolean | `true` | Fetch review summary and the product's most recent reviews (rating, title, text, date, verified purchaser flag). |
| `maxReviewsPerProduct` | integer | `10` | Cap on reviews returned per product when Fetch reviews is on. The product page itself renders only its most recent reviews (currently up to about 10), so values above that return what the page shows. `0` returns all available on that page. Maximum `1000`. |
| `maxPages` | integer | `0` | Cap on result pages per search, category or URL entry. `0` means unlimited, walk every page until the site stops returning new products or the total product cap is hit. |
| `maxItems` | integer | `20` | Hard cap on total products returned across every search, category or URL entry. `0` means unlimited (still bounded by Max pages per search). |
| `incrementalMode` | boolean | `false` | Remember products between runs and emit only changes (see Incremental mode above). |
| `stateKey` | string | (auto) | Name for the remembered state; empty derives it from your search and filters. |
| `emitUnchanged` | boolean | `false` | Also emit products that did not change (`changeType` UNCHANGED). |
| `emitExpired` | boolean | `true` | After a complete run, emit EXPIRED rows for products no longer listed. |
| `ignoreFieldsForChanges` | array | (empty) | Field names that must not count as a change. |
| `resumeFromRunId` | string | (none) | A previous run id (or its dataset id). Products already in that run's dataset are skipped, so this run returns only products not already there (a delta). Leave empty for a normal run. |
| `proxy` | object | Residential, country DE | Connection settings. The default already selects a residential connection in Germany. |
| `mcpConnectors` | array | (none) | Optional MCP connectors to export a summary of results into (Notion, Linear, Airtable, Apify). |
| `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 are illustrative placeholders, not from a live product.

```json
{
  "productId": "3141592",
  "sku": "3141592",
  "ean": "4012345678905",
  "name": "UltraView Pro 15 Notebook",
  "brand": "Voltek",
  "category": "15 Zoll Notebooks",
  "categoryPath": ["Computer & Zubehör", "Notebooks & Laptops", "15 Zoll Notebooks"],
  "url": "https://www.mediamarkt.de/de/product/_p-3141592.html",
  "price": 899,
  "currency": "EUR",
  "originalPrice": 1299,
  "discountAmount": 400,
  "discountPercent": 31,
  "isOnSpecial": true,
  "strikePriceType": "RRP",
  "onlineAvailable": true,
  "availabilityStatus": "ONLINE",
  "isMarketplace": false,
  "image": "https://assets.mmsrg.com/isr/sample/ASSET_PLACEHOLDER",
  "images": ["https://assets.mmsrg.com/isr/sample/ASSET_PLACEHOLDER"],
  "specs": {
    "Bildschirmdiagonale": "15,6 Zoll",
    "Arbeitsspeicher (RAM)": "16 GB"
  },
  "rating": 4.2,
  "reviewCount": 86,
  "reviews": {
    "averageRating": 4.2,
    "totalReviewCount": 86,
    "items": [
      {
        "rating": 5,
        "title": "Guter Kauf",
        "text": "Läuft schnell und leise, absolut empfehlenswert.",
        "reviewerName": "Julia K.",
        "date": "2026-03-14T10:22:00.000Z",
        "isVerifiedPurchaser": true
      }
    ]
  }
}
```

#### Output views

The dataset has four views in the Console. **Overview** shows one row per product with price, discount, availability and rating. **Detail** adds the spec sheet, delivery, pickup, energy label, badges and marketplace data. **Reviews** flattens each product's reviews into readable columns. **Changes** lists the incremental-mode change fields next to price and link. Every view reads the same record; the fields in the table above are only added to, never renamed.

### Plan Requirement

A residential connection is required. MediaMarkt answers datacenter connections with a security challenge (HTTP 403, a managed browser check) on every request, so a datacenter connection does not return products. The default proxy configuration already selects a residential connection in Germany, which needs a paid Apify plan with residential proxy access, or your own proxy URLs.

What you will see when the connection is not available:

- On a free plan (no residential access), the log prints a notice that the selected connection is unavailable and that Apify free plans do not include residential proxies, then continues on a backup connection where some pages may still be unavailable. If the backup connection serves data, the log says `Served over the backup connection (the default connection was unavailable).`
- If the backup connection also cannot load pages, the run fails with `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 MediaMarkt pages.`
- If the proxy connection is refused for the account, the run fails with `The proxy connection was refused for this account, so no page could be read.`
- If no results page could be loaded for any other reason, the run fails with `Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search.` An empty search with a working connection ends normally with no products.

A refused request is retried on a fresh connection a limited number of times, and if most connections keep being refused the run stops early instead of grinding on, keeping everything already collected.

### FAQ

#### How much does it cost?

You pay per product returned (the result event), plus one detail-enrichment event per product whose full detail and/or reviews were fetched. Fetch reviews is on by default, so most runs include this event for nearly every product. It is charged once per enriched product, right after that product is written to the dataset, so it is counted as the run goes and never for a product that was not delivered; turn both detail toggles off to pay only the per-product result event. The **Pricing** tab shows the current rates. Use **Max products total** to cap the cost of any run.

#### Is it legal to scrape MediaMarkt?

This actor collects only publicly available product data. You are responsible for how you use it, follow MediaMarkt's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Product images, brand names and review text may be subject to third party rights.

#### Can I avoid re-collecting products I already have?

Yes, but not automatically on a schedule. Set `resumeFromRunId` to a previous run's id (or dataset id) and this run skips every product already in that run's dataset, so you do not pay twice for the same product. On a recurring schedule, turn on **Incremental mode** instead: the actor remembers the previous run itself and returns only new, changed or no-longer-listed products, with no id to update.

#### Why do I need a residential connection?

MediaMarkt's pages only load reliably over a residential connection. The default proxy configuration already selects one in Germany, so most runs need no changes at all.

#### Why did my run return no products?

Check your filters (brand, price range, minimum rating, in-stock only) and category or search term first. If no page could be loaded at all, the run fails with a connection message (see Plan Requirement) rather than finishing empty; run it again in a few minutes. If only some pages could not be read, you still get what was found, and already collected products are kept.

#### 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 a summary of results into Notion, Linear or Airtable.

### 🔗 Want more MediaMarkt data?

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

<table>
<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/obi-de-scraper"><b>OBI.de Scraper</b></a><br>Scrape OBI (obi.de) DIY/home-improvement products: current + strike-through original...</td></tr>
<tr><td>🥦 <a href="https://apify.com/abotapi/kaufland-de-scraper"><b>Kaufland.de Scraper</b></a><br>Scrape Kaufland.de, Germany's hypermarket and online marketplace: keyword/category/brand...</td><td>🥦 <a href="https://apify.com/abotapi/rewe-de-scraper"><b>REWE.de Scraper</b></a><br>Scrape REWE Germany (rewe.de) grocery products: current price, was-price and discount...</td></tr>
<tr><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><td>🛒 <a href="https://apify.com/abotapi/douglas-de"><b>Douglas Germany Scraper</b></a><br>Scrape Douglas.de beauty and fragrance products by keyword, category, brand, or URL...</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/mediamarkt-de-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 MediaMarkt category id, with the site's own brand/price filters and native sort. 'url' scrapes any product, category, or search listing page URL you paste, walking pagination forward automatically.

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

Free-text keyword, e.g. 'notebook' or 'kaffeemaschine'. Leave empty if you set a Category id below.

## `categoryId` (type: `string`):

The numeric id from a MediaMarkt category URL (e.g. .../laptops-notebooks-362.html gives 362), or a category name as typed on the site (e.g. notebook), which is resolved through the site's own search; a name that does not resolve fails the run with a clear error. Combine with a keyword to search within a category, or leave the keyword empty to browse the whole category.

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

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

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

Only return products rated at or above this many stars, 1-5.

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

## `inStockOnly` (type: `boolean`):

Keep only products that are currently available to buy online. Applies in both search and URL mode (checked on each product's online-availability flag, so pagination still fills the item cap with in-stock products only).

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

MediaMarkt's own sort order, verified live by driving the site's sort dropdown -- reorders the full server-side result set, so it stays correct across pagination. Applies in both search and URL mode: URL mode does not replay the pasted link, it rebuilds the category/search request from scratch and applies this input to that rebuilt request, so a pasted listing URL's own sort parameter is dropped, not preserved.

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

Paste MediaMarkt product pages (.../product/\_<slug>-<id>.html or \_p-<id>.html), category pages (.../category/<slug>-<id>.html or c-<id>.html) or search pages (.../search.html?query=...). A pasted page, sort, brand and currentprice are carried through. Other hosts or paths are skipped with a warning. When the urls key is omitted (API call or default), a list of seven distinct-target examples is scraped; the Console pre-fill holds 13 URLs, including six pre-fill-only forms (a search that redirects to a category, c-<id> and \_p-<id> links, a brand-filtered search, a no-www host link and a category link with a searchParams parameter, whose embedded query is not applied). An explicitly empty list logs 'URL mode needs at least one pasted URL' and scrapes nothing.

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

Adds the full flattened spec sheet (varies per category -- RAM/CPU for a laptop, panel type for a TV), delivery/pickup availability detail, energy efficiency label, promo badges, and marketplace/other-seller offers from the product page. Current price, was-price/discount, rating and main image are already included without this toggle.

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

Fetch each product's review summary (average rating, total count) and its most recent reviews (rating, title, text, date, verified-purchaser flag). MediaMarkt renders its newest review page server-side; it does not expose a plain paginated route for a product's entire review history, so this returns that first page, capped by 'Max reviews per product'. Products with no reviews simply return an empty list.

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

Cap on reviews returned per product when 'Fetch reviews' is on (bounded by what the site's own product page renders, currently up to about 10). 0 = all available on that page. Capped at 1000.

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

Stop after this many result pages per search/category/URL entry. 0 = unlimited -- walk every page until the site stops returning new products or Max products total is hit.

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

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

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

A residential connection is required for a reliable run on this site. The default below already selects a residential connection in Germany.

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

Paste a previous run id (or its dataset id) to continue that run: products already collected there are skipped, so this run only returns new products (a delta). Leave empty for a normal run.

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

Remember products between runs and emit only what changed: each row gets changeType NEW, UPDATED, REAPPEARED or EXPIRED, plus changedFields (the names of the fields that differ), firstSeenAt and lastSeenAt. Compared fields: everything in the row except the scrape timestamp and the review list (a new review still shows through rating and reviewCount). Unchanged products are not emitted or billed unless you turn on the next option. EXPIRED (no longer listed) is only reported after a run that walked the whole result list, so combine with Max products total = 0 and Max pages = 0 for full tracking. Off by default: output is unchanged.

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

Optional name for the remembered state. Leave empty to derive it from your search, filters and detail/review options, so a different search never shares a baseline. Set the same key on a task to keep one baseline when you edit its search.

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

Emit products that did not change, with changeType UNCHANGED. Off: they are skipped and not billed.

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

After a complete run, emit one EXPIRED row for each previously seen product that is no longer in the results. Each emitted row is a normal result row.

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

Field names that must NOT count as a change, for example shippingCost or availabilityStatus. The scrape timestamp and the review list are always ignored. Only used when incremental mode is on.

## `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": "notebook",
  "brands": [],
  "inStockOnly": false,
  "sortBy": "RELEVANCE",
  "urls": [
    "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24",
    "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24&page=2",
    "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24&sort=price",
    "https://www.mediamarkt.de/de/search.html?query=notebook",
    "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html",
    "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?page=2",
    "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?sort=price&brand=APPLE",
    "https://www.mediamarkt.de/de/category/c-362.html",
    "https://www.mediamarkt.de/de/product/_hp-omen-17-db1351ng-173-zoll-amd-ryzentm-ai-5-340-16-gb-1-tb-nvidia-geforce-rtxtm-5060-windows-11-home-3008418.html",
    "https://www.mediamarkt.de/de/product/_p-3008418.html",
    "https://www.mediamarkt.de/de/search.html?query=iphone&brand=APPLE",
    "https://mediamarkt.de/de/category/laptops-notebooks-362.html",
    "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?searchParams=%2FSearch.ff%3Fquery%3Dnotebook"
  ],
  "fetchDetails": false,
  "fetchReviews": true,
  "maxReviewsPerProduct": 10,
  "maxPages": 0,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": true,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

No description

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

No description

## `detail` (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": "notebook",
    "brands": [],
    "urls": [
        "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24",
        "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24&page=2",
        "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24&sort=price",
        "https://www.mediamarkt.de/de/search.html?query=notebook",
        "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html",
        "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?page=2",
        "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?sort=price&brand=APPLE",
        "https://www.mediamarkt.de/de/category/c-362.html",
        "https://www.mediamarkt.de/de/product/_hp-omen-17-db1351ng-173-zoll-amd-ryzentm-ai-5-340-16-gb-1-tb-nvidia-geforce-rtxtm-5060-windows-11-home-3008418.html",
        "https://www.mediamarkt.de/de/product/_p-3008418.html",
        "https://www.mediamarkt.de/de/search.html?query=iphone&brand=APPLE",
        "https://mediamarkt.de/de/category/laptops-notebooks-362.html",
        "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?searchParams=%2FSearch.ff%3Fquery%3Dnotebook"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "DE"
    },
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/mediamarkt-de-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": "notebook",
    "brands": [],
    "urls": [
        "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24",
        "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24&page=2",
        "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24&sort=price",
        "https://www.mediamarkt.de/de/search.html?query=notebook",
        "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html",
        "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?page=2",
        "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?sort=price&brand=APPLE",
        "https://www.mediamarkt.de/de/category/c-362.html",
        "https://www.mediamarkt.de/de/product/_hp-omen-17-db1351ng-173-zoll-amd-ryzentm-ai-5-340-16-gb-1-tb-nvidia-geforce-rtxtm-5060-windows-11-home-3008418.html",
        "https://www.mediamarkt.de/de/product/_p-3008418.html",
        "https://www.mediamarkt.de/de/search.html?query=iphone&brand=APPLE",
        "https://mediamarkt.de/de/category/laptops-notebooks-362.html",
        "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?searchParams=%2FSearch.ff%3Fquery%3Dnotebook",
    ],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "DE",
    },
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/mediamarkt-de-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": "notebook",
  "brands": [],
  "urls": [
    "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24",
    "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24&page=2",
    "https://www.mediamarkt.de/de/search.html?query=samsung%20galaxy%20s24&sort=price",
    "https://www.mediamarkt.de/de/search.html?query=notebook",
    "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html",
    "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?page=2",
    "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?sort=price&brand=APPLE",
    "https://www.mediamarkt.de/de/category/c-362.html",
    "https://www.mediamarkt.de/de/product/_hp-omen-17-db1351ng-173-zoll-amd-ryzentm-ai-5-340-16-gb-1-tb-nvidia-geforce-rtxtm-5060-windows-11-home-3008418.html",
    "https://www.mediamarkt.de/de/product/_p-3008418.html",
    "https://www.mediamarkt.de/de/search.html?query=iphone&brand=APPLE",
    "https://mediamarkt.de/de/category/laptops-notebooks-362.html",
    "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html?searchParams=%2FSearch.ff%3Fquery%3Dnotebook"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  },
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/mediamarkt-de-scraper --silent --output-dataset

```

## MCP server setup

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