OTTO.de Scraper - Products, Prices, Variants & Reviews
Pricing
from $1.20 / 1,000 product results
OTTO.de Scraper - Products, Prices, Variants & Reviews
Scrape OTTO.de products by search or URL. Extract prices, discounts, variants, availability, brand, seller, EAN/GTIN, specifications, categories, and customer reviews across fashion, furniture, electronics, and homeware.
Pricing
from $1.20 / 1,000 product results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
7
Total users
4
Monthly active users
5 days ago
Last modified
Categories
Share
OTTO Scraper: Prices, Discounts, Variants and Reviews
OTTO Scraper turns OTTO into structured product data. Search by keyword or category, or paste product and listing links directly, and get the current price, the strike-through original price with the site's discount percent when a product is marked down, colour variants with their own variant id and colour code, brand, seller identity when detail is fetched, and customer reviews for fashion, furniture, technik and household appliances. Export the results to JSON, CSV or Excel, or pull them straight into your app through the API.
Why This Scraper?
- Price and discount, already structured. When a product is marked down, the current price, the original price, the site's discount percent and its own promo label all come from one listing fetch, at no extra cost.
- Colour variant matrix. Every colour option a product offers is returned with its own variant id and colour code.
- Specials, first class.
specialsOnlynarrows any search to only products currently showing a reduced price, andsortBy: DISCOUNTsurfaces the biggest reductions first, both driven by the site's own live discount signal. - Seller transparency. With Fetch full product detail on, the seller is captured, distinguishing OTTO itself from third-party marketplace partners, with the partner's own identifier.
- Native review history. Overall rating, review count, and individual reviews (up to Max reviews per product, 10 by default, or every review the page renders with it set to 0) with author, location, date, star rating, verified-purchase flag, body text and helpful-vote counts, sourced directly from the product page.
- Rich detail on demand. Full breadcrumb category path, flattened technical specifications (these vary per product category), EAN/GTIN/SKU, the full image gallery and the return policy.
- Built for schedules. Incremental mode returns only new and changed products on recurring runs, Resume continues one interrupted run without double charges, and a long run survives an Apify platform interruption through its own checkpoint.
Use Cases
- Deal hunters and price trackers: monitor a category or brand for the current price, the original price and the discount percent so you can time a purchase or a repricing decision.
- Marketplace and assortment research: compare OTTO's own listings against third-party marketplace partners selling the same or similar products, and see who actually fulfils each one.
- Review and reputation analysis: build a dataset of native customer reviews per product or category for sentiment, quality, or complaint analysis.
- Catalogue monitoring: track new, updated and removed products in a search or category on a recurring schedule.
- Product data enrichment: pull structured specs, EAN/GTIN/SKU, images and return policy into your own catalogue or PIM system.
Data You Get
| Field | Example |
|---|---|
productId / variationId / articleNumber | "S0AB12CD" / "S0AB12CD4XYZ" / "S0AB12CDKIE" |
name | "Sample Brand Ecksofa, Sofa L-Form, mit Schlaffunktion" |
brand | "Sample Brand" |
category / breadcrumb | "Ecksofas" / [{"name": "Möbel", "url": "..."}, {"name": "Sofas", "url": "..."}, {"name": "Ecksofas", "url": "..."}] |
url | "https://www.otto.de/p/sample-ecksofa-S0AB12CD/" |
price / currency | 799.00 / "EUR" |
originalPrice / discountPercent / promoLabel | 1599.00 / 50 / "-50%" |
isOnSpecial | true |
availability / availabilityText | "AVAILABLE" / "lieferbar in 5 Wochen" |
rating / reviewCount | 4.5 / 26 |
variants[] | [{"variationId": "S0AB12CD4XYZ", "color": "Khaki", "hexCode": "BEB2A9", "selected": true}] |
image / images[] | "https://sample.example/img1.jpg" / ["https://sample.example/img1.jpg", "https://sample.example/img2.jpg"] |
ean / gtin / sku | "4068181820000" / "4068181820000" / "S0AB12CD4XYZ" |
specs | {"Höhe": "85 cm", "Breite": "289 cm", "Polsterung": "Schaumstoff", "Design": "Modern"} (flattened, fields vary per category) |
seller | {"name": "Sample Home Brands GmbH", "partnerId": "1000000", "sellerType": "MARKETPLACE_PARTNER"} |
returnPolicy | {"days": 30, "freeReturn": true} |
reviews.averageRating / reviews.reviewCount | 4.5 / 26 |
reviews.items[] | [{"reviewId": "sample-uuid", "author": "Sample R.", "location": "Sample City", "date": "11.04.2026", "rating": 5, "verifiedPurchase": true, "title": null, "body": "Sample review text.", "helpfulVotes": 5, "helpfulVotesTotal": 5, "variantPurchased": "Farbe: Khaki", "seller": "Sample Home Brands GmbH"}] |
changeType / changedFields / firstSeenAt / lastSeenAt | "UPDATED" / ["price"] / "2026-08-01T00:00:00Z" / "2026-08-17T00:00:00Z" (incremental mode only) |
Sample shape: values above are illustrative placeholders, not from a live product.
category, breadcrumb, specs, seller, ean, gtin, sku and returnPolicy are only populated when full product detail is fetched, either because you turned on Fetch full product detail, or because the record came from a pasted product URL, which always fetches its own detail page.
How to Use
- Pick a mode:
search(keyword or category name) orurl(paste product, search or category links). - Fill in the field for that mode, and switch on the narrowing filters or detail toggles you need.
- Set Max products total to control run size and cost, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it through the API.
Keyword search, first page, with reviews (the defaults):
{"mode": "search","searchTerm": "ecksofa","maxItems": 20}
Category-style search, filtered to specials and sorted by biggest discount:
{"mode": "search","searchTerm": "sofas","specialsOnly": true,"sortBy": "DISCOUNT","maxItems": 50,"maxPages": 5}
Full product detail and reviews for a pasted product link:
{"mode": "url","urls": ["https://www.otto.de/p/sample-ecksofa-S0AB12CD/"],"fetchDetails": true,"fetchReviews": true,"maxReviewsPerProduct": 0}
Paste a listing link and keep paginating forward:
{"mode": "url","urls": ["https://www.otto.de/suche/ecksofa/"],"maxItems": 100,"maxPages": 10}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/otto-de-scraper").call(run_input={"mode": "search", "searchTerm": "ecksofa", "maxItems": 20})for product in client.dataset(run["defaultDatasetId"]).iterate_items():print(product["name"], product["price"], product["currency"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/otto-de-scraper').call({ mode: 'search', searchTerm: 'ecksofa', maxItems: 20 });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Full-catalogue walk and Max products
Max pages per search (maxPages) is 0 (unlimited) by default: a run walks every result page for a search, category or pasted listing URL until the site's own last page, Max products total (maxItems), or a page that adds no new products, whichever comes first. Set maxPages to a positive number only if you want to cap the number of page fetches directly.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted run: paste its run or dataset id and the actor skips every product already collected there, so this run only returns new products, a delta, instead of a full re-scrape. - Incremental mode (
incrementalMode) is for scheduled runs over the same search or URL set. Each product is classifiedNEW,UPDATED(withchangedFields), orUNCHANGED(suppressed and not billed unlessemitUnchangedis on).EXPIREDdetection only runs at all whenemitExpiredis on, and only produces rows on a run that fully scanned the tracked search or URL set: not capped bymaxItemsormaxPages, not usingresumeFromRunId, no failed page along the way, and at least one product scanned; turn onemitExpiredto have those rows returned and billed.REAPPEAREDonly appears for a product that an earlier complete-scan run withemitExpiredon had already markedEXPIREDand that has now been found again.stateKeynames or shares the stored state; leave it empty and the actor derives one automatically from the search and detail settings. With incremental mode off, output is exactly as before. - A long run also checkpoints its own progress: if it is interrupted by an Apify platform migration, or resumed with the Resurrect button, it picks up where it left off with no duplicate products and no double charges.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, through Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset itself is never changed.
What gets written to the connector: a condensed, human-readable summary of each product, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. If the picker is empty, you have not authorized a connector yet.
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's own MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (keyword or category) or url (paste product, search, or category links). |
searchTerm | string | none (prefill: "ecksofa") | Keyword or category name to search (search mode only). |
urls | array | none (prefill: one sample search URL) | Product, search, or category page URLs to scrape (url mode only). Pagination continues forward automatically. |
specialsOnly | boolean | false | Keep only currently-discounted products. Applies to a keyword search and a pasted search or category URL. Also evaluated on a single pasted product URL, but the detail page never exposes special-offer status, so it always excludes a pasted product link, on special or not; leave it off when pasting a single product URL. |
brands | array | none (prefill: []) | Exact brand names to keep. Applies to a keyword search, a pasted search or category URL, and a single pasted product URL. Leave empty for all brands. |
minRating | integer | none | 1 to 5, minimum rating to keep. Applies to a keyword search, a pasted search or category URL, and a single pasted product URL. |
minPrice | number | none | Minimum price in EUR to keep. Applies to a keyword search, a pasted search or category URL, and a single pasted product URL. |
maxPrice | number | none | Maximum price in EUR to keep. Applies to a keyword search, a pasted search or category URL, and a single pasted product URL. |
sortBy | string | RELEVANCE | RELEVANCE, PRICE_ASC, PRICE_DESC, DISCOUNT, NEWEST, or RATING. Applies to a keyword search and a pasted search or category URL; has no effect on a single pasted product URL, since there is nothing to reorder. |
fetchDetails | boolean | false | Fetch full product detail for a product found through search or a listing: breadcrumb, flattened specs, seller identity, EAN/GTIN/SKU, return policy and full image gallery. A pasted product URL always includes these fields regardless of this toggle. |
fetchReviews | boolean | true | Fetch native customer reviews. Products with no reviews return an empty list. |
maxReviewsPerProduct | integer | 10 | Cap on reviews fetched per product when fetchReviews is on. 0 returns all the reviews the product page renders. |
maxPages | integer | 0 | Stop after this many result-page fetches per search, category or URL entry. 0 means unlimited: the run walks the full catalogue and stops at Max products total instead. |
maxItems | integer | 20 | Hard cap on total products returned across every search, category, or URL entry. 0 means unlimited (still bounded by Max pages per search). |
resumeFromRunId | string | none | Paste a previous run id (or its dataset id) to continue that run: products already collected there are skipped, so this run only returns new products. Leave empty for a normal run. |
incrementalMode | boolean | false | Turn on for recurring monitoring of the same search or URL set. See "Resume and recurring updates" above for exactly how NEW, UPDATED, UNCHANGED, REAPPEARED and EXPIRED are decided. |
stateKey | string | none | Optional, incremental mode only. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to derive a key automatically. |
emitUnchanged | boolean | false | Incremental mode only. Also return, and bill, products that have not changed since the last run. |
emitExpired | boolean | false | Incremental mode only. Also return, and bill, products that were present in a previous run but are no longer found. Only produced once a run has fully scanned the tracked search or URL set. |
proxy | object | Apify Proxy | Connection settings for the product listing and search fetch. Product detail and review fetches (on by default) always use a residential connection at extra cost, regardless of this setting. |
mcpConnectors | array | none | Optional: send a summary of each product to apps you authorized under Integrations. |
notionParentPageUrl | string | none | Notion connector only: page under which item pages are created. |
maxNotifyListings | integer | 50 | Cap on items exported to each connector per run. Does not affect the dataset. |
Output Example
{"productId": "S0AB12CD","variationId": "S0AB12CD4XYZ","articleNumber": "S0AB12CDKIE","name": "Sample Brand Ecksofa, Sofa L-Form, mit Schlaffunktion","brand": "Sample Brand","category": "Ecksofas","url": "https://www.otto.de/p/sample-ecksofa-S0AB12CD/","price": 799.00,"currency": "EUR","originalPrice": 1599.00,"discountPercent": 50,"isOnSpecial": true,"availability": "AVAILABLE","rating": 4.5,"reviewCount": 26,"variants": [{ "variationId": "S0AB12CD4XYZ", "color": "Khaki", "hexCode": "BEB2A9", "selected": true }],"image": "https://sample.example/img1.jpg","specs": { "Höhe": "85 cm", "Breite": "289 cm", "Polsterung": "Schaumstoff" },"seller": { "name": "Sample Home Brands GmbH", "partnerId": "1000000", "sellerType": "MARKETPLACE_PARTNER" },"returnPolicy": { "days": 30, "freeReturn": true },"reviews": {"averageRating": 4.5,"reviewCount": 26,"items": [{"reviewId": "sample-uuid","author": "Sample R.","location": "Sample City","date": "11.04.2026","rating": 5,"verifiedPurchase": true,"body": "Sample review text.","helpfulVotes": 5,"helpfulVotesTotal": 5,"variantPurchased": "Farbe: Khaki","seller": "Sample Home Brands GmbH"}]}}
Sample shape: values above are illustrative placeholders, not from a live product.
Plan Requirement
The default connection setting handles the product listing and search fetch on every plan. Fetching full product detail and reviews (on by default) always uses a residential connection at extra cost, regardless of the connection setting you choose, because the product page can occasionally decline an automated request without one. For large search runs, picking the residential group under Connection also gives the listing fetch more headroom.
FAQ
How much does it cost?
You pay per product returned, with the detail and review enrichment billed only once per product, only when it is actually fetched and kept. The Pricing tab shows the current rates. Use Max products total to cap the cost of any run.
Is it legal to scrape OTTO?
This actor collects only publicly available product data. You are responsible for how you use it: follow OTTO's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices, availability and specifications are generally facts, but product photos and review text may be subject to third-party rights.
Can I get only new or changed products on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated products, and unchanged ones are not returned or billed unless you turn that on too.
Why did specialsOnly return nothing for my pasted product link?
The product detail page does not expose the same special-offer signal a listing card does, so Specials / offers only always excludes a single pasted product URL, whether or not that product is actually discounted. Leave it off when pasting one product link, and use it on a search or category URL or link instead.
Why did my run fail instead of returning an empty dataset?
If the site's response no longer matches any shape this actor recognizes, the run fails with a clear message instead of quietly returning zero products, so "no results for this search" is never confused with "the extraction broke". A genuinely empty search still completes normally with zero items. If the connection is repeatedly refused partway through, the run keeps everything already collected and stops cleanly rather than retrying forever.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
🔗 Want more fashion data?
Pair this actor with these related scrapers from the same team:
| 🔌 MediaMarkt Germany Scraper Scrape MediaMarkt.de products by keyword or URL. Extract current and original prices... | 🔌 Boulanger.com Scrape Boulanger (boulanger.com) electronics and home-appliance products: current price... |
| 🔌 Fnac Scraper Scrape Fnac (fnac.com) products: current price plus strike-through discount, colour/model... | 🔌 MediaMarkt.es Scraper Scrape MediaMarkt Spain (mediamarkt.es) products: current price, strike-through original... |
| 🔌 PcComponentes Scraper Scrape PcComponentes (pccomponentes.com) products: current price plus strike-through... | 🛒 dm.de Scrape dm-drogerie markt (dm.de) products: current + strike-through Ausverkauf price with... |
💬 Support & custom scrapers
- 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- 🛠️ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.