# Douglas.de Scraper — German Perfumery & Beauty Products (`studio-amba/douglas-de-scraper`) Actor

Scrape products, prices, ratings, and availability from douglas.de, Germany's #1 perfumery chain. Perfume, skincare, make-up, and health & beauty data by keyword or category.

- **URL**: https://apify.com/studio-amba/douglas-de-scraper.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 $1.20 / 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.
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

## Douglas.de Scraper

Scrape products, prices, ratings, and availability from douglas.de — Germany's #1 perfumery chain, covering perfume, skincare, make-up, and health & beauty.

### What is Douglas Scraper?

Douglas is Germany's largest perfumery and beauty retailer, with hundreds of stores and a catalogue spanning fine fragrance, skincare, make-up, hair care, and personal care from both luxury brands (Chanel, Dior, YSL, Armani) and Douglas's own exclusive lines. This scraper reads the retailer's own server-rendered product data — no HTML guesswork, no brittle CSS selectors — for fast, structured extraction.

If you need reliable perfumery and beauty product data at scale — competitive pricing, brand catalogue tracking, or feeding a comparison platform — this actor delivers clean, structured results.

**Common use cases:**

- **Fragrance market research** — Track pricing, discounts, and new launches across Douglas's perfume catalogue
- **Price benchmarking** — Compare Douglas against dm, Rossmann, Kruidvat, and other drugstore/beauty retailers in our fleet
- **Brand monitoring** — Watch how a specific perfume house or skincare brand is priced and merchandised on Douglas
- **Product catalogue enrichment** — Feed Douglas product data (brand, price, rating, images) into your own comparison or affinity tool
- **Beauty & fragrance analytics** — Study category trends in the German perfumery market

### What data does Douglas Scraper extract?

