# OBI.de Scraper - Prices, Offers & Reviews (`abotapi/obi-de-scraper`) Actor

Scrape OBI (obi.de) DIY/home-improvement products: current + strike-through original price with discount, per-unit pricing (per m2/kg), specials/offers listings, brand, EAN, multi-seller stock, tech specs, and full reviews with rating breakdown. Search or paste links.

- **URL**: https://apify.com/abotapi/obi-de-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 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/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

## OBI Product Scraper

Pull rich product data from OBI (obi.de), the German DIY / home-improvement / hardware / garden retailer. Search by keyword, category, or currently-discounted specials, or paste product and listing links directly. Every record includes the current price, the strike-through original price with computed discount when a product is marked down, per-unit pricing (per m² / per kg / per piece) where the site shows it, and a complete customer review history with a full rating breakdown.

### Why This Scraper?

- **Was-price and discount, structured, not scraped from a badge.** When a product carries a reduced or recommended-retail original price, both are captured plus the computed discount amount and percentage.
- **Real per-unit pricing.** Building-material products (tiles, flooring, timber) return their per-square-metre or per-kilogram price separately from the pack/sale-unit price, exactly as the site distinguishes the two.
- **Specials, first-class.** A `specialsOnly` toggle narrows any search or category listing to only products currently showing a reduced price -- OBI has no separate "on sale" category route, so this filters the site's own live discount signal instead of faking a category that doesn't exist.
- **Full review history.** Overall rating, review count, a full 1 to 5 star rating breakdown, and every individual review with author, date, rating, title, and body text.
- **Rich detail on demand.** Full breadcrumb category path, flattened technical specifications (varies per product category, never hardcoded), media gallery, EAN, and multi-seller pricing/stock/shipping.
- **Two ways in.** Keyword or category search with real site filters (brand, rating, price range, specials, sort), or paste any product/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.

### Data You Get

| Field | Example value |
|---|---|
| productId / sku | `1234567` |
| name | `Sample Cordless Fan` |
| brand | `Sample Brand` |
| category / categoryPath | `Battery tools`, `[{"name": "Power tools", "url": "..."}, {"name": "Battery tools", "url": "..."}]` |
| url | `https://www.obi.de/p/1234567/sample-cordless-fan` |
| price / currency | `39.99`, `EUR` |
| originalPrice / originalPriceType / discountAmount / discountPercent | `49.99`, `STRIKE_PRICE`, `10.00`, `20.0` |
| unitPrice / unitPriceUnit | `20.99`, `m²` |
| isOnSpecial | `true` |
| rating / reviewCount | `4.7`, `62` |
| onlineAvailable / onlineAvailabilityStatus / storeAvailabilityStatus | `true`, `BESTELLBAR`, `KEIN_MARKT_AUSGEWAEHLT` |
| image / images | `["https://www.obi.de/sample/image.png"]` |
| ean / eans | `4000000000000` |
| description | full text field |
| technicalData | `{"Weight": "476 g", "Height": "26.5 cm", "Battery type": "Li-Ion"}` (flattened per category) |
| media | `[{"type": "image", "url": "...", "thumbnail": "..."}]` |
| variants | `[]` (populated when the product has size/colour options) |
| sellers | `[{"sellerName": "Sample Seller", "price": 39.99, "shippingCost": 4.95, "stock": 36}]` |
| manufacturerName / manufacturerCountry / taxPercent | `Sample Manufacturer AG`, `DE`, `19` |
| reviews.averageRating / reviews.totalReviewCount | `4.7`, `62` |
| reviews.ratingDistribution | `[{"rating": 5, "count": 50}, {"rating": 4, "count": 10}, ...]` |
| reviews.items\[] | `[{"rating": 5, "title": "Sample title", "body": "Sample review text.", "author": "Sample User", "date": "2026-07-12T07:31:15.000+00:00", "isRecommended": true, "verifiedPurchaser": true}]` |

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

### How to Use

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

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

**2. Category browse, filtered to a brand and only currently-discounted items:**

```json
{
  "mode": "search",
  "searchTerm": "werkzeuge",
  "brands": ["Bosch"],
  "specialsOnly": true,
  "sortBy": "PRICE_ASC",
  "maxItems": 50,
  "maxPages": 5
}
```

**3. Full product detail + reviews for pasted product links:**

```json
{
  "mode": "url",
  "urls": ["https://www.obi.de/p/1234567/sample-cordless-fan"],
  "fetchDetails": true,
  "fetchReviews": true,
  "maxReviewsPerProduct": 0
}
```

**4. Paste a listing link and keep paginating forward:**

```json
{
  "mode": "url",
  "urls": ["https://www.obi.de/search/akku%20ventilator/"],
  "maxItems": 100,
  "maxPages": 10
}
```

### Input Parameters

