dm.de - Prices, Offers, Unit Price & Reviews avatar

dm.de - Prices, Offers, Unit Price & Reviews

Pricing

from $1.00 / 1,000 product results

Go to Apify Store
dm.de - Prices, Offers, Unit Price & Reviews

dm.de - Prices, Offers, Unit Price & Reviews

Scrape dm-drogerie markt (dm.de) products: current + strike-through Ausverkauf price with discount, per-unit pricing (per 100ml/kg/piece), brand incl. dm own-brands, EAN, ingredients, pack-size variants, and full reviews with rating breakdown. Search or paste links.

Pricing

from $1.00 / 1,000 product results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

6

Total users

5

Monthly active users

10 days ago

Last modified

Share

dm.de Scraper: Prices, Discounts, Unit Pricing & Reviews

dm.de Scraper turns dm-drogerie markt (dm.de), Germany's drugstore and personal-care retailer, into a clean product data feed. Search by keyword, by a real dm.de category, or by the site's own currently-reduced Ausverkauf items, or paste product and listing links directly. Every record carries the current price, the strike-through original price with a computed discount when a product is marked down, per-unit pricing (for example price per 100 ml or per kg) where the site shows it, and a full customer review history with a rating breakdown. Export to JSON, CSV or Excel, pull results straight into your app through the API, or pipe them into Notion, Linear or Airtable.

Why This Scraper?

  • Was-price and discount, structured, not scraped from a badge. When a product carries a reduced original price, both prices are captured along with the computed discount amount and percentage.
  • Real per-unit pricing. Bodycare, food, and household products return their price per 100 ml, 100 g, kg, or piece separately from the pack price, exactly as the site itself breaks it down.
  • Ausverkauf, first class. A specialsOnly toggle narrows any search or category listing to dm's own live clearance/sellout feed, the site's own queryable discount signal, not a guessed category.
  • Full review history. Overall rating, review count, a full 1 to 5 star rating breakdown, and every individual review with author, date, rating, title, and body text.
  • Rich detail on demand. Full breadcrumb category path, flattened product information (description, ingredients, usage notes, which varies per category and is never hardcoded), pack-size variants with their own price and EAN, brand image, and online/store availability, plus coverage of every brand dm carries, including its own private-label lines alongside national brands.
  • Two ways in, one set of filters. Keyword or category search, or paste any product/listing link and continue pagination automatically. Brand, rating, price range, Ausverkauf, and sort narrow the results either way.
  • Resume and recurring updates. Turn on Incremental mode to get only new and updated products on a scheduled re-run of the same search (plus reappeared ones if you also track expiry), see "Resume and recurring updates" below for exactly how that works.

Use Cases

  • Price and discount tracking: monitor Ausverkauf and clearance prices, plus per-unit pricing, across brands to catch genuine markdowns.
  • Retail intelligence: benchmark dm's own private-label and national-brand pricing over time for competitor research.
  • Review and reputation analysis: study rating breakdowns and review text for personal-care and household products.
  • Catalog and assortment research: build category-level snapshots of the range, including pack sizes and ingredient lists.
  • Shopping tools and feeds: feed a price-comparison site, browser extension, or shopping assistant with structured product and pricing data.

Data You Get

Sample shape: values below are entirely invented placeholders, not from a live product.