- **Product name & brand** — Including the brand line/collection where Douglas shows one (e.g. "Chanel Coco Mademoiselle")
- **Price & discount** — Current price, original price, and discount percentage on promoted items
- **Price per unit** — Normalized per-liter/per-kg price, as Douglas is legally required to show
- **Customer ratings** — Average rating and total review count
- **Stock status** — In stock / out of stock (nullable — never guessed when the source doesn't say)
- **Product identifiers** — Variant SKU and base product ID
- **Category** — Category or product-type name (e.g. "Eau de Parfum")
- **Product images** — Direct image URLs

### How to scrape Douglas.de data

The scraper offers two approaches:

#### Search by keyword

Enter any German search term — "parfum", "creme", "shampoo", "mascara", or a brand name like "Chanel". The actor queries Douglas's own search endpoint, the same one the website's search bar uses.

#### Browse by category or brand URL

Paste a douglas.de category or brand URL, e.g. `https://www.douglas.de/de/b/yves-saint-laurent/parfum/damenduefte/b0611_0101`, to scrape everything listed there instead of searching.

#### Input parameters

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `searchQuery` | String | `parfum` | Search keyword (ignored if `categoryUrl` is set) |
| `categoryUrl` | String | — | douglas.de category or brand URL to browse |
| `maxResults` | Integer | 100 | Maximum products to return (hard-capped at 5,000) |
| `inStockOnly` | Boolean | `false` | Off by default. When on, only returns products confirmed in stock |
| `requestDelaySecs` | Integer | 0 | Minimum pause between requests; 0 = full speed with automatic adaptive backoff |
| `brightDataApiKey` | String | — | Optional — use your own Bright Data key instead of the actor's default |
| `proxyConfiguration` | Object | — | Present for schema compatibility; actual fetches run through Bright Data (see below) |

### Output

```json
{
  "name": "Eau de Parfum - 60 ml",
  "brand": "DIOR Sauvage",
  "price": 68.99,
  "originalPrice": 79.99,
  "currency": "EUR",
  "discount": "-14%",
  "pricePerUnit": "1.149,83 €/l",
  "sku": "995604",
  "productId": "3001042193",
  "inStock": true,
  "rating": 4.7,
  "reviewCount": 1021,
  "category": "Eau de Parfum",
  "imageUrl": "https://media.douglas.de/medias/cpPyKK995604-0-dgl-DE.jpg",
  "url": "https://www.douglas.de/de/p/3001042193?variant=995604",
  "scrapedAt": "2026-08-22T09:20:35.589Z"
}
```

### Why Bright Data, not a plain proxy?

douglas.de runs behind Akamai Bot Manager: a plain HTTP request gets an edge-level "Access Denied" before any challenge page is even served, and a bare headless browser hits the same wall. This actor routes requests through Bright Data's Web Unlocker, which clears the Akamai layer server-side and returns the fully rendered listing HTML. One request returns ~48-56 products, so the cost per result stays low — a few tenths of a cent per product.

### How much does it cost?

Each listing page pulls roughly 48-56 products in one Bright Data request. Compute is minimal — no browser rendering happens inside the actor itself.

| Volume | Estimated CU | Estimated Cost |
|--------|-------------|----------------|
| 100 products | ~0.02 CU | ~$0.01 |
| 1,000 products | ~0.15 CU | ~$0.08 |
| 10,000 products | ~1.5 CU | ~$0.80 |

These are Apify platform-cost estimates only. Actual cost also depends on your Apify plan; this actor's own Bright Data usage is covered by the default access included with the run. Usage cost only settles after the run reports **SUCCEEDED** — a run that fails or is aborted mid-way is not charged for items it never wrote.

### Can I integrate?

Export your data as JSON, CSV, Excel, or XML, or pipe it directly into your existing tools:

- **Google Sheets** — Automatically push product data to a shared spreadsheet
- **Webhooks** — Trigger a custom URL when the scrape completes
- **Zapier / Make / n8n** — Connect to thousands of apps without writing code
- **Amazon S3 / Google Cloud** — Dump large datasets straight to cloud storage

### Can I use it as an API?

Yes. Integrate Douglas product data directly into your applications.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("studio-amba/douglas-de-scraper").call(run_input={
    "searchQuery": "parfum",
    "maxResults": 200,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['brand']} — {item['name']}: EUR {item['price']}")
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('studio-amba/douglas-de-scraper').call({
    searchQuery: 'parfum',
    maxResults: 200,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(item => {
    console.log(`${item.brand} — ${item.name}: EUR ${item.price}`);
});
```

### FAQ

**Does Douglas sell only perfume?**
No. Perfume is Douglas's signature category, but the catalogue also covers skincare, make-up, hair care, body care, and men's grooming from both name brands and Douglas's own labels.

**Why is `inStock` sometimes `null` instead of `true` or `false`?**
When Douglas doesn't publish a clear stock status for a listing, the field is left `null` rather than guessed. Treat `null` as "unknown", not as "out of stock".

**How do I get every variant of a product (different sizes)?**
Each size/shade variant is returned as its own row, with a shared `productId` (the base product) and a unique `sku` (the variant). Group by `productId` to see all variants of one product.

**Can I filter by brand?**
There's no dedicated brand filter input, but searching for a brand name (e.g. "Chanel", "Rituals") works well since Douglas's search matches brand names directly. You can also use `categoryUrl` with a brand page like `/de/b/chanel/b0007`.

**How frequently can I run the scraper?**
As often as you need for price-monitoring use cases. Daily or weekly runs are common.

### Tips for effective Douglas data extraction

1. **Use category URLs for a stable, bounded set** — a brand or sub-category page (e.g. all Yves Saint Laurent women's fragrances) gives a fixed, predictable product list, unlike a broad keyword search.
2. **Pair with dm-scraper and Rossmann Scraper** — Douglas, dm, and Rossmann together cover most of the German drugstore and beauty retail landscape; join on brand and product name for cross-retailer pricing.
3. **Watch the `discount` field for promo tracking** — Douglas runs frequent percentage-off promotions, especially on fragrance.
4. **Use `pricePerUnit` for fair size comparison** — perfume and skincare come in many pack sizes; the per-unit price normalizes that.

### Limitations

- Search result ordering can shift slightly between requests (site-side relevance ranking), so very large `maxResults` pulls on a broad keyword may return fewer unique products than requested — the actor de-duplicates automatically and stops cleanly rather than returning repeats. Category and brand URLs do not have this issue.
- No ingredient lists or full product descriptions — this actor extracts commerce fields (name, brand, price, stock, rating), not marketing copy.
- Germany (douglas.de) only. Douglas's other European storefronts use the same platform family but are out of scope for this actor.
- No purchase history, loyalty pricing, or store-specific stock data — this reads the public online catalogue only.

### Other pharmacy & drugstore scrapers

Need drugstore, pharmacy, or beauty data from more sources? Explore our full collection:

- [dm Scraper](https://apify.com/studio-amba/dm-scraper) — Germany's largest drugstore chain
- [Rossmann Scraper](https://apify.com/studio-amba/rossmann-scraper) — German/Polish/Hungarian/Turkish drugstore chain
- [Kruidvat Scraper](https://apify.com/studio-amba/kruidvat-scraper) — Belgian/Dutch drugstore chain
- [Shop Apotheke Scraper](https://apify.com/studio-amba/shopapotheke-scraper) — Europe's leading online pharmacy (DE/AT/CH/BE/FR/IT)
- [Farmaline Scraper](https://apify.com/studio-amba/farmaline-scraper) — Belgium's largest online pharmacy
- [Matas Scraper](https://apify.com/studio-amba/matas-scraper) — Denmark's leading beauty and pharmacy retailer

### Your feedback

Found a bug? Need a new feature? Want help building a pipeline on top of Douglas data? [Open an issue](https://console.apify.com/actors/studio-amba/douglas-de-scraper/issues) or contact us on Apify. We read every message and ship fixes fast.

# Actor input Schema

## `searchQuery` (type: `string`):

German keyword to search the Douglas catalogue (e.g. 'parfum', 'creme', 'shampoo', 'mascara'). Ignored if categoryUrl is set. Leave empty to use the default.

## `categoryUrl` (type: `string`):

A douglas.de category or brand URL to browse instead of searching, e.g. https://www.douglas.de/de/b/yves-saint-laurent/parfum/damenduefte/b0611\_0101

## `maxResults` (type: `integer`):

Maximum number of products to scrape. Hard-capped at 5000 per run.

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

Off by default. When enabled, only returns products currently marked in stock (products with unknown stock status are still excluded, since 'unknown' is not the same as 'in stock').

## `requestDelaySecs` (type: `integer`):

Minimum pause between page requests. Raise this (5-15s) for large runs if you hit throttling. 0 = full speed with automatic adaptive backoff.

## `brightDataApiKey` (type: `string`):

Optional. Your own Bright Data Web Unlocker API key. Normally not needed — the actor ships with access. Only set this to route traffic through your own Bright Data account.

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

Proxy settings. douglas.de is fetched through the Bright Data Web Unlocker (Germany) to clear Akamai bot protection, so this can be left at its default.

## Actor input object example

```json
{
  "searchQuery": "parfum",
  "maxResults": 20,
  "inStockOnly": false,
  "requestDelaySecs": 0,
  "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 = {
    "searchQuery": "parfum",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "DE"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/douglas-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 = {
    "searchQuery": "parfum",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "DE",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/douglas-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 '{
  "searchQuery": "parfum",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}' |
apify call studio-amba/douglas-de-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/douglas-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/bXqSf54qop3POIHdl/builds/iOeWmZZCoDp0BSXpZ/openapi.json
