OBI.de Scraper - Prices, Offers & Reviews
Pricing
from $1.00 / 1,000 product results
OBI.de Scraper - Prices, Offers & Reviews
Scrape OBI (obi.de) DIY/home-improvement products: current + strike-through original price with discount, per-unit pricing (per m2/kg), specials/offers listings, brand, EAN, multi-seller stock, tech specs, 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
Maintained by CommunityActor stats
1
Bookmarked
3
Total users
0
Monthly active users
a day ago
Last modified
Categories
Share
OBI Scraper: Prices, Specials, Stock & Reviews
OBI Scraper turns obi.de, the German DIY, home improvement and garden retailer, into structured product data. Search by keyword or category slug, narrow to the site's own currently discounted specials, or paste product and listing links directly. Every record from search, category or listing pages carries the current price, the strike-through original price with a computed discount when a product is marked down, per-unit pricing per square metre or per kilogram where the site shows it, and an online availability status, plus on request the full breadcrumb category path, technical specifications, media gallery, EAN and multi-seller pricing, and a complete customer review history with a full rating breakdown. A pasted single product link reads name, brand, description, images, category and reviews only, since it never visits a listing page. Export to JSON, CSV or Excel, pull results through the API, or send them into apps you already use.
Why This Scraper?
- Was-price and discount, structured, not read off a badge. When a product carries a reduced or recommended-retail original price, both prices are captured plus the computed discount amount and percentage.
- Real per-unit pricing. Building-material products such as tiles, flooring and timber return their per-square-metre or per-kilogram price separately from the pack or sale-unit price, exactly as the site distinguishes the two.
- Specials as a first-class filter. A "Specials / offers only" toggle narrows any search or category listing to only products currently showing a reduced price. OBI has no separate "on sale" category route, so this filters the site's own live discount signal instead of guessing at a category that does not exist.
- 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 technical specifications that vary per product category and are never hardcoded, media gallery, EAN and multi-seller pricing, stock and shipping.
- Two ways in. Keyword or category search with filters for brand, rating, price range and specials plus a sort order (the site ignores sort parameters, so sorting is applied by the actor to the fetched result set), or paste any product or listing link and let pagination continue forward on its own.
- Optional export to your apps. Send results into Notion, Linear, Airtable or any Apify MCP connector alongside the dataset.
Use Cases
- Price trackers and comparison sites: monitor OBI's current and strike-through prices, discount percentages and per-unit pricing across chosen categories.
- DIY retail and category managers: watch how an assortment's pricing, ratings and stock status move over a search or category on a recurring schedule.
- Consumer and product researchers: collect full review text, rating breakdowns and technical specifications for comparison or sentiment studies.
- Marketing and promotions teams: track which products currently carry a reduced price with the specials filter, to plan campaigns around active discount windows.
- Data teams building historical DIY pricing datasets: run Incremental mode on a schedule to build a change log of new, updated and no-longer-listed products over time.
Data You Get
Sample shape: values below are illustrative placeholders, not from a live product.
| Field | Example |
|---|---|
productId / sku | "3345566" |
name | "Voltago Akku-Laubbläser LB-320" |
brand | "Voltago" |
category / categoryPath | "Gartengeräte", [{"name": "Garten", "url": "..."}, {"name": "Gartengeräte", "url": "..."}] |
url | "https://www.obi.de/p/3345566/voltago-akku-laubblaeser-lb-320" |
price / currency | 79.99, "EUR" |
originalPrice / originalPriceType / discountAmount / discountPercent | 99.99, "STRIKE_PRICE", 20.00, 20.0 |
unitPrice / unitPriceUnit | 14.50, "m²" |
isOnSpecial | true |
rating / reviewCount | 4.6, 34 |
onlineAvailable / onlineAvailabilityStatus | true, "BESTELLBAR" |
inStock | true (same signal as onlineAvailable: whether the product can currently be ordered online) |
scrapedAt | "2026-11-04T10:15:00Z" (when this run read the record) |
storeAvailabilityStatus | "KEIN_MARKT_AUSGEWAEHLT" (the actor never picks a store, so this field usually just says none is selected) |
image / images | "https://www.obi.de/sample/image.png", ["https://www.obi.de/sample/image.png"] |
ean / eans | "4001234567890", ["4001234567890"] |
description | full product description text |
technicalData | {"Weight": "2.4 kg", "Battery type": "Li-Ion", "Voltage": "18 V"} (flattened per category) |
media | [{"type": "image", "url": "...", "thumbnail": "..."}] |
variants | [] (populated when the product has size or colour options) |
sellers | [{"sellerName": "Sample Seller", "price": 79.99, "shippingCost": 4.95, "stock": 12}] |
manufacturerName / manufacturerCountry / taxPercent | "Sample Manufacturer GmbH", "DE", 19 |
reviews.averageRating / reviews.totalReviewCount | 4.6, 34 |
reviews.ratingDistribution | [{"rating": 5, "count": 22}, {"rating": 4, "count": 8}, {"rating": 3, "count": 2}] |
reviews.items[] | [{"rating": 5, "title": "Works well in the garden", "body": "Sample review text.", "author": "Sample Buyer", "date": "2026-03-14T10:22:00.000+00:00", "isRecommended": true, "verifiedPurchaser": true, "helpfulVotes": 3, "unhelpfulVotes": 0, "replies": []}] |
OBI does not expose a separate "discontinued" flag. onlineAvailable / onlineAvailabilityStatus describe whether a still-listed product can currently be ordered online, passed straight through from the site. storeAvailabilityStatus is the site's own per-store status code, but this actor never selects a specific store, so it typically just reports that no store is selected rather than real local stock. A product that disappears from a tracked search or category altogether is what Incremental mode's EXPIRED classification is designed to catch, and only once "Emit expired products" is turned on (see How to Use below).
How to Use
- Pick a mode:
search(a keyword or a real category slug, with real site filters) orurl(paste product or listing links). - Fill in the search term or the URLs, then narrow with the specials, brand, rating and price filters if you want a subset.
- Turn on Fetch full product detail and/or Fetch reviews for the extra fields you want, then set Max products total and Max pages per search to bound the run.
- Start the run, then download the dataset as JSON, CSV or Excel, or read it through the API.
Keyword search, first page, with reviews (the review toggle default):
{"mode": "search","searchTerm": "akku ventilator","maxItems": 20}
Category browse, filtered to a brand and only currently-discounted items:
{"mode": "search","searchTerm": "werkzeuge","brands": ["Bosch"],"specialsOnly": true,"sortBy": "PRICE_ASC","maxItems": 50,"maxPages": 5}
Supported URL shapes (url mode with the urls field left untouched now scrapes one example of each shape below, instead of one sample search; clear the field and paste your own links to scrape only those):
| Shape | Example |
|---|---|
| Keyword search listing | https://www.obi.de/search/akku%20ventilator/ |
Paginated search (starts at ?page=N; a partial scope, so it never produces EXPIRED) | https://www.obi.de/search/werkzeuge/?page=3 |
| Category slug | https://www.obi.de/search/werkzeuge/ |
| Specials listing | https://www.obi.de/search/aktion/ |
Sorted query (the site ignores ?sort=; the actor logs a warning and orders within each fetched page only) | https://www.obi.de/search/akku%20ventilator/?sort=price_asc |
| Product detail | https://www.obi.de/p/6929863/einhell-werkzeugkoffer-universal-80tlg-e-case |
| Product by article number only | https://www.obi.de/p/6929863 |
| Search without trailing slash | https://www.obi.de/search/akku%20ventilator |
| Apex host | https://obi.de/search/akku%20ventilator/ |
| Brand shop (mapped to that brand's search listing) | https://www.obi.de/marken/eufy |
Paste a single product link (full detail is always included; reviews on request):
{"mode": "url","urls": ["https://www.obi.de/p/1409713/einhell-akku-ventilator-gc-cf-18-110-li-solo"],"fetchReviews": true,"maxReviewsPerProduct": 0}
Paste a listing link and keep paginating forward:
{"mode": "url","urls": ["https://www.obi.de/search/schrauben/"],"maxItems": 100,"maxPages": 10}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/obi-de-scraper").call(run_input={"mode": "search", "searchTerm": "akku ventilator", "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/obi-de-scraper').call({ mode: 'search', searchTerm: 'akku ventilator', 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.
A note on pasted single product links
A bare product link has no search-result card to read anything from, so this actor always reads the full product detail page for a pasted product link, regardless of the Fetch full product detail toggle. That toggle only controls whether search and category results also get that same detail fetch. Reviews still follow the Fetch reviews toggle in every mode. A pasted product record never carries price, currency, originalPrice, originalPriceType, discountAmount, discountPercent, isOnSpecial, unitPrice, onlineAvailable, onlineAvailabilityStatus, storeAvailabilityStatus, image or images, since none of that comes from the product detail page this actor reads for it; it does still carry categoryPath, description, technicalData, media, variants, sellers, ean, eans, manufacturerName, manufacturerCountry, taxPercent, rating, reviewCount and reviews. specialsOnly, minPrice and maxPrice will always filter a pasted product out if set, since it has no price or discount data to check against.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted or oversized run: paste its run or dataset ID and this run skips every product already collected there, returning only the remaining new products. - Incremental mode (
incrementalMode) is for a schedule, for example daily, against the same search: the actor remembers the previous run itself, so you never paste a run ID. The first run returns everything asNEW. Later runs classify each product asNEW,UPDATED(withchangedFields),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),REAPPEAREDorEXPIRED. State is isolated per search term or URL, mode, filter and detail setting automatically; setstateKeyto name or deliberately share a monitoring campaign. The nested review list itself is excluded from change detection, but the top-levelratingandreviewCountfields are not, so a new review that moves either of those still turns the productUPDATEDon the next run. What is compared: every returned field except the nestedreviewsblock and thescrapedAttimestamp, which are always excluded (they stay in the returned row). UseignoreFieldsForChangesto exclude more fields (a dotted path such asimages.urldrops a nested key), or setchangeScopetopriceAndStockso only price, original price, discount, special flag and availability decideUPDATED.compactUpdatesturnsUPDATEDandEXPIREDrows into slim rows (ids, url, name, current price and availability,priceChanges); a compact row carries no reviews or detail fields, so it does not trigger the detail-enrichment charge. SwitchingchangeScopeorignoreFieldsForChangeswith the automatic state key starts a fresh baseline (every productNEWonce); setstateKeyto keep the current one. EXPIREDproducts (present before, no longer found) are only produced onceemitExpiredis on and a run completes a full, uncapped scan of the tracked search, never on a run cut short by Resume or by Max products total.expireAfterMissedScans(default 1) delays the mark until a product was missing from that many consecutive complete scans.EXPIREDmeans the product dropped out of the listing; it does not prove it was delisted, so readonlineAvailablefor availability. A pasted listing URL that starts at?page=Nwith N above 1 never walked the earlier pages, so it never producesEXPIRED. TurningemitExpiredon for the first time is also what starts marking a missing product as gone in the stored state.REAPPEAREDcan only ever follow, on a later run, for a product that was previously marked gone that way. WithemitExpiredleft off, which is the default, nothing is ever marked gone, soREAPPEAREDnever fires either.
Dataset views
The dataset has four views in the Output tab: Products (the main listing), Reviews (one row per review, with author, rating, date, text, helpful and unhelpful votes and any seller replies), Product detail (the fetchDetails fields) and Changes (the incremental changeType, changedFields and priceChanges). Each review also carries helpfulVotes, unhelpfulVotes and replies, as shown in the Data You Get table.
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 (a title 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
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search finds products by keyword, category or specials; url scrapes pasted product, search or category links. |
searchTerm | string | (prefill akku ventilator) | Keyword or a real OBI category slug, used in search mode only. |
urls | array | (one example of each supported URL shape) | Product, listing or brand shop URLs to scrape, used in url mode only. Pagination continues forward from any ?page= already in the link. Leaving the field untouched scrapes one example of each shape (see the table above). |
specialsOnly | boolean | false | Keep only currently-discounted products. Applies to search mode and a pasted listing/category link; a pasted single product link never carries discount data, so it is always filtered out when this is on. |
brands | array | (none) | Exact brand names to keep. Applies to both search and url mode. |
minRating | integer | (none) | 1 to 5, minimum rating to keep. Applies to both search and url mode. |
minPrice | number | (none) | Minimum price in EUR to keep. Applies to search mode and a pasted listing/category link; a pasted single product link has no price to filter on, so it is always filtered out when this is set. |
maxPrice | number | (none) | Maximum price in EUR to keep. Applies to search mode and a pasted listing/category link; a pasted single product link has no price to filter on, so it is always filtered out when this is set. |
sortBy | string | RELEVANCE | RELEVANCE, PRICE_ASC, PRICE_DESC or RATING, applied to the fetched result set. |
fetchDetails | boolean | false | Adds breadcrumb category path, description, flattened technical specifications, media gallery, EAN and multi-seller pricing and stock from the product detail page, for search and listing results. A pasted single product link always includes this detail regardless of this toggle. |
fetchReviews | boolean | true | Fetches each product's full review history: overall rating, review count, a full rating breakdown, and per-review author, date, rating, title and body text. |
maxReviewsPerProduct | integer | 20 | Cap on reviews fetched per product when Fetch reviews is on. 0 means all available reviews, capped at 5000 per product. |
maxPages | integer | (none; hard limit 1000) | Cap on result pages per search, category or URL entry. Leave empty for the built-in hard limit of 1000 pages per entry; the run also stops at Max products total. |
maxItems | integer | 20 | Hard cap on total products returned across every search, category or URL entry. 0 means the maximum of 100000, still bounded by Max pages per search. |
resumeFromRunId | string | (none) | Paste a previous run ID or dataset ID to continue one interrupted or oversized crawl without returning or charging for products already collected there. |
incrementalMode | boolean | false | Turn on for recurring monitoring of the same search. Later runs return only new and changed products. |
stateKey | string | (none) | Optional name for an incremental-mode monitoring campaign; derived automatically from the search and filters when left empty. |
emitUnchanged | boolean | false | Incremental mode only: also return, and bill for, products unchanged since the last run. |
emitExpired | boolean | false | Incremental mode only: also return, and bill for, products no longer found, once a run fully scans the tracked search. |
changeScope | string | all | Incremental mode only: priceAndStock makes only price, discount, special flag and availability decide UPDATED. |
compactUpdates | boolean | false | Incremental mode only: UPDATED and EXPIRED rows become slim (ids, current price and availability, priceChanges). |
expireAfterMissedScans | integer | 1 | Incremental mode only: consecutive complete scans a product must be missing before it is marked EXPIRED. |
ignoreFieldsForChanges | array | (none) | Incremental mode only: field names or dotted paths that never decide UPDATED. Reviews and scrapedAt are always ignored. |
proxy | object | {"useApifyProxy": true} | Connection configuration for the run. |
mcpConnectors | array | (none) | Optional MCP connectors to export results into (Notion, Linear, Airtable, Apify). |
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
Sample shape: values below are illustrative placeholders, not from a live product.
{"productId": "3345566","sku": "3345566","name": "Voltago Akku-Laubbläser LB-320","brand": "Voltago","category": "Gartengeräte","url": "https://www.obi.de/p/3345566/voltago-akku-laubblaeser-lb-320","price": 79.99,"currency": "EUR","originalPrice": 99.99,"originalPriceType": "STRIKE_PRICE","discountAmount": 20.00,"discountPercent": 20.0,"isOnSpecial": true,"unitPrice": null,"unitPriceUnit": null,"rating": 4.6,"reviewCount": 34,"onlineAvailable": true,"onlineAvailabilityStatus": "BESTELLBAR","storeAvailabilityStatus": "KEIN_MARKT_AUSGEWAEHLT","image": "https://www.obi.de/sample/image.png","reviews": {"averageRating": 4.6,"totalReviewCount": 34,"ratingDistribution": [{ "rating": 5, "count": 22 },{ "rating": 4, "count": 8 },{ "rating": 3, "count": 2 }],"items": [{"rating": 5,"title": "Works well in the garden","body": "Sample review text.","author": "Sample Buyer","date": "2026-03-14T10:22:00.000+00:00","isRecommended": true,"verifiedPurchaser": true}]}}
When fetchDetails is on for search or category results, the record also carries categoryPath, description, technicalData, media, variants, sellers, ean, eans, manufacturerName, manufacturerCountry and taxPercent. A pasted single product link (always detail-fetched) carries those same fields but never price, currency, originalPrice, discount fields, isOnSpecial, unitPrice, onlineAvailable, either availability status, image or images, since none of that lives on the product detail page; see "A note on pasted single product links" above. When incrementalMode is on, every returned record also carries changeType (NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED), changedFields, firstSeenAt and lastSeenAt.
Plan Requirement
The default connection (Apify datacenter proxy, country not pinned) loaded listing pages, the product-detail data and the review data in testing, and obi.de shows no challenge page, so no residential proxy is needed and the default works without extra configuration on a plan that includes proxy access. Apify free plans do not include proxy access, so on a free plan the run uses a backup connection instead; if the default connection is refused the run says so in the log: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable." and, once a page is served that way, "Served over the backup connection (the default connection was unavailable)." A residential proxy under Proxy & connection is optional and only worth turning on for very large monitoring campaigns. If you supply your own proxy URLs, no backup connection is used.
A run that could not load any usable page ends as FAILED with a status message, never as a successful empty run. The three messages are: no proxy access for the account ("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"), backup connection also failed ("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 OBI pages"), and an ordinary connection failure ("Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later.").
FAQ
How much does it cost?
Three events are charged, and the Pricing tab shows the current rates. (1) apify-default-dataset-item: once per product row pushed to the dataset. (2) detail-enrichment: a surcharge for each row where full detail and/or the review history was actually fetched, charged after the row is in the dataset: one unit per started block of 10 reviews returned, with the product read folded into the first block (minimum 1 unit per enriched row): 8 reviews bill 1 unit, 11 bill 2, 25 bill 3. A row whose reads all failed, an UNCHANGED row that is suppressed, and a compact UPDATED or EXPIRED row carry no surcharge. (3) apify-actor-start: once per run. A pasted single product link always fetches full detail, so it always carries the surcharge when the fetch succeeds. Fetch reviews is on by default, so the default input includes the surcharge; turn it off for listing-only output. Use Max products total to cap the cost of any run.
Is it legal to scrape OBI?
This actor collects only publicly available product and review information from obi.de pages already visible to a shopper. You are responsible for how you use the data: follow OBI's terms and the laws that apply to you, and get legal advice before any commercial redistribution. Review text in particular may carry rights held by its authors.
Can I get only new or changed products on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Later runs then return only new, updated and reappeared products for the same tracked search, and unchanged ones are suppressed and not billed unless Emit unchanged is on.
Does Incremental mode report REAPPEARED or EXPIRED products by default?
No. EXPIRED products are only produced once Emit expired is turned on and a run completes a full, uncapped scan of the tracked search, never on a run cut short by Resume or by Max products total. Turning Emit expired on is also what first lets the stored state mark a missing product as gone; REAPPEARED can then only follow, on a later run, for a product that was marked gone that way and is found again. With Emit expired left off, which is the default, nothing is ever marked gone, so REAPPEARED never fires either.
Why did my run fail instead of returning an empty dataset?
If no page can be loaded at all (for example the proxy is refused for the account, or every request fails), the run ends as FAILED with one of the status messages quoted under Plan Requirement, so a connection problem is never mistaken for an empty search. A search that loads normally but matches nothing finishes successfully with no rows. If a run loads some pages and then meets refusals, it stops retrying and keeps what was already collected. A pasted single product link whose detail page is refused still pushes a stub row (productId, sku, url only), unless specialsOnly, minPrice or maxPrice excludes it first. An unreadable Resume run or dataset ID, or Incremental mode and Resume together against a search that already has tracked state, also stop the run with a clear failure message.
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 a summary of each result 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... |
| 🛒 ROSSMANN.de Scraper Scrape ROSSMANN (rossmann.de) drugstore products: current + original strike-through price... | 🥦 Kaufland.de Scraper Scrape Kaufland.de, Germany's hypermarket and online marketplace: keyword/category/brand... |
| 🛒 MediaMarkt Germany Scraper Scrape MediaMarkt.de products by keyword or URL. Extract current and original prices... | 🛒 Thalia.de Scraper Scrape Thalia.de books, eBooks, audiobooks, toys and stationery. Search by keyword or... |
💬 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.