Otto.de Product Price Watch (Germany)
Pricing
from $0.55 / 1,000 product scrapeds
Otto.de Product Price Watch (Germany)
Search otto.de for any term and get one flat row per product: price in EUR, UVP and discount, rating, review count, brand, delivery note, URL, image - and whether each product is new, cheaper or dearer than on the last run.
Pricing
from $0.55 / 1,000 product scrapeds
Rating
0.0
(0)
Developer
Superslow Sloth
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Search otto.de for one or more terms and get one flat row per product: price in EUR, UVP (the crossed-out recommended price) and discount, rating and review count, brand, delivery note, URL and image - and whether each product is new since your last run or changed price. Schedule it daily with Only new and re-priced products on and you get a price-watch feed that costs nothing for products whose price has not moved.
Input
| Field | Notes |
|---|---|
queries | Search terms, one per line (staubsauger, akku staubsauger). Each is searched separately; a product two terms both find is returned once, under the first. |
maxItems | Products read per search term (default 100, max 5,000). Otto serves 120 per page. |
sort | topseller (default), preis-aufsteigend, preis-absteigend, bewertung, hoechste-reduzierung, neuheiten - Otto's own sort chips. The actor checks which sort the page says it served and stops with a failure on a mismatch, because Otto silently falls back to the default for a value it does not know. |
fullPrices | See Which products have a price below. Default on. |
changesOnly | Return and charge only products that are new or re-priced since the last run of the same search. |
Which products have a price
This is the one thing to know about otto.de. Its search page is server-rendered,
but only the first 18 of the 120 products on a page are rendered with a
price (measured 2026-10-07 on staubsauger, offsets 0, 120, 240 and 3,900,
and on three other queries). The other 102 are placeholders with an id, a name
and a link; the website fills them in with a second request the moment you
scroll.
fullPricesoff reads the page exactly as it is served. Products with a price on the page become rows; placeholders are skipped and not charged (the run log counts them). You get the 18 priced products of every page - a thin slice of the result list, but each row is complete.fullPriceson (default) also callsGET /crocotile/tile/data?variationIds=...- the endpoint the website's own script calls to fill the placeholders in - with the ids of the unpriced products of each page, one extra request per page. Every product becomes a row. Its prices matched the page's own on all 17 products both sources priced.
Output
| Field | Notes |
|---|---|
change | new, price_drop, price_rise or unchanged, compared with the previous run of the same search. |
query, sort | The term that surfaced the product first, and the sort order. |
position, sponsored | Place in the result list (counted across pages) and whether it is a paid placement. Sponsored tiles repeat products that are also listed ordinarily; the product is returned once. |
product_id, variation_id, article_number | Otto's ids. A product has one variation per colour or size; the price and the change tracking belong to the variation. |
name, brand, url, image_url | url is https://www.otto.de/p/<slug>/?variationId=<variation_id>. |
price, currency | The selling price as a float, EUR. |
is_starting_price | True for "ab 3,48 €": the lowest of several variants' prices. |
suggested_retail_price | The crossed-out UVP. Null when the tile shows none. |
discount_percent | Whole percent below the UVP, computed from the two prices above. It equalled the sale tag Otto prints on every tile checked (about 110). Null without a UVP. |
unit_price, unit_price_amount, unit_price_unit | "(7,00 €/ 1 Stk)" as 7.0, 1.0, "Stk". Null when Otto prints none. |
rating, review_count | Star average and number of ratings; both null for an unreviewed product. |
availability, delivery_note | InStock and Otto's delivery line, verbatim. The wording changes between requests ("in 4-5 Werktagen bei dir" / "bis Mo., 12. Okt. bei dir") - do not diff it between runs. |
Honest nulls
A value the tile does not show is null, never 0 or "". A product with no
UVP has discount_percent: null, not 0.
What is not exported
Otto's own earlier price ("Vergleichspreis") exists in only one of the two markups otto.de serves for the same tile (chosen per request: six identical requests gave one markup four times and the other twice), so it would be filled on half the runs and read as a price change on the others. It is left out.
A search never comes back empty
A nonsense term is not a "no results" page on otto.de: xqzvbnmkjhg returned
1,333 unrelated products (a loose match; the nonsense word is still printed in
the heading). Check your terms; the actor cannot tell that from a real hit.
Change tracking
Each search (the set of terms and the sort order) has its own memory, kept in a
named key-value store on your Apify account (otto-de-products-watch), so
it is never visible to anyone else. The first run labels every product new.
After that a product is new if the last run did not read it, price_drop /
price_rise if its price moved, and unchanged otherwise. The memory keys on
the variation id, not the product id, so a tile that starts showing a
different colour is new rather than a fake price change.
With changesOnly, unchanged products are neither returned nor charged.
maxItems still counts them: it is how much of the result list is watched, so
a watch of the top 500 results reads 500 however few moved. Otto's lists are
not newest-first (the default is Topseller), so there is no early stop - the
run reads maxItems products per term.
Pricing
Pay per event:
- $0.002 per run (
actor-start), charged only after your input is validated - a run that fails on bad input costs nothing. - $0.00055 per product row written (
product-scraped), i.e. $0.55 per 1,000 products. WithchangesOnly, unchanged products are not charged.
How it fetches
It reads the same pages otto.de serves to a browser
(https://www.otto.de/suche/<term>/?l=gq&o=<offset>&sortiertnach=<sort>, 120
products per page), parsing the product JSON-LD and price markup of each tile;
with fullPrices it adds one request per page to /crocotile/tile/data. No
account, no login, no cookies. Apify datacenter proxy is the default; a refused
request (HTTP 403, 429, 5xx, or a 200 page without results) is retried from a
fresh address.