# Car Parts Price Matrix — Autodoc, Mister-Auto, kfzteile24 (`studio-amba/car-parts-price-matrix`) Actor

Compare car parts prices across Autodoc, Mister-Auto and kfzteile24 in one run. Matches products by manufacturer part number (MPN), EAN barcode, or OEM cross-reference number, and flags the cheapest retailer per matched part with the price spread.

- **URL**: https://apify.com/studio-amba/car-parts-price-matrix.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 result scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## Car Parts Price Matrix

Compare car parts prices across Autodoc, Mister-Auto and kfzteile24 in a single run. Give it one or more part categories, and it returns one row per part per retailer that carries it, matched on manufacturer part number (MPN), EAN barcode, or OEM cross-reference number — with the cheapest source and the price spread flagged on every matched row.

This actor does not scrape a website itself. It runs our own Autodoc, Mister-Auto and kfzteile24 scrapers in parallel, joins what comes back by part-number identifier, and builds the comparison matrix from the results.

### Why use this actor?

Mechanics, independent garages and parts resellers all face the same problem: the same branded part — a Brembo brake disc, a Bosch oil filter — is listed at different prices across every parts retailer, and reconciling that by hand means opening three tabs and matching part numbers yourself. This actor does the fan-out and the matching in one call and returns a flat table you can sort straight to the widest price gaps.

### What it returns

Each row in the output is one part at one source. Parts found at two or more sources are flagged `matched: true` with a price spread; parts found at only one source still get a row (`matched: false`) so nothing is silently dropped.

Real output from a cloud-verified run (see Matching logic below for the full match-rate numbers). This ATE brake disc (MPN `24.0112-0169.1`) turned up at all three sources — note Mister-Auto sells it as a pair (`packQty: 2`) while the other two sell it as a single disc, and `pricePerUnit` (not the raw listed `price`) is what the spread is computed on:

```json
[
    {
        "categoryLabel": "Brake discs (front, ATE)",
        "productName": "ATE 24.0112-0169.1 Bremsscheibe",
        "brand": "ATE",
        "source": "Autodoc",
        "price": 41.49,
        "currency": "EUR",
        "packQty": 1,
        "pricePerUnit": 41.49,
        "inStock": true,
        "url": "https://www.autodoc.de/ate/957024",
        "partNumberNormalized": "24011201691",
        "partNumberType": "mpn",
        "mpnRaw": "24.0112-0169.1",
        "eanRaw": "4006633267892",
        "oemRaw": "5Q0 615 601 G",
        "matched": true,
        "sourceCount": 3,
        "priceMin": 39.58,
        "priceMax": 42.46,
        "priceSpreadPct": 7.3,
        "cheapestSource": "kfzteile24",
        "scrapedAt": "2026-08-16T11:11:36.925Z"
    },
    {
        "categoryLabel": "Brake discs (front, ATE)",
        "productName": "ATE 24.0112-0169.1 Bremsscheibe",
        "brand": "ATE",
        "source": "Mister-Auto",
        "price": 84.92,
        "currency": "EUR",
        "packQty": 2,
        "pricePerUnit": 42.46,
        "inStock": null,
        "url": "https://www.mister-auto.com/disque-de-frein-arriere-ate-003-24011201691-p/",
        "partNumberNormalized": "24011201691",
        "partNumberType": "mpn",
        "mpnRaw": "24.0112-0169.1",
        "eanRaw": null,
        "oemRaw": "021197031",
        "matched": true,
        "sourceCount": 3,
        "priceMin": 39.58,
        "priceMax": 42.46,
        "priceSpreadPct": 7.3,
        "cheapestSource": "kfzteile24",
        "scrapedAt": "2026-08-16T11:11:36.925Z"
    },
    {
        "categoryLabel": "Brake discs (front, ATE)",
        "productName": "ATE 24.0112-0169.1 Bremsscheibe",
        "brand": "ATE",
        "source": "kfzteile24",
        "price": 39.58,
        "currency": "EUR",
        "packQty": 1,
        "pricePerUnit": 39.58,
        "inStock": true,
        "url": "https://www.kfzteile24.de/artikeldetails?search=1420-8792",
        "partNumberNormalized": "24011201691",
        "partNumberType": "mpn",
        "mpnRaw": "24.0112-0169.1",
        "eanRaw": null,
        "oemRaw": null,
        "matched": true,
        "sourceCount": 3,
        "priceMin": 39.58,
        "priceMax": 42.46,
        "priceSpreadPct": 7.3,
        "cheapestSource": "kfzteile24",
        "scrapedAt": "2026-08-16T11:11:36.925Z"
    }
]
```

### Use cases

- **Independent mechanics and garages** sourcing the cheapest supplier for a specific branded part before ordering.
- **Parts resellers doing arbitrage** — buy where a part is cheapest, resell or fit at the going rate.
- **Procurement teams at repair chains** tracking part costs across their approved suppliers.
- **Marketplace and catalog builders** who need part prices matched to a manufacturer part number rather than a fuzzy product-name guess.

### How to scrape and compare car parts prices across European retailers

1. Add one or more entries to **Part categories** (`queries`). Each entry needs a query or URL per source in that source's own language — an Autodoc category URL (German/French/etc. storefront), a Mister-Auto search term (French), and a kfzteile24 search term (German). None of the three sites take a literal part-number search reliably across languages, so a shared category (e.g. "brake discs") is what puts the same parts in front of all three sources.
2. Choose which **Sources** to include. Leave all three selected for the full matrix.
3. Set **Max Items Per Source** to control how many candidate parts each source contributes per category. Autodoc fetches a detail page per product to get OEM/EAN data, so this source is the slowest and the main cost driver — see Limitations.
4. Run the actor. All selected sources are queried in parallel per category, so adding sources doesn't multiply run time.
5. Open the dataset. Sort or filter on `matched: true` to see only parts confirmed across 2+ sources, then sort by `priceSpreadPct` descending to find the widest gaps.
6. Use `partNumberType` to judge match confidence: `mpn` and `ean` are exact-SKU matches; `oem` is a weaker vehicle-fitment match (see Matching logic).

### Input

| Field | Type | Description |
|-------|------|-------------|
| `queries` | array | Part categories to compare. Each entry: `label`, `autodocCategoryUrl`, `misterAutoQuery`, `kfzteile24Query`. Defaults to a brake-discs category if left empty. Max 10 entries. |
| `sources` | array | Which of the three sources to include (`autodoc`, `misterauto`, `kfzteile24`). Empty means all. |
| `maxItemsPerSource` | integer | Max candidate parts considered per source per category (1-50, default 20). |
| `timeoutPerSourceSecs` | integer | Max seconds to wait for each source scraper before treating it as failed (60-900, default 300). |
| `proxyConfiguration` | object | Proxy settings passed through to the kfzteile24 child scraper only. Autodoc uses its own Bright Data setup; Mister-Auto needs no proxy. |

#### Example input

```json
{
    "queries": [
        {
            "label": "Brake discs (front)",
            "autodocCategoryUrl": "https://www.autodoc.de/autoteile/bremsscheibe-10132",
            "misterAutoQuery": "disque de frein",
            "kfzteile24Query": "Bremsscheibe"
        },
        {
            "label": "Oil filters",
            "autodocCategoryUrl": "https://www.autodoc.de/autoteile/oelfilter-10004",
            "misterAutoQuery": "filtre a huile",
            "kfzteile24Query": "Oelfilter"
        }
    ],
    "sources": ["autodoc", "misterauto", "kfzteile24"],
    "maxItemsPerSource": 20
}
```

### Output

| Field | Type | Description |
|-------|------|-------------|
| `categoryLabel` | string | The part category this row was matched under |
| `productName` | string | Product name as reported by this source |
| `brand` | string | Parts manufacturer, when exposed |
| `source` | string | Autodoc, Mister-Auto or kfzteile24 |
| `price` | number | Current price at this source |
| `currency` | string | Price currency, never converted (EUR for all three sources today) |
| `inStock` | boolean | True/false/null — null when the source doesn't report stock status |
| `url` | string | Product page URL at this source |
| `partNumberNormalized` | string | The join key used to match this part across sources |
| `partNumberType` | string | `mpn`, `ean` or `oem` — see Matching logic |
| `mpnRaw` | string | Manufacturer part number as reported by this source, before normalization |
| `eanRaw` | string | EAN barcode as reported by this source, before normalization |
| `oemRaw` | string | First OEM cross-reference number as reported by this source, before normalization |
| `matched` | boolean | True if this part number was found at 2+ sources |
| `sourceCount` | integer | How many sources this part number was found at |
| `priceMin` / `priceMax` | number | Lowest/highest price for this matched part, same currency only |
| `priceSpreadPct` | number | `(priceMax - priceMin) / priceMin * 100` for this matched part |
| `cheapestSource` | string | Which source has the lowest price for this matched part |

### Matching logic

Parts are matched across sources in three tiers, tried in order:

1. **MPN (manufacturer part number)** — the exact aftermarket SKU as printed on the part, separators stripped and uppercased (`09.9772.11` → `09977211`). Two listings sharing an MPN are the same manufactured product. This is the primary match and covers the large majority of matches, since Autodoc, Mister-Auto and kfzteile24 all expose it (kfzteile24 under the field name `sku`, which follows the same "manufacturer part number as printed" convention).
2. **EAN barcode** — also exact, used when MPN is missing on one side.
3. **OEM cross-reference number** — used only as a last resort, for parts with neither MPN nor EAN. This is deliberately the weakest tier: an OEM number identifies a vehicle-fitment slot (e.g. "front brake disc for VW Golf 7"), not a specific manufactured product. Two *different* aftermarket parts — say an ATE disc and a Brembo disc that both fit the same car — can legitimately share an OEM reference. A `matched: true` row with `partNumberType: "oem"` means "these fit the same slot," not necessarily "this is the identical product." Filter to `mpn`/`ean` matches for a strict same-SKU comparison.

Note the priority is MPN first, not OEM first: an OEM cross-reference can legitimately point to several different branded parts that all fit the same car, so leading with it risks grouping different products together. MPN is the one identifier that's unique to a single manufactured item, so it's the safer primary key even though it's a narrower match on paper.

**Cloud-verified match rate**: a real run against a "brake discs" category (all three sources, `maxItemsPerSource: 60`, Autodoc capped at its usual ~20) returned 140 rows across 122 distinct part numbers, of which 17 (13.9%) matched across 2+ sources — including one part found at all three. Match rate depends heavily on how much the sources' catalogues actually overlap for the category and sample size queried; see Limitations.

### Norauto is not included

Norauto's own scraper output has no manufacturer part number, EAN or OEM field at all — just name, brand, price and rating. There is nothing to join on, so including it would mean either silently falling back to fuzzy name matching (which this actor deliberately avoids, unlike the grocery price matrix) or listing Norauto rows that can never be marked `matched: true`. It's left out until Norauto exposes a part-number field on its product listings.

### FAQ

**Does this actor scrape the retailer websites itself?**
No. It calls our own Autodoc, Mister-Auto and kfzteile24 scrapers and combines their output. Each of those actors is also available separately on the Store.

**Why can't I just search by a literal part number?**
None of the three underlying sources reliably support that across languages through this actor. Autodoc has no keyword search at all — only category browsing. Mister-Auto and kfzteile24 take a native-language search term against their own index. Point all three at the same part category (e.g. brake discs) instead, and let the part-number join do the matching.

**Why does Autodoc take longer than the other two sources?**
Autodoc's MPN/EAN/OEM data only exists on the product detail page, so this actor asks it to fetch one detail page per product (`fetchDetails: true`). Mister-Auto and kfzteile24 return everything from a single listing/search response. Budget more time and a slightly higher `timeoutPerSourceSecs` when Autodoc is included.

**What does `matched: false` mean?**
This source's version of the part wasn't found at any other selected source in this run. It's still a real result — just not (yet) confirmed elsewhere. It doesn't mean the part is exclusive to that retailer, only that this run didn't find a matching part number elsewhere.

**How is `priceSpreadPct` calculated?**
`(priceMax - priceMin) / priceMin * 100` across whichever sources carry the matched part number, restricted to sources reporting the same currency (currency is never converted). It's null when only one source has the part, or when the matched sources report different currencies.

**Do I need my own Bright Data key or proxy?**
No. Autodoc's Bright Data Web Unlocker key is configured on that actor itself. Proxy for kfzteile24 is optional (its listing pages have no anti-bot wall); Mister-Auto needs no proxy at all.

### Cost estimate

This actor is priced per result at $0.005 per row plus a $0.01 run-start fee — see the Store pricing tab for the current numbers. A single category query with all three sources at the default `maxItemsPerSource` (12; Autodoc capped at 20 regardless) typically returns 30-90 rows, so budget roughly $0.15-0.50 per category on a first run. Autodoc is the priciest source per result: each of its rows costs one extra Bright Data Web Unlocker request on top of this actor's own per-result price, so keep `maxItemsPerSource` proportionate to how many parts you actually need matched rather than maxing it out by default.

### Limitations

- Match rate depends on how much category overlap the three sources actually carry for a given part type — some categories will have a higher matched-vs-unmatched ratio than others. Every unmatched row is still returned, so you can judge coverage directly from the `matched` field rather than trusting a blanket claim.
- Autodoc is the slowest and priciest source in this matrix: each of its results costs one detail-page fetch through Bright Data Web Unlocker on top of Autodoc's own listed per-result price. Keep `maxItemsPerSource` proportionate to how many parts you actually need matched.
- A run's usage cost only settles once the run reports SUCCEEDED — reading a partial/in-progress dataset will show a cost far below the final total.
- Norauto is excluded (see above). Coverage is limited to Autodoc, Mister-Auto and kfzteile24 for now.
- Prices reflect each source's standard online price at the time of the run and can change without notice.

### Related actors

This matrix is built on our standalone car-parts scrapers, each of which you can also run on its own for a full-catalogue pull:

- [Autodoc Scraper](https://apify.com/studio-amba/autodoc-scraper)
- [Mister-Auto Scraper](https://apify.com/studio-amba/mister-auto-scraper)
- [kfzteile24 Scraper](https://apify.com/studio-amba/kfzteile24-scraper)
- [Norauto Scraper](https://apify.com/studio-amba/norauto-scraper)

We run this comparison as a managed service too: scheduled runs, a fixed part list, and delivery to your inbox, Google Sheets, or API, maintenance included. See [studioamba.dev/services](https://studioamba.dev/services/) or email <hello@studioamba.dev> for a free data sample.

# Actor input Schema

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

One entry per part category to compare. Each entry needs a query/URL per source in that source's own language — Autodoc has no keyword search (category browsing only), Mister-Auto and kfzteile24 take a native-language search term. Leave a source's field empty to skip it for that category. Capped at 10 entries per run.

## `sources` (type: `array`):

Which retailer scrapers to include in the comparison. Leave all selected for the full matrix. Norauto is deliberately excluded — its catalogue exposes no manufacturer part number, EAN or OEM field to join on (see README).

## `maxItemsPerSource` (type: `integer`):

Maximum number of products to pull from each source per part category. Autodoc fetches a detail page per product to get OEM/EAN data (roughly 10 seconds each) and is internally capped at 20 regardless of this value — a single Autodoc category page lists about that many products directly, and asking for more makes it wander into unrelated sibling categories (cloud-verified: requesting 40 from a brake-discs category pulled in oil filters). Mister-Auto and kfzteile24 use this value as-is. Cloud-verified: raising this for Mister-Auto/kfzteile24 (50-150+) substantially increases how many parts get matched, since these are large catalogues (1,000-2,000+ variants per category) and a small sample has low odds of hitting the exact same part number by chance.

## `timeoutPerSourceSecs` (type: `integer`):

Maximum time to wait for each underlying retailer scraper to finish. A slow or failing source is skipped after this rather than blocking the whole run. Autodoc's detail-page fetches need more headroom than the other two sources.

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

Proxy settings passed through to the kfzteile24 child scraper. Autodoc uses its own Bright Data Web Unlocker setup regardless of this setting; Mister-Auto queries a public JSON API directly and does not need a proxy.

## Actor input object example

```json
{
  "queries": [
    {
      "label": "Brake discs (front, ATE)",
      "autodocCategoryUrl": "https://www.autodoc.de/autoteile/bremsscheibe-10132",
      "misterAutoQuery": "disque de frein ATE",
      "kfzteile24Query": "Bremsscheibe"
    }
  ],
  "sources": [
    "autodoc",
    "misterauto",
    "kfzteile24"
  ],
  "maxItemsPerSource": 12,
  "timeoutPerSourceSecs": 300,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}
```

# Actor output Schema

## `results` (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 = {
    "queries": [
        {
            "label": "Brake discs (front, ATE)",
            "autodocCategoryUrl": "https://www.autodoc.de/autoteile/bremsscheibe-10132",
            "misterAutoQuery": "disque de frein ATE",
            "kfzteile24Query": "Bremsscheibe"
        }
    ],
    "sources": [
        "autodoc",
        "misterauto",
        "kfzteile24"
    ],
    "maxItemsPerSource": 12,
    "timeoutPerSourceSecs": 300,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "DE"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/car-parts-price-matrix").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 = {
    "queries": [{
            "label": "Brake discs (front, ATE)",
            "autodocCategoryUrl": "https://www.autodoc.de/autoteile/bremsscheibe-10132",
            "misterAutoQuery": "disque de frein ATE",
            "kfzteile24Query": "Bremsscheibe",
        }],
    "sources": [
        "autodoc",
        "misterauto",
        "kfzteile24",
    ],
    "maxItemsPerSource": 12,
    "timeoutPerSourceSecs": 300,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "DE",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/car-parts-price-matrix").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 '{
  "queries": [
    {
      "label": "Brake discs (front, ATE)",
      "autodocCategoryUrl": "https://www.autodoc.de/autoteile/bremsscheibe-10132",
      "misterAutoQuery": "disque de frein ATE",
      "kfzteile24Query": "Bremsscheibe"
    }
  ],
  "sources": [
    "autodoc",
    "misterauto",
    "kfzteile24"
  ],
  "maxItemsPerSource": 12,
  "timeoutPerSourceSecs": 300,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}' |
apify call studio-amba/car-parts-price-matrix --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/car-parts-price-matrix"
        }
    }
}

```

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/rbl8xGkuqNtmcE0rK/builds/Et5atzAONlRdPxPzs/openapi.json
