# BAUHAUS Product Scraper (`memo23/bauhaus-product-scraper`) Actor

Scrape BAUHAUS (bauhaus.info) products: name, brand, price in EUR, rating, reviews, availability, EAN/GTIN, images and full technical specs. Search by keyword, sweep category URLs, or pull specific product URLs. Overview or detail mode. Clean JSON/CSV, no code.

- **URL**: https://apify.com/memo23/bauhaus-product-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.50 / 1,000 overview products

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/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

## BAUHAUS Product Scraper

Turn any bauhaus.info search, category, or product link into structured product data.
Pull price, brand, rating, availability, EAN, and the full German spec table from BAUHAUS, the German DIY and home-improvement retailer. Start from a keyword like `bohrmaschine`, a category page, or a direct product URL. Output is clean JSON or CSV, one row per product.

![How the BAUHAUS Product Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-bauhaus.png)

### Why Use This Scraper

- ✅ Three ways in: free-text keywords, category or search URLs, or direct product links, mixed in one run
- ✅ Two speeds: Overview mode for fast price and rating pulls, Detail mode for the full spec table, description, EAN, and breadcrumbs
- ✅ German technical specs captured as they appear on the page (e.g. `Spannweite Bohrfutter`, `Gewicht (Netto)`, `Gangzahl`), 11 to 21 rows per product
- ✅ EAN / GTIN on every detail row for catalog and PIM matching
- ✅ Sort by relevance, price, or topseller to grab the exact slice you want
- ✅ Bot protection is handled for you: no proxies, no API keys, no browser setup
- ✅ One flat row per product, ready for CSV, spreadsheets, or a database

### Overview

The BAUHAUS Product Scraper is built for pricing analysts, category managers, and catalog teams who need structured product data from bauhaus.info, the German DIY and home-improvement retailer.

Every run returns product rows. Whether you start from a keyword, a category page, or a single product URL, the dataset is a flat stream of products, not separate search or category records.

Two modes control how much you get per product:

- **Overview** (default) reads the fields shown on search and category cards: price, brand, rating, availability, and image. It is the fast, low-cost option for price tracking.
- **Detail** opens each product page and adds the SKU, EAN, description, breadcrumb path, USP highlights, and the full German specification table.

Some fields are naturally sparse. Products with no reviews return `null` for `rating` and `reviewCount`, unbranded items return an empty `brand`, and the `highlights` array is empty on products where BAUHAUS shows no USP badges. Those keys stay present in every row so your columns line up across the whole export.

### Supported Inputs

#### Keyword mode

Type what you would type in the BAUHAUS search bar, one search per line. Every result lands in the same dataset.

```json
{
  "keywords": ["bohrmaschine", "akkuschrauber", "led lampe"]
}
```

#### Start URL types

Paste bauhaus.info links directly. The actor detects each one and routes it to the right handler.

| Type | Pattern | Example |
|---|---|---|
| Category / listing page | `/<category>/c/<id>` | `https://www.bauhaus.info/akkuschrauber-akkubohrschrauber/c/10007754` |
| Product page | `/<category>/<product-name>/p/<id>` | `https://www.bauhaus.info/akkuschrauber-akkubohrschrauber/skil-akkuschrauber-2636-ad/p/24816535` |

Category and search-result pages are swept page by page, exactly like a keyword. Product pages (`.../p/<id>`) are fetched directly. You can mix keywords and URLs freely in one run.

```json
{
  "startUrls": [
    "https://www.bauhaus.info/akkuschrauber-akkubohrschrauber/c/10007754",
    "https://www.bauhaus.info/akkuschrauber-akkubohrschrauber/skil-akkuschrauber-2636-ad/p/24816535"
  ]
}
```

#### Unsupported inputs

- ❌ Account, cart, or checkout pages behind the BAUHAUS login
- ❌ Country sites other than bauhaus.info (for example bauhaus.at or bauhaus.ch)
- ❌ Hosts outside `bauhaus.info`

### Use Cases

| Audience | Use case |
|---|---|
| **Pricing teams** | Track BAUHAUS prices over time and react to competitor moves |
| **Category & assortment managers** | Compare catalog breadth, brands, and gaps against your own range |
| **Catalog / PIM teams** | Enrich product records with EAN/GTIN, specs, and descriptions |
| **Market researchers** | Study the German DIY market: brands, price bands, and ratings |
| **Resellers & marketplaces** | Build and refresh product feeds from a single source |

### How It Works

1. **Input** — add keywords, category or search URLs, and product URLs (any mix).
2. **Clear the bot check** — each fetch lane opens a session that passes the site's protection, then reuses it for later requests.
3. **Collect products** — keywords and category/search pages are swept in your chosen sort order until `maxItems` is reached.
4. **Enrich (Detail mode)** — each product page is opened for its SKU, EAN, description, breadcrumbs, highlights, and spec table.
5. **Output** — one product per dataset row, exportable as JSON, CSV, or Excel, or read live through the Apify API.

### Input Configuration

Every field below maps one-to-one to the actor's input schema.

| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
| `keywords` | `array<string>` | keywords or startUrls | — | Free-text BAUHAUS searches, one per line (e.g. `bohrmaschine`) |
| `startUrls` | `array` | keywords or startUrls | — | Category, search, or product URLs; mix with keywords |
| `scrapeMode` | `string` enum | optional | `overview` | `overview` (fast fields) or `detail` (specs, description, EAN) |
| `sort` | `string` enum | optional | `relevance` | `relevance`, `price_low`, `price_high`, `topseller` |
| `maxItems` | `integer` | optional | `100` | Cap across all keywords and URLs combined; free runs are capped at 25 |
| `maxConcurrency` | `integer` | optional | `4` | Parallel fetch lanes, 1 to 6. Higher is faster but uses more memory |

#### Common scenarios

**1. Fast price pull by keyword**

```json
{
  "keywords": ["akkuschrauber"],
  "scrapeMode": "overview",
  "sort": "price_low",
  "maxItems": 200
}
```

**2. Full specs from a category, cheapest first**

```json
{
  "startUrls": ["https://www.bauhaus.info/akkuschrauber-akkubohrschrauber/c/10007754"],
  "scrapeMode": "detail",
  "sort": "price_low",
  "maxItems": 100
}
```

**3. Specific products by URL**

```json
{
  "startUrls": [
    "https://www.bauhaus.info/akkuschrauber-akkubohrschrauber/skil-akkuschrauber-2636-ad/p/24816535"
  ],
  "scrapeMode": "detail"
}
```

### Output Overview

Each dataset item is one product. The row shape depends on `scrapeMode`:

- **Overview rows** carry the core fields: `productId`, `name`, `brand`, `price`, `currency`, `availability`, `rating`, `reviewCount`, `image`, `url`, and `scrapedAt`.
- **Detail rows** carry everything above plus `sku`, `ean`, `description`, `breadcrumbs`, `highlights`, and `specifications`.

`price` is a number and `currency` is `EUR`, so you can sum and sort without stripping symbols. `specifications` is an object of German label/value pairs taken straight from the product's spec table, so the keys vary by product category.

### Output Samples

#### Overview row

```json
{
  "scrapeMode": "overview",
  "productId": "11140495",
  "name": "Werkzeug-Gürteltasche CE-499-2SL",
  "brand": "",
  "price": 20.95,
  "currency": "EUR",
  "availability": "InStock",
  "rating": 5,
  "reviewCount": 1,
  "image": "https://media.cdn.bauhaus/m/179150-1/prod_medium_square.webp",
  "url": "https://www.bauhaus.info/werkzeugguertel/werkzeug-guerteltasche-ce-499-2sl/p/11140495",
  "scrapedAt": "2026-09-21T13:27:19.337Z"
}
```

#### Detail row (specifications trimmed for readability)

```json
{
  "scrapeMode": "detail",
  "productId": "24816535",
  "name": "Skil Akkuschrauber 2636 AD",
  "brand": "Skil",
  "price": 39,
  "currency": "EUR",
  "availability": "InStock",
  "rating": null,
  "reviewCount": null,
  "image": "https://media.cdn.bauhaus/m/541692/prod_large_square.webp",
  "url": "https://www.bauhaus.info/akkuschrauber-akkubohrschrauber/skil-akkuschrauber-2636-ad/p/24816535",
  "scrapedAt": "2026-09-21T13:30:58.089Z",
  "sku": "24816535",
  "ean": "8710364076215",
  "description": "Der Skil Akkuschrauber 2636 AD ist ein besonders handliches und kompaktes Gerät. Er eignet sich ideal zum Aufbauen von Möbeln, für kleine Montagearbeiten und für den mobilen Einsatz in Haushalt und Werkstatt ...",
  "breadcrumbs": [
    "Produkte",
    "Werkzeug & Maschinen",
    "Maschinen",
    "Bohrer & Schrauber",
    "Akkuschrauber & Akkubohrschrauber"
  ],
  "highlights": [
    "30 Tage Rückgabe – auch im Fachcentrum",
    "Kostenloser Rückversand",
    "5 Jahre Garantie für alle elektro- oder motorbetriebenen Geräte"
  ],
  "specifications": {
    "Bohrfutter/Werkzeugaufnahme Elektromaschine": "¼″ Innensechskant",
    "Gewicht (Netto)": "350 g",
    "Kapazität": "1,5 Ah",
    "Max. Drehmoment": "7 Nm",
    "Akkuspannung": "3,6 V",
    "Akkutyp": "Li-Ionen"
  }
}
```

### Key Output Fields

#### Core (both modes)

- `productId` — BAUHAUS product ID, also the trailing number in the product URL
- `name`, `brand` — product title and brand (`brand` is empty on unbranded items)
- `price`, `currency` — numeric price and `EUR`
- `availability` — stock status token (e.g. `InStock`)
- `rating`, `reviewCount` — average stars and number of reviews (`null` when a product has no reviews)
- `image`, `url` — product image and the canonical product URL
- `scrapedAt` — ISO timestamp for when the row was captured

#### Detail mode only

- `sku`, `ean` — stock-keeping unit and the EAN / GTIN barcode
- `description` — the full German product description
- `breadcrumbs` — category path as an array, from `Produkte` down to the leaf category
- `highlights` — USP badge lines (empty array when the product shows none)
- `specifications` — object of German spec label/value pairs (11 to 21 rows, keys depend on the category)

### FAQ

#### Which BAUHAUS site does this cover?

The German storefront at bauhaus.info. Other country domains (such as bauhaus.at or bauhaus.ch) are separate sites and are out of scope.

#### What is the difference between Overview and Detail mode?

Overview reads only the fields on search and category cards (price, brand, rating, availability, image), which makes it fast and cheap. Detail opens each product page as well and adds the SKU, EAN, description, breadcrumbs, highlights, and the full spec table. Use Overview for price tracking and Detail when you need specs or barcodes.

#### What URLs can I paste into `startUrls`?

Category and listing pages of the form `/<category>/c/<id>`, and product pages of the form `/<category>/<product-name>/p/<id>`. Search-result URLs also work and are swept like a keyword. You can mix URLs and keywords in one run.

#### Do I need proxies or an API key?

No. The actor clears the site's bot protection on its own. You do not supply any proxy, key, or login.

#### Are `brand`, `rating`, and `highlights` always filled?

No, and that is expected. Unbranded products return an empty `brand`, products with no reviews return `null` for `rating` and `reviewCount`, and `highlights` is an empty array when BAUHAUS shows no USP badges. The keys are always present so exports stay aligned.

#### What is inside the `specifications` object?

The product's German technical spec table, copied as label/value pairs. Expect 11 to 21 rows on most tools and machines, with keys like `Spannweite Bohrfutter`, `Gewicht (Netto)`, or `Gangzahl`. The exact keys depend on the product category, so treat it as a flexible map rather than a fixed set of columns.

#### Can I scrape private or account-only pages?

No. The actor reads only publicly available product, category, and search pages. Anything behind the BAUHAUS login is out of scope.

#### How am I billed?

This actor uses pay-per-event pricing with three events: Actor Start, one event per Overview product, and one event per Detail product. Detail runs cost more per product because they also open each product page. Exact amounts are on the actor's **Pricing** tab.

#### How many products can I get, and how fast?

`maxItems` caps the total across all keywords and URLs (free runs are capped at 25). Raise `maxConcurrency` (up to 6) for more speed at the cost of more memory.

### Support

Found a bug or need a new field? Open an issue on the actor's [Issues tab](https://apify.com/memo23/bauhaus-product-scraper/issues) or email muhamed.didovic@gmail.com.

### Additional Services & More Scrapers

Need a custom export shape, an extra field parsed from the product page, or scheduled price monitoring? I take tailored work: email muhamed.didovic@gmail.com.

If this actor is useful, you might also like:

- [**Kaufland Seller Contact Scraper**](https://apify.com/memo23/kaufland-sellers-scraper) — sellers, emails, phone, and VAT behind Kaufland.de listings
- [**Google Shopping Scraper**](https://apify.com/memo23/google-shopping-scraper) — product prices and merchants across Google Shopping
- [**zalando.de Scraper**](https://apify.com/memo23/zalando-scraper) — product data from the Zalando fashion catalog
- [**kleinanzeigen.de Scraper**](https://apify.com/memo23/kleinanzeigen-search-scraper-ppe) — listings from Germany's largest classifieds site

Full list at [apify.com/memo23](https://apify.com/memo23).

### 🤖 For AI Agents & LLM Apps

Compact reference for agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/bauhaus-product-scraper`).

**Purpose:** scrape product data from bauhaus.info (German DIY retailer) by keyword, category URL, or product URL.

**Minimal input:**

```json
{
  "keywords": ["akkuschrauber"],
  "scrapeMode": "overview",
  "maxItems": 25
}
```

**Output:** one dataset row per product — `productId`, `name`, `brand`, `price` (number), `currency` (`EUR`), `availability`, `rating`, `reviewCount`, `image`, `url`, `scrapedAt`. Detail mode adds `sku`, `ean`, `description`, `breadcrumbs[]`, `highlights[]` (can be empty), and `specifications{}` (11 to 21 German spec rows, keys vary by category).

**Behaviors an agent should know:**

- Always set `maxItems`; it caps total products across all keywords and URLs. Free runs are capped at 25.
- `keywords` and `startUrls` run together in one dataset. Category and search URLs are swept like keywords; product URLs (`.../p/<id>`) are fetched directly.
- `scrapeMode: "overview"` is the cheapest path. Switch to `"detail"` only when you need specs, EAN, or the description.
- Billing is pay-per-event: one Actor Start, plus one Overview or Detail event per product (see the Pricing tab). `rating` and `reviewCount` are `null` with no reviews; `brand` and `highlights` can be empty.
- Public data only, bauhaus.info only. No login-gated pages, no other country domains.

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by BAUHAUS GmbH & Co. KG or any BAUHAUS group company. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available product, category, and search pages on bauhaus.info. It does not touch authenticated endpoints, account areas, or any content behind the BAUHAUS login. Users are responsible for ensuring their use complies with bauhaus.info's Terms of Service, applicable data-protection law (GDPR, CCPA, and similar), and any contractual obligations of their own organization.

### SEO Keywords

bauhaus scraper, scrape bauhaus, bauhaus.info scraper, Apify bauhaus, german diy scraper, home improvement product scraper, product price scraper, price monitoring data, ean scraper, gtin product data, product specification scraper, competitor price tracking, retail catalog data, pim enrichment, german retail scraper, diy market research, ecommerce product data, product feed scraper

# Actor input Schema

## `keywords` (type: `array`):

Free-text BAUHAUS searches — exactly what you'd type in the site's search bar (e.g. bohrmaschine, akkuschrauber, led lampe). One search per line; all results land in the same dataset.

## `startUrls` (type: `array`):

Direct bauhaus.info URLs. Category listing pages (…/slug/c/10000090) and search pages are swept page by page; product pages (…/slug/name/p/12345678) are scraped directly. Mix freely with keywords.

## `scrapeMode` (type: `string`):

Overview = search fields only (price, rating, brand, image, availability) — fastest and cheapest. Detail = everything in Overview PLUS the full technical-spec table, description, USP highlights and EAN from each product page.

## `sort` (type: `string`):

Native BAUHAUS result ordering.

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

Maximum products to return across all keywords and URLs combined. FREE runs are capped at 25.

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

Parallel fetch lanes. Each lane opens one browser session to clear the site's bot check, then reuses it. Higher = faster but more memory.

## `useApi` (type: `boolean`):

On (default): scrape via the BAUHAUS Android app's JSON API — fast, no Cloudflare challenge, structured data. Falls back to the browser path automatically if the app credentials are revoked. Off: always use the browser + Cloudflare path.

## Actor input object example

```json
{
  "keywords": [
    "bohrmaschine"
  ],
  "scrapeMode": "overview",
  "sort": "relevance",
  "maxItems": 100,
  "maxConcurrency": 4,
  "useApi": true
}
```

# 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 = {
    "keywords": [
        "bohrmaschine"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/bauhaus-product-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 = { "keywords": ["bohrmaschine"] }

# Run the Actor and wait for it to finish
run = client.actor("memo23/bauhaus-product-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 '{
  "keywords": [
    "bohrmaschine"
  ]
}' |
apify call memo23/bauhaus-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/bauhaus-product-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/IEugQw5SBOkdU0jlb/builds/Y1ZXUDfrj36XI8LaO/openapi.json