| Parameter | Type | Description |
|---|---|---|
| `mode` | string | `search` or `url`. |
| `searchTerm` | string | Keyword or a real category slug (search mode only). |
| `specialsOnly` | boolean | Keep only currently-discounted products (search mode only). |
| `brands` | array | Exact brand names to keep (search mode only). |
| `minRating` | integer | 1-5, minimum rating to keep (search mode only). |
| `minPrice` / `maxPrice` | number | EUR price band to keep (search mode only). |
| `sortBy` | string | `RELEVANCE`, `PRICE_ASC`, `PRICE_DESC`, or `RATING` (search mode only). |
| `urls` | array | Product or listing URLs to scrape (url mode only). |
| `fetchDetails` | boolean | Fetch full product detail (breadcrumb, description, specs, media, EAN, sellers). |
| `fetchReviews` | boolean | Fetch full review history. |
| `maxReviewsPerProduct` | integer | Cap on reviews per product; `0` = all. |
| `maxPages` | integer | Cap on result pages per search/URL entry; empty = unlimited. |
| `maxItems` | integer | Cap on total products returned; `0` = unlimited. |
| `proxy` | object | Apify proxy configuration. Works on every plan by default. |
| `mcpConnectors` | array | Optional MCP connectors to export results into (Notion, Linear, Airtable, Apify). |
| `notionParentPageUrl` | string | Notion connector only: page under which item pages are created. |
| `maxNotifyListings` | integer | Cap on items exported to each connector per run. Does not affect the dataset. |

### Output Example

```json
{
  "productId": "1234567",
  "sku": "1234567",
  "name": "Sample Cordless Fan",
  "brand": "Sample Brand",
  "category": "Battery tools",
  "url": "https://www.obi.de/p/1234567/sample-cordless-fan",
  "price": 39.99,
  "currency": "EUR",
  "originalPrice": null,
  "discountAmount": null,
  "discountPercent": null,
  "isOnSpecial": false,
  "unitPrice": null,
  "unitPriceUnit": null,
  "rating": 4.7,
  "reviewCount": 62,
  "onlineAvailable": true,
  "image": "https://www.obi.de/sample/image.png",
  "reviews": {
    "averageRating": 4.7,
    "totalReviewCount": 62,
    "ratingDistribution": [{ "rating": 5, "count": 50 }, { "rating": 4, "count": 10 }],
    "items": [
      {
        "rating": 5,
        "title": "Sample title",
        "body": "Sample review text.",
        "author": "Sample User",
        "date": "2026-07-12T07:31:15.000+00:00",
        "isRecommended": true,
        "verifiedPurchaser": true
      }
    ]
  }
}
```

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

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

Optionally pipe results into the apps you already use through Model Context Protocol (MCP) connectors. Authorize a connector once under Apify, Settings, Integrations, then select it in the `mcpConnectors` field. Each connector receives a condensed, human-readable summary per product (title plus key fields), while the complete record always stays in the Apify dataset. For Notion, set `notionParentPageUrl` to the page the item pages should be created under, and use `maxNotifyListings` to cap how many items are exported per connector per run. Supported connectors: Notion, Linear, Airtable, and Apify. Leave the field empty to skip; it never changes the dataset output.

### A note on plans

The default connection works on every Apify plan, including the free tier. A residential proxy connection is optional and only worth turning on for very large or sustained runs.

# Actor input Schema

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

'search' finds products by keyword, category, and/or the site's own currently-discounted specials, with real site filters. 'url' scrapes any product, search-result, or category page URL you paste, walking pagination forward automatically.

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

Free-text keyword (e.g. 'akku ventilator') or a known OBI category slug (e.g. 'werkzeuge', 'garten', 'bad', 'kueche') to browse a whole listing. Leave empty and set only Specials category below to browse current offers.

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

OBI has no separate 'on sale' category route -- it marks currently-reduced products with a strike-through original price inline in every listing. Turn this on to keep only products that currently show a reduced price and discount (narrows the same search/category listing, verified live on 'aktion').

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

Only return products from these brands, e.g. 'Bosch', 'Einhell', 'Makita'. 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.

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

Order of the returned results (applied to the fetched result set; for a fully sorted view across a large catalog, combine with a larger Max products total).

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

Paste one or more OBI product pages (.../p/<articleNumber>/<slug>), or search/category listing pages (.../search/<term>/). Pagination continues forward automatically from any ?page= already in the URL. Filter fields above are ignored in this mode.

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

Adds the full breadcrumb category path, description, technical data/specifications (flattened), media gallery, variants, EAN, multi-seller pricing/stock, and manufacturer info from the product detail page. Current price, was-price/discount, unit price and rating are already included without this toggle.

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

Fetch each product's full review history: overall rating, review count, a full 1-5 rating breakdown, and per-review author/date/rating/title/body. Products with no reviews simply return an empty list.

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

Cap on reviews fetched per product when 'Fetch reviews' is on. 0 = all available reviews.

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

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

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

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

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

The default connection works on every Apify plan, including the free tier. A residential connection is optional and only needed for very large or sustained runs.

## `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": "akku ventilator",
  "specialsOnly": false,
  "brands": [],
  "sortBy": "RELEVANCE",
  "urls": [
    "https://www.obi.de/search/akku%20ventilator/"
  ],
  "fetchDetails": false,
  "fetchReviews": true,
  "maxReviewsPerProduct": 20,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (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": "akku ventilator",
    "brands": [],
    "urls": [
        "https://www.obi.de/search/akku%20ventilator/"
    ],
    "proxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/obi-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": "akku ventilator",
    "brands": [],
    "urls": ["https://www.obi.de/search/akku%20ventilator/"],
    "proxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/obi-de-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": "akku ventilator",
  "brands": [],
  "urls": [
    "https://www.obi.de/search/akku%20ventilator/"
  ],
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call abotapi/obi-de-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=abotapi/obi-de-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Pk81tZ7fcR0bzfJJL/builds/FjS6jqZr4bBYmKEh2/openapi.json