FieldExample
productId / sku"2938471"
ean"4009876543219"
name"Feuchtigkeitscreme Ringelblume 50 ml"
brand"GartenPflege"
category / categoryPath"Gesichtspflege", ["Pflege & Parfum", "Gesichtspflege", "Cremes & Masken"]
url"https://www.dm.de/p/d/2938471/feuchtigkeitscreme-ringelblume"
price / currency5.29, "EUR"
originalPrice / discountAmount / discountPercent6.99, 1.7, 24.3
isOnSpecial / promoLabeltrue, "Ausverkauf"
unitPrice / unitPriceBasis / packSize10.58, "100 ml", "50 ml"
rating / reviewCount4.2, 63
onlineAvailable / onlineAvailabilityStatus / storeAvailabilityStatustrue, "Lieferbar", "Im Markt vorrätig"
image / images"https://www.dm.de/pics/p2938471.jpg", ["https://www.dm.de/pics/p2938471.jpg"]
description / ingredientsfull text fields
productDetails{"Produktmerkmale": "...", "Verwendungshinweise": "..."} (flattened per category)
variants[{"productId": "2938473", "ean": "4009876543226", "label": "150 ml", "isSelected": false}]
isPharmacyfalse
reviews.averageRating / reviews.totalReviewCount4.2, 63
reviews.ratingDistribution[{"rating": 5, "count": 36}, {"rating": 4, "count": 14}, {"rating": 3, "count": 6}, {"rating": 2, "count": 3}, {"rating": 1, "count": 4}]
reviews.items[][{"rating": 5, "title": "Fictional title text", "body": "Fictional review body text.", "author": "Fictional Reviewer", "date": "2026-03-05T10:15:00.000Z", "isRecommended": true, "verifiedPurchaser": true}]

Any record carries priceExclVat (the VAT-exclusive price) when the site shows a net price. Detail-enriched records also carry brandImage and categoryCodes when the site provides them. When incrementalMode is on, every returned record also carries changeType (NEW, UPDATED, UNCHANGED, REAPPEARED, or EXPIRED), changedFields (non-empty only for UPDATED), firstSeenAt, and lastSeenAt, see "Resume and recurring updates" below for exactly when each value is produced.

How to Use

  1. Pick a mode: search (keyword, category, and/or Ausverkauf) or url (paste product or listing links).
  2. Fill in the fields for that mode, and set the shared filters, brand, rating, price range, Ausverkauf, and sort, that apply to both modes.
  3. Turn on Fetch full product detail and/or Fetch reviews for full detail and review history, then set Max products total to control run size and cost.
  4. Click Start, then download the dataset as JSON, CSV, or Excel, or read it through the API.

Keyword search, first page, with reviews (default):

{
"mode": "search",
"searchTerm": "bodylotion",
"maxItems": 20
}

Category browse, filtered to a brand and only currently-reduced Ausverkauf items:

{
"mode": "search",
"searchTerm": "pflege-und-parfum/koerperpflege/bodylotion-und-hautcreme",
"brands": ["Balea"],
"specialsOnly": true,
"sortBy": "PRICE_ASC",
"maxItems": 50,
"maxPages": 5
}

Full product detail and reviews for a pasted product link:

{
"mode": "url",
"urls": ["https://www.dm.de/p/d/<product-id>/<product-slug>"],
"fetchDetails": true,
"fetchReviews": true,
"maxReviewsPerProduct": 0
}

Paste a listing link and keep paginating forward:

{
"mode": "url",
"urls": ["https://www.dm.de/search?query=bodylotion"],
"maxItems": 100,
"maxPages": 10
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/dm-de-scraper").call(run_input={"mode": "search", "searchTerm": "bodylotion", "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/dm-de-scraper').call({ mode: 'search', searchTerm: 'bodylotion', 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.

Resume and recurring updates

There are two different things here. Resume (resumeFromRunId) continues one specific interrupted or previous large crawl: paste a run id or dataset id and this run skips products already collected there, returning only the remaining new products. Incremental mode (incrementalMode) is for running the same search again and again on a schedule, for example daily: the actor remembers the previous run of that search by itself, so you never paste a run id.

The first run for a search returns everything as NEW. Later runs return only NEW, UPDATED, and REAPPEARED products by default, duplicates and unchanged products are suppressed and not billed. REAPPEARED only appears for a product that a previous run had already marked EXPIRED, and that marking itself only happens once emitExpired was on and a run completed a full, uncapped, non-resumed scan of the same search, and the product has now been seen again. Changes to reviews, rating, or reviewCount alone never mark a product UPDATED; they are still returned on every record. Turn on emitUnchanged or emitExpired only when you also want those rows returned, and billed for. Set stateKey to name or deliberately share a monitoring campaign, or leave it empty to let the actor derive one automatically from the search and detail/review settings. Combining resumeFromRunId with incrementalMode on a brand-new state key bootstraps the incremental baseline from that resume dataset instead of starting empty.

Send results into your apps (MCP connectors)

Optionally pipe results into the apps you already use through Model Context Protocol (MCP) connectors. Authorize a connector once under Apify, Settings, Integrations, then select it in the mcpConnectors field. Each connector receives a condensed, human-readable summary per product, name plus key fields, while the complete record always stays in the Apify dataset. For Notion, set notionParentPageUrl to the page the item pages should be created under, and use maxNotifyListings to cap how many items are exported per connector per run. Supported connectors: Notion, Linear, Airtable, and Apify. Leave the field empty to skip, it never changes the dataset output.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (keyword, category, and/or Ausverkauf) or url (paste product or listing links).
searchTermstringnone (prefill shampoo)Keyword or a real dm.de category path (search mode only).
urlsarraynone (prefill one sample URL)Product or listing URLs to scrape (url mode only).
specialsOnlybooleanfalseKeep only products currently in dm's Ausverkauf/clearance feed (applies to both search and url mode; has no effect on a single pasted product URL, there is no listing to narrow).
brandsarraynone (prefill empty)Exact brand names to keep (applies to both search and url mode, including a single pasted product URL).
minRatingintegernone1 to 5, minimum rating to keep (applies to both search and url mode, including a single pasted product URL).
minPricenumbernoneOnly return products priced at or above this amount, in euros.
maxPricenumbernoneOnly return products priced at or below this amount, in euros.
sortBystringRELEVANCERELEVANCE, PRICE_ASC, PRICE_DESC, NEWEST, or RATING (applies to both search and url mode; has no effect on a single pasted product URL, there is no listing to reorder).
fetchDetailsbooleanfalseFetch full product detail (breadcrumb, description, ingredients, pack-size variants, brand image, availability). A pasted product URL always fetches detail regardless of this toggle, since a bare product page has no listing card to fall back on, and is charged the enrichment surcharge when the detail or review fetch succeeds.
fetchReviewsbooleantrueFetch full review history. Shares one enrichment surcharge with fetchDetails, charged at most once per product, and only when at least one of the two fetches actually succeeds.
maxReviewsPerProductinteger20Cap on reviews per product; 0 = all.
maxPagesinteger0Cap on result pages per search/category/URL entry; 0 = unlimited, the run stops at Max products total instead.
maxItemsinteger20Cap on total products returned; 0 = unlimited.
resumeFromRunIdstringnoneContinue one specific previous run/dataset: products already collected there are skipped, so this run only returns new products. For recurring monitoring of the same search, use Incremental mode instead, see "Resume and recurring updates" above.
incrementalModebooleanfalseDaily/recurring monitoring of this same search. First run returns everything as NEW; later runs return only NEW/UPDATED by default (REAPPEARED needs emitExpired too, plus a prior full, uncapped scan). See "Resume and recurring updates" above.
stateKeystringnoneIncremental mode only. Name this monitoring campaign, or deliberately share state across differently-configured runs. Leave empty to derive one automatically.
emitUnchangedbooleanfalseIncremental mode only. Also return products unchanged since the last run, marked UNCHANGED. Adds and bills extra rows you already have.
emitExpiredbooleanfalseIncremental mode only. Also return products from a previous run no longer found, marked EXPIRED, once a run has fully scanned the search, not capped, not a resume. Adds and bills extra synthetic rows.
proxyobjectApify Proxy (useApifyProxy: true)Connection settings.
mcpConnectorsarraynoneOptional MCP connectors to export results into (Notion, Linear, Airtable, Apify).
notionParentPageUrlstringnoneNotion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap on items exported to each connector per run. Does not affect the dataset.

Output Example

Sample shape: values below are entirely invented placeholders, not from a live product.

{
"productId": "2938471",
"sku": "2938471",
"ean": "4009876543219",
"name": "Feuchtigkeitscreme Ringelblume 50 ml",
"brand": "GartenPflege",
"category": "Gesichtspflege",
"url": "https://www.dm.de/p/d/2938471/feuchtigkeitscreme-ringelblume",
"price": 5.29,
"currency": "EUR",
"originalPrice": 6.99,
"discountAmount": 1.7,
"discountPercent": 24.3,
"isOnSpecial": true,
"promoLabel": "Ausverkauf",
"unitPrice": 10.58,
"unitPriceBasis": "100 ml",
"packSize": "50 ml",
"rating": 4.2,
"reviewCount": 63,
"onlineAvailable": true,
"onlineAvailabilityStatus": "Lieferbar",
"storeAvailabilityStatus": "Im Markt vorrätig",
"isPharmacy": false,
"priceExclVat": 4.94,
"image": "https://www.dm.de/pics/p2938471.jpg",
"images": ["https://www.dm.de/pics/p2938471.jpg"],
"reviews": {
"averageRating": 4.2,
"totalReviewCount": 63,
"ratingDistribution": [
{ "rating": 5, "count": 36 },
{ "rating": 4, "count": 14 },
{ "rating": 3, "count": 6 },
{ "rating": 2, "count": 3 },
{ "rating": 1, "count": 4 }
],
"items": [
{
"rating": 5,
"title": "Fictional title text",
"body": "Fictional review body text.",
"author": "Fictional Reviewer",
"date": "2026-03-05T10:15:00.000Z",
"isRecommended": true,
"verifiedPurchaser": true
}
]
}
}

Plan Requirement

The default connection works out of the box, and failed requests are retried with backoff. For large or frequent runs, the residential proxy group gives more headroom; pick it under Connection.

FAQ

How much does it cost?

You pay per product returned, plus one detail and review enrichment charge per product, and only when that product's full detail or review history is actually fetched successfully. fetchDetails and fetchReviews share that single surcharge, charged at most once per product. The Pricing tab shows current rates. Use Max products total to cap the cost of any run.

This actor collects only publicly available product data. You are responsible for how you use it: follow dm.de's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Product images, brand names, 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 emitUnchanged.

What's the difference between Resume and Incremental mode?

Resume continues one specific interrupted run using a pasted run or dataset id. Incremental mode is for running the same search again and again, for example daily, without ever pasting an id: the actor remembers the previous run of that search by itself.

Why did my run fail instead of returning an empty dataset?

If Apify Proxy refuses this account the connection the run asked for (for example, a proxy group your plan doesn't include), the run fails with a clear connection message instead of reporting "no products matched". If dm.de itself returns no results or blocks individual requests, the run still succeeds with whatever it collected, which can be an empty dataset. Check that your plan includes the proxy access the run requests, then try again.

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 e-commerce data?

Pair this actor with these related scrapers from the same team:

🛒 OBI.de Scraper
Scrape OBI (obi.de) DIY/home-improvement products: current + strike-through original...
🛒 ROSSMANN.de Scraper
Scrape ROSSMANN (rossmann.de) drugstore products: current + original strike-through price...
👗 OTTO.de Scraper
Scrape OTTO.de products by search or URL. Extract prices, discounts, variants...
🛒 HORNBACH Products, Prices & Reviews Scraper
Scrape HORNBACH (hornbach.de) DIY, building & garden products: current + strike-through...
🥦 REWE.de Scraper
Scrape REWE Germany (rewe.de) grocery products: current price, was-price and discount...
🛒 Thalia.de Scraper
Scrape Thalia.de books, eBooks, audiobooks, toys and stationery. Search by keyword or...

👉 Browse all abotapi scrapers

💬 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.