# Otto Product Scraper (`kawsar/otto-product-scraper`) Actor

Otto Product Scraper collects Otto.de product listings, including price, discount, brand, rating, stock, and image, so e-commerce teams can track prices and build product feeds without copying anything by hand.

- **URL**: https://apify.com/kawsar/otto-product-scraper.md
- **Developed by:** [Kawsar](https://apify.com/kawsar) (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 $2.99 / 1,000 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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Otto Product Scraper: Extract Product Data from Otto.de

Otto Product Scraper collects product listings from Otto.de and returns them as clean, structured records. Type a keyword like "t-shirt", or paste an Otto listing URL you have already filtered, and it pulls every product on the results with title, brand, price, discount, rating, stock, color, and image. It is for anyone who needs Otto.de product data without copying and pasting by hand.

Otto.de is one of the largest online retailers in Germany, with millions of products across fashion, furniture, electronics, and home goods. This Otto scraper turns any search or category into a spreadsheet you can sort, filter, and track over time.

### What this Otto.de scraper does

- Searches Otto.de by keyword and reads every product on the results
- Scrapes any Otto.de search or category URL you paste in
- Returns full pricing, including the current price, the original price, and the discount percent
- Includes customer ratings, review counts, stock status, and color variants
- Pages through results automatically until it reaches your per-query limit
- Exports to CSV, JSON, Excel, or Google Sheets, and runs on a schedule

### Use cases

- **Price monitoring**: track prices and discounts on Otto.de and react when a competitor changes theirs
- **Stock tracking**: watch availability on specific products or whole categories over time
- **Product feed building**: turn Otto listings into a structured feed for your own catalog or marketplace research
- **Competitor analysis**: compare brands, pricing, and ratings across a category in the German market
- **Reselling and arbitrage**: find discounted products with strong ratings and healthy stock
- **Deal and coupon sites**: surface the biggest markdowns by sorting on the discount percent field
- **SEO and content work**: gather product details and images for comparison pages and buyer guides
- **Market research**: measure how many products a brand has on Otto and where they sit on price

### How to use the Otto Product Scraper

1. Add your scrape.do token as a secret environment variable named `SCRAPE_DO_TOKEN` in the actor settings (see Setup below).
2. Enter one or more search keywords in `searchQueries`, or paste Otto listing URLs into `startUrls`. You can use both at once.
3. Set `maxItems` to how many products you want per query or per URL.
4. Run the actor. Watch the log to see products come in page by page.
5. Export the dataset as CSV, JSON, Excel, or Google Sheets, or pull it from the Apify API.

### How data is collected

The actor reads the product data that Otto.de embeds in its search and category pages, then pages through the results to gather every product. Each product comes back with full pricing and rating data, not just the handful shown before you scroll. Requests are routed through a bypass service so pages load the same way a normal browser sees them.

### Input

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchQueries` | array | (empty) | Keywords to search on Otto.de, one per line. Each becomes an Otto search such as https://www.otto.de/suche/t-shirt/ |
| `startUrls` | array | (empty) | Direct Otto.de search or category URLs, one per line |
| `maxItems` | integer | 100 | Maximum products to collect for each search query and each start URL. The limit is per listing, not a global total |
| `requestTimeoutSecs` | integer | 60 | How long to wait for a single request before giving up |

Provide at least one search query or one start URL. You can combine both in a single run. Because `maxItems` is per listing, a run with two queries and a limit of 100 can return up to 200 products.

#### Example input

```json
{
    "searchQueries": ["t-shirt", "sneaker"],
    "startUrls": ["https://www.otto.de/mode/herrenmode/shirts/"],
    "maxItems": 200
}
````

This run collects up to 200 products for "t-shirt", up to 200 for "sneaker", and up to 200 from the men's shirts category, each tagged with where it came from.

### What data does this actor extract?

The actor stores results in a dataset. Each product record looks like this:

```json
{
    "productId": "S056Y0P8",
    "variationId": "S056Y0P80J0I",
    "productTitle": "TOM TAILOR T-Shirt Herren Printshirt Regular Fit (Vorteilspack, 4-tlg)",
    "brand": "TOM TAILOR",
    "productUrl": "https://www.otto.de/p/tom-tailor-t-shirt-...-S056Y0P8/?variationId=S056Y0P80J0I",
    "imageUrl": "https://i.otto.de/i/otto/1c191365-c97a-5223-b7a6-1e425dec656f",
    "price": 49.99,
    "originalPrice": 69.99,
    "discountPercent": 29,
    "currency": "EUR",
    "onSale": true,
    "isStartingPrice": false,
    "availability": "AVAILABLE",
    "availabilityText": "lieferbar - in 2-3 Werktagen bei dir",
    "ratingValue": 4.5,
    "reviewCount": 35,
    "colorName": "Woodland Green (10373)",
    "colorCount": 8,
    "popular": true,
    "searchQuery": "t-shirt",
    "sourceUrl": "https://www.otto.de/suche/t-shirt/",
    "scrapedAt": "2026-07-05T09:00:48Z"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `productId` | string | Product identifier shared across variants |
| `variationId` | string | Identifier of the listed variant |
| `productTitle` | string | Full product title |
| `brand` | string | Brand name |
| `productUrl` | string | Link to the product detail page |
| `imageUrl` | string | Main product image |
| `price` | number | Current selling price |
| `originalPrice` | number | Recommended retail price before discount |
| `discountPercent` | number | Discount off the original price, in percent |
| `currency` | string | Currency code, EUR for Otto.de |
| `onSale` | boolean | Whether the product is marked on sale |
| `isStartingPrice` | boolean | Whether the price is a "from" price across variants |
| `availability` | string | Stock state such as AVAILABLE |
| `availabilityText` | string | Delivery note shown on the listing |
| `ratingValue` | number | Average customer rating out of 5 |
| `reviewCount` | integer | Number of customer reviews |
| `colorName` | string | Color of the listed variant |
| `colorCount` | integer | Number of color variants |
| `popular` | boolean | Whether Otto flags the product as popular |
| `searchQuery` | string | Query that produced the result |
| `sourceUrl` | string | Listing page the product came from |
| `scrapedAt` | string | UTC timestamp of the scrape |

### Tips for better results

- To scrape a filtered or sorted set, apply the filters on Otto.de first, then copy the URL from your browser into `startUrls`. The actor keeps your sort order and filters.
- Category pages work the same as search pages. Paste any Otto category URL into `startUrls`.
- Keep `maxItems` modest while testing, then raise it once the output looks right. Each page adds about 18 products.
- Sort the dataset by `discountPercent` to find the deepest markdowns, or by `ratingValue` to find the best-reviewed products.

### FAQ

**Does it get the price for every product, or only the first few?**
Every product on the pages it fetches comes back with full price and rating data, including the products that normally load only as you scroll.

**Is maxItems a total for the whole run?**
No. It is a per-listing limit. Each search query and each start URL collects up to `maxItems` products on its own, so more queries means more products.

**Can I scrape a category instead of a search?**
Yes. Paste the category URL into `startUrls`. The actor handles Otto search pages and category pages the same way.

**Can I scrape filtered or sorted results?**
Yes. Filter or sort on Otto.de, then copy the resulting URL into `startUrls`. The actor follows that exact listing.

**How many products can it collect per query?**
Up to the `maxItems` value you set, from 1 to 1000. The actor pages through results until it hits that number or runs out of products.

**In what formats can I export the data?**
Any Apify dataset format works, including CSV, JSON, Excel, and Google Sheets, plus the API.

**Is the data in German?**
Yes. Otto.de is a German store, so titles, colors, and delivery notes come back in German with prices in EUR.

**Can I run this on a schedule?**
Yes. Use Apify Schedules to run it every hour, day, or week and keep your price and stock data current.

### Integrations

Connect Otto Product Scraper with other apps and services using [Apify integrations](https://apify.com/integrations). You can integrate with Make, Zapier, Slack, Airbyte, GitHub, Google Sheets, Google Drive, and many more. You can also use [webhooks](https://docs.apify.com/integrations/webhooks) to trigger actions whenever a run finishes and fresh Otto.de product data is ready.

Start scraping Otto.de product data now to keep prices, stock, and ratings in front of you without the manual work.

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords to search on Otto.de, one per line. Each query is run against the Otto search page (for example 't-shirt' becomes https://www.otto.de/suche/t-shirt/).

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

Direct Otto.de search or category URLs to scrape, one per line. Use this when you already have a filtered or sorted Otto listing URL.

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

Maximum number of products to collect for each search query and each start URL. The limit is applied per listing, not across the whole run, so three queries with a limit of 100 can return up to 300 products. The actor pages through the results until it reaches this number or runs out of products.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for a single page request before giving up.

## Actor input object example

```json
{
  "searchQueries": [
    "t-shirt",
    "sneaker"
  ],
  "startUrls": [
    "https://www.otto.de/suche/t-shirt/",
    "https://www.otto.de/mode/herrenmode/shirts/"
  ],
  "maxItems": 15,
  "requestTimeoutSecs": 60
}
```

# 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 = {
    "searchQueries": [
        "t-shirt"
    ],
    "requestTimeoutSecs": 60
};

// Run the Actor and wait for it to finish
const run = await client.actor("kawsar/otto-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 = {
    "searchQueries": ["t-shirt"],
    "requestTimeoutSecs": 60,
}

# Run the Actor and wait for it to finish
run = client.actor("kawsar/otto-product-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 '{
  "searchQueries": [
    "t-shirt"
  ],
  "requestTimeoutSecs": 60
}' |
apify call kawsar/otto-product-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Otto Product Scraper",
        "description": "Otto Product Scraper collects Otto.de product listings, including price, discount, brand, rating, stock, and image, so e-commerce teams can track prices and build product feeds without copying anything by hand.",
        "version": "0.0",
        "x-build-id": "RbA2pl2i8TVT1aTac"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/kawsar~otto-product-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-kawsar-otto-product-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/kawsar~otto-product-scraper/runs": {
            "post": {
                "operationId": "runs-sync-kawsar-otto-product-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/kawsar~otto-product-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-kawsar-otto-product-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchQueries": {
                        "title": "Search queries",
                        "type": "array",
                        "description": "Keywords to search on Otto.de, one per line. Each query is run against the Otto search page (for example 't-shirt' becomes https://www.otto.de/suche/t-shirt/).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "Direct Otto.de search or category URLs to scrape, one per line. Use this when you already have a filtered or sorted Otto listing URL.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxItems": {
                        "title": "Max items per query",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum number of products to collect for each search query and each start URL. The limit is applied per listing, not across the whole run, so three queries with a limit of 100 can return up to 300 products. The actor pages through the results until it reaches this number or runs out of products.",
                        "default": 15
                    },
                    "requestTimeoutSecs": {
                        "title": "Request timeout (seconds)",
                        "minimum": 10,
                        "maximum": 180,
                        "type": "integer",
                        "description": "How long to wait for a single page request before giving up.",
                        "default": 60
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
