ROSSMANN.de Scraper - Prices, Reviews & Specials
Pricing
from $1.00 / 1,000 product results
ROSSMANN.de Scraper - Prices, Reviews & Specials
Scrape ROSSMANN (rossmann.de) drugstore products: current + original strike-through price with discount, per-unit pricing (per 100ml/kg/piece), brand, stock and promo badges, plus full reviews with rating breakdown. Search by keyword, category or Angebote/online-only specials, or paste links.
Pricing
from $1.00 / 1,000 product results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
9
Total users
4
Monthly active users
2 days ago
Last modified
Categories
Share
ROSSMANN Scraper: Prices, Discounts, Unit Prices & Reviews
ROSSMANN Scraper turns rossmann.de, the German drugstore retailer, into a clean product data feed. Get the current price, the manufacturer's original price with the computed discount when a product is marked down, real per-unit pricing (per litre, per kilogram, or per piece) alongside the pack size, stock and promo badges, and review history (up to 1000 reviews per product) with a complete rating breakdown. Search by keyword, browse a category, or pull the site's own current deals and online-only campaign listings, or paste product, search, category, or specials links directly, then export to JSON, CSV or Excel, or pull results straight into your app through the API.
Why This Scraper?
- Was-price and discount, structured, not scraped from a badge. When a product carries a manufacturer's original price alongside ROSSMANN's own price, both are captured plus the computed discount amount and percentage.
- Real per-unit pricing. Search, category and specials results return a per-litre, per-kilogram, or per-piece price alongside the pack size where the site shows one, with the unit kept separate from the package size so the two are never confused; a pasted product link has no unit price.
- Review history. Overall rating, review count, a complete 1 to 5 star rating breakdown, and individual reviews (20 per product by default, up to 1000 with Max reviews per product) with author, date, rating, title, and body text.
- Two real promotional listings. Current deals ("Angebote") and the online-only campaign, each with thousands of live items, not a single featured product.
- Three ways in. Keyword search, category browse, or paste any product, search, category, or specials link and pagination continues forward automatically.
- Built for schedules. Incremental mode returns only new and changed products on repeat runs against the same search, and Resume continues one interrupted run without paying twice.
- Optional export to your apps. Send results into Notion, Linear, Airtable, or any Apify MCP connector alongside the dataset.
Use Cases
- Price monitoring and repricing: track ROSSMANN's current price, was-price, and discount for your own catalogue over time.
- Deal and promotion tracking: pull every item in Angebote or the online-only campaign to catch markdowns as they go live.
- Review and reputation research: analyze rating distributions and individual review text across a brand or product line.
- Assortment and category research: browse a whole category or brand for range and pricing analysis.
Data You Get
Sample shape: values are illustrative placeholders, not from a live product.
| Field | Example |
|---|---|
productId | 654321 |
ean / sku | 4000000000001 |
name | Sample Repair Shampoo 250ml |
brand | Sample Brand |
url | https://www.rossmann.de/de/sample-repair-shampoo/p/4000000000001 |
price / currency | 2.29, EUR |
originalPrice / discountAmount / discountPercent | 2.99, 0.7, 23.4 |
promotionLabel / isOnSpecial | "Sample promo", true |
unitPrice / unitPriceUnit / unitPriceBasisSize | 9.16, "L", 1 |
packagingAmount / packagingUnit | 250, "ml" |
rating / reviewCount | 4.8, 261 |
badges | ["Sample badge"] |
stockLevelStatus / salesChannel | "IN_STOCK", "BOTH" |
categoryPath | [{"name": "Care & Fragrance", "url": "..."}] (with Fetch full product detail on) |
articleNumber | 654321 (with Fetch full product detail on) |
images | ["https://www.rossmann.de/media-neu/.../sample.png"] (with Fetch full product detail on) |
reviews.averageRating / reviews.totalReviewCount | 4.8, 261 |
reviews.ratingDistribution | [{"rating": 5, "count": 218}, {"rating": 4, "count": 35}, ...] |
reviews.items[] | [{"rating": 5, "title": null, "body": "Sample review text.", "author": "Sample User", "date": "2026-03-23T12:27:40.000+00:00", "isRecommended": true}] |
changeType / changedFields | "UPDATED", ["price"] (incremental mode only) |
firstSeenAt / lastSeenAt | "2026-03-01T00:00:00Z" (incremental mode only) |
With Fetch full product detail on, each product record also carries a full text description, an ingredients list, legal/warning notes, and, for products sold in several variants (for example colours), the sibling variants straight from the product page. Every search, category or specials result additionally carries a thumbnail image and alt text, per-item order limits (minOrderAmount, maxOrderAmount, orderIncrement), an isRateable flag, and the raw disruptors array that badges and the special flag are derived from, plus the raw legalNotes array. A pasted product link's record starts from the site's own search card for that article number (price, unit price, discount, stock, order limits, disruptors, legalNotes, rating) when the site's search finds it, and is completed with the product-page fields (brand, categoryPath, badges, articleNumber, description, ingredients, legalNotesText, images, variants, currency, availability) and reviews. If the search does not return the article, the record carries only productId, ean, sku, url, name and the product-page fields, with the price read from the product page.
How to Use
- Pick a mode:
search(keyword, category, and/or ROSSMANN's own Angebote/online-only specials) orurl(paste links). - For search mode, set a keyword and/or category, and narrow it with brand, rating, and sort filters as needed.
- Turn on Fetch full product detail and/or Fetch reviews for the extra fields you need, and set Max products total to control run size and cost.
- Click Start, then download the dataset as JSON, CSV, or Excel, or read it through the API.
Basic keyword search:
{"mode": "search","searchTerm": "shampoo","maxItems": 20}
Search narrowed by category, brand, rating, and sort order:
{"mode": "search","searchTerm": "shampoo","category": "olcat3_4133099","brands": ["Nivea"],"minRating": 4,"sortBy": "PRICE_ASC","maxItems": 30}
Current deals, with full detail and reviews (up to 1000 per product):
{"mode": "search","specialsCategory": "angebote","fetchDetails": true,"fetchReviews": true,"maxReviewsPerProduct": 0,"maxItems": 50}
Paste product, search, category, or specials links:
{"mode": "url","urls": ["https://www.rossmann.de/de/sample-product-name/p/4000000000001","https://www.rossmann.de/de/search?text=shampoo","https://www.rossmann.de/de/angebote/m/angebote"],"maxItems": 40}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/rossmann-de-scraper").call(run_input={"mode": "search", "searchTerm": "shampoo", "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/rossmann-de-scraper').call({ mode: 'search', searchTerm: 'shampoo', 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.
Max items and max pages
URL mode accepts these link shapes:
| Shape | Example path |
|---|---|
| Keyword search | /de/search?text=nivea%20duschgel |
| Paginated search | /de/search?text=nivea%20duschgel&pageIndex=1 |
| Search with sort | /de/search?text=nivea&sort=sale_price%20asc (the friendly sort=PRICE_ASC, PRICE_DESC, NEWEST, RATING are also accepted) |
| EAN search | /de/search?text=4006000317779 |
| Category (any slug) | /de/pflege-und-duft/c/olcat1_2325036, /de/kategorie/c/olcat1_2325036 |
| Paginated category | /de/pflege-und-duft/c/olcat1_2325036?pageIndex=1 |
| Specials | /de/angebote/m/angebote, /de/angebote/m/neu-im-sortiment, bare /de/angebote, paginated with ?pageIndex=1 |
| Product detail (any slug) | /de/<slug>/p/4006000317779, /de/x/p/4006000317779 |
| Brands index | /de/marken/c/brands is not supported: it is skipped with a warning per link |
Note: in URL mode the URLs field is pre-filled with one example per shape, so running URL mode without editing it scrapes all of them (still capped by Max products total).
Max products total (maxItems) caps the number of products actually returned, and billed, across every search/category/specials/URL entry in one run; 0 means unlimited. Max pages per search (maxPages) caps how many result pages are walked per entry before moving to the next one; leave it empty for no page limit, in which case a run simply stops once Max products total is reached. A run that stops before the natural end of its result set, whether from either cap, also disables Incremental mode's EXPIRED detection for that run.
Resume and recurring updates
Two distinct features, both off by default:
-
Resume (
resumeFromRunId) continues ONE specific interrupted run. Paste the run ID or dataset ID of a previous run and this run returns only products it did not already collect there, no duplicates, no double charges. -
Incremental mode (
incrementalMode) is for scheduling this actor to run the SAME search again and again (for example daily). The actor remembers what it saw last time (keyed on the search/category/specials/URL and detail/review settings, or your ownstateKey) and classifies every product asNEW,UPDATED(withchangedFieldslisting what changed; a field simply not observed on one of the two runs is never treated as a change),UNCHANGED(suppressed, not returned or billed, unlessemitUnchangedis on),REAPPEARED, orEXPIRED.EXPIREDis only produced once a run has scanned the FULL tracked search with no item cap hit and Resume not in effect; a partial scan cannot tell "gone" apart from "not reached yet", so those products simply keep their previous state instead. This also requiresemitExpired.REAPPEAREDcan only happen to a product that an earlier complete scan already markedEXPIREDthis way; a product does not turn up as REAPPEARED just because one run happened to miss it. Every incremental-mode record addschangeType,changedFields,firstSeenAt, andlastSeenAt; these fields are absent from a normal (non-incremental) run. What is compared.UPDATEDmeans price, original price, discount, promotion, unit price, stock status, name, brand, images, descriptions, badges or other product data moved. Ratings, review counts and reviews never make a productUPDATED(they stay in the output), and the order of badges is ignored. Change scope (changeScope) set topriceAndStocknarrows this to price, discount, unit price, stock status and variant price/stock only. Ignore fields when detecting changes (ignoreFieldsForChanges) removes further fields (a dotted path such asvariants.labelremoves that key inside nested lists). Compact UPDATED rows (compactUpdates) return only identifiers, the current price and stock status and the old/new values of what moved (priceChanges,variantChanges); compact rows carry no detail or review data and the detail-enrichment charge is not applied to them. Expire after N missed scans (expireAfterMissedScans, default 1) tombstones a product only after it was missing from that many consecutive complete scans;EXPIREDmeans the product was no longer found in the search results, which a listing change and a delisting both cause, so use the stock status field for availability. A pasted URL that starts at a laterpageIndexis a partial scan and never producesEXPIRED.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset 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 haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where product pages should be created. maxNotifyListingscaps how many items are written to each connector per run; it never affects the dataset.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Aliases for users of other ROSSMANN scrapers
Every product row also carries productName, inStock (true/false from the stock status), imageUrl, category (the last breadcrumb name, when product details are fetched; the full path is categoryPath), productDescription (when details are fetched), discount (percent) and scrapedAt. The inputs searchQuery, categoryUrl, maxResults and proxyConfiguration are accepted as aliases of Search term, Category, Max products total and Proxy. The country input accepts only de; any other value stops the run with a clear message. If the site visibly ignores a brand, minimum-rating or price-sort setting on the first page, the run log says so. Price sorting follows the site's own ordering, so a product with several price points can sit slightly out of order. A keyword that is a brand name (for example nivea) lists that brand's whole range, exactly as the site's own search does.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (keyword/category/specials with filters) or url (paste links). |
searchTerm | string | no default (prefill: nivea duschgel) | Free-text keyword for search mode. |
category | string | no default | A category code (olcat...), the category page URL, or the category name as shown in the site navigation. A name that is not found stops the run with a clear error. Narrows a keyword search, or browses a whole category alone. |
specialsCategory | string | `` (none) | angebote (current deals) or online-only (online-only campaign). |
brands | array | no default (prefill: []) | Only return products from these exact brand names. |
minRating | integer | no default | Only products rated at or above this many stars (1-5). |
sortBy | string | RELEVANCE | RELEVANCE, PRICE_ASC, PRICE_DESC, NEWEST, or RATING. |
urls | array | 11 example links (one per URL shape, see the URL mode table) | Product, search, category, or specials links for URL mode. Filter fields above are ignored in this mode. If you leave the field untouched, URL mode scrapes one example per shape; clear the list and add your own links to scrape only those. |
fetchDetails | boolean | false | Adds the breadcrumb category path, description, ingredients, legal/warning notes, media gallery, sibling variants (colours and similar, when the product has any), and article number from the product page for search/category/specials results. A pasted product link in URL mode always fetches the product page regardless of this toggle; it is billed for detail-enrichment when that page was read or its reviews were fetched. |
fetchReviews | boolean | true | Fetches each product's reviews, up to Max reviews per product (default 20, at most 1000). |
maxReviewsPerProduct | integer | 20 | Cap on reviews per product when Fetch reviews is on; 0 = up to the maximum of 1000 reviews per product; higher values are also limited to 1000. |
maxPages | integer | no default (unlimited when empty) | Stop after this many result pages per search/category/specials/URL entry. |
maxItems | integer | 20 | Hard cap on total products returned across the whole run; 0 = unlimited. |
proxy | object | Apify Proxy (auto) | Connection configuration. |
resumeFromRunId | string | no default | Continue ONE interrupted run: paste its run or dataset ID and already-collected products are skipped, not returned, not charged again. |
incrementalMode | boolean | false | Turn on for daily/recurring monitoring of the same search; classifies each product against the previous run's state. |
stateKey | string | no default | Name or deliberately share an incremental-mode monitoring campaign; auto-derived from the search/detail/review settings when left empty. |
changeScope | string | all | Incremental mode: priceAndStock makes only price, discount and stock changes count as UPDATED. |
compactUpdates | boolean | false | Incremental mode: UPDATED and EXPIRED rows carry only identifiers, current price/stock and old/new values. |
expireAfterMissedScans | integer | 1 | Incremental mode: consecutive complete scans a product must be missing before it is EXPIRED. |
ignoreFieldsForChanges | array | empty | Incremental mode: fields (or dotted paths) that never make a product UPDATED. |
emitUnchanged | boolean | false | Also return (and bill for) products classified UNCHANGED. |
emitExpired | boolean | false | Also return (and bill for) products classified EXPIRED after a complete scan. |
mcpConnectors | array | no default | Optional: send a summary of each product to apps you authorized under Integrations. |
notionParentPageUrl | string | no default | Notion connector only: page under which product pages are created. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. |
searchQuery | string | no default | Alias of searchTerm. |
categoryUrl | string | no default | Alias of category. |
maxResults | integer | no default | Alias of maxItems. |
proxyConfiguration | object | no default | Alias of proxy. |
country | string | de | Only de is accepted; any other value stops the run with a clear message. |
Output Example
Sample shape: values are illustrative placeholders, not from a live product.
{"productId": "654321","ean": "4000000000001","sku": "4000000000001","name": "Sample Repair Shampoo 250ml","brand": "Sample Brand","url": "https://www.rossmann.de/de/sample-repair-shampoo/p/4000000000001","price": 2.29,"currency": "EUR","originalPrice": 2.99,"originalPriceCurrency": "EUR","discountAmount": 0.7,"discountPercent": 23.4,"promotionLabel": "Sample promo","isOnSpecial": true,"badges": ["Sample badge"],"unitPrice": 9.16,"unitPriceCurrency": "EUR","unitPriceUnit": "L","unitPriceBasisSize": 1,"packagingAmount": 250,"packagingUnit": "ml","rating": 4.8,"reviewCount": 261,"stockLevelStatus": "IN_STOCK","salesChannel": "BOTH","reviews": {"averageRating": 4.8,"totalReviewCount": 261,"ratingDistribution": [{ "rating": 5, "count": 218 },{ "rating": 4, "count": 35 },{ "rating": 3, "count": 6 },{ "rating": 2, "count": 2 },{ "rating": 1, "count": 0 }],"items": [{"rating": 5,"title": null,"body": "Sample review text describing the product experience.","author": "Sample User","date": "2026-03-23T12:27:40.000+00:00","isRecommended": true}]}}
Plan Requirement
ROSSMANN protects every page (search, category, specials, product) with a JavaScript access check ("Client Challenge"). Plain HTTP requests, including through a datacenter proxy, only receive that check page and no product data, so this actor opens a real browser session to clear the check and then reads the pages. The first clearance can take a few minutes, so allow a generous run timeout (at least 5 minutes) for small runs.
The connection starts on your selected Apify proxy and escalates through further connections automatically. Residential proxies are not included on Apify free plans: there the run logs "The selected connection is unavailable to this run." and continues on a backup connection where possible, and some pages may still be unavailable. If you supply your own proxy URLs the backup connections are disabled. For large or sustained runs, select the residential proxy group under Connection on a paid plan.
Running this actor bills the pay-per-event charges shown on the actor's Pricing tab: one charge per product returned, plus the detail-enrichment charge, applied once per product as that product is delivered, when full detail and/or reviews were fetched for it. Compact UPDATED rows and unchanged rows that are not returned are not charged.
FAQ
How much does it cost?
You pay per product returned, plus a one-time-per-product surcharge, applied as each product is delivered, whenever full detail and/or the review history was actually fetched for it. fetchReviews defaults to on, so most runs already trigger that surcharge unless you turn it off. The Pricing tab shows the current per-event rates. Use Max products total to cap the cost of any run.
Is it legal to scrape ROSSMANN?
This actor collects only publicly available product data. You are responsible for how you use it: follow ROSSMANN's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices and product facts are generally not protected, 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 billed unless you turn on Emit unchanged.
Why did my run fail with a connection message?
If ROSSMANN's access check cannot be cleared on any available connection, or no results page could be read, the run ends as Failed with a clear status message instead of reporting an empty success. The messages are: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required", "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested Rossmann pages", and "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search." Items collected before a mid-run block are kept. When the backup connection serves the run, the log says "Served over the backup connection (the default connection was unavailable)."
Why did my run return an empty dataset instead of failing?
Only when the pages loaded normally and nothing matched your search, category or filters: that is a genuinely empty result and the run succeeds with an empty dataset. A blocked or unreadable connection never ends as an empty success; it fails with one of the messages above. Two other situations also stop the run: pasting a Resume run or dataset ID that cannot be read, and turning on Resume together with Incremental mode when that same search already has saved incremental state.
Does "Fetch full product detail" apply to a pasted product link?
No. A pasted product link is first looked up by its article number in the site's search to get the listing card (price, stock and so on), at the cost of one extra search request per link, and the product page is then always fetched, whatever the Fetch full product detail toggle says. The detail-enrichment charge applies once to that product when its product page was read or its reviews were fetched. That toggle only controls whether search, category, and specials results also get an extra detail-page fetch on top of their listing-card data.
What's the difference between Resume and Incremental mode?
Resume continues ONE specific interrupted run: paste its run or dataset ID and already-collected products are skipped, no duplicates, no double charges. Incremental mode is for running the SAME search again and again on a schedule; the actor remembers state itself and classifies every product as new, changed, unchanged, reappeared, or expired. Turning on Resume together with Incremental mode for a search that already has saved incremental state is rejected; use one or the other for that search.
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 product summaries into Notion, Linear, or Airtable.
π Want more e-commerce data?
Pair this actor with these related scrapers from the same team:
| π HORNBACH Products, Prices & Reviews Scraper Scrape HORNBACH (hornbach.de) DIY, building & garden products: current + strike-through... | π dm.de Scrape dm-drogerie markt (dm.de) products: current + strike-through Ausverkauf price with... |
| π₯¦ Kaufland.de Scraper Scrape Kaufland.de, Germany's hypermarket and online marketplace: keyword/category/brand... | π OBI.de Scraper Scrape OBI (obi.de) DIY/home-improvement products: current + strike-through original... |
| π Thalia.de Scraper Scrape Thalia.de books, eBooks, audiobooks, toys and stationery. Search by keyword or... | π Douglas Germany Scraper Scrape Douglas.de beauty and fragrance products by keyword, category, brand, or URL... |
π Browse all abotapi scrapers
π¬ Support
- π 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 contact@abotapi.com.
- β Enjoying it? A quick review on the actor page helps other users find it.