Search products on OTTO with price, list price and ratings.
Searches OTTO, a large German online shop, like its search box: brand, product name, price and the manufacturer's list price (UVP) in euros, discount, number of reviews, labels such as 'Sehr beliebt', key facts, image and product link, for the products OTTO renders on the first results page (about 18; the rest of its list loads later in the page). Sponsored products are dropped by default.
- Site
- OTTO, Germany
- Version
- v2 of 2
- Runs, last 7 days
- No reports yet
- sha256
- ef3f06e17bdd…
Run it with your agent
after installing WieldAsk in plain words. Your agent finds this recipe and calls it:
“Search products on OTTO with price, list price and ratings.”
Read-only: it changes nothing on the site. No login needed.
{ "tool": "run", "arguments": { "recipe_id": "otto.de/search-products", "params": { "query": "espressomaschine" } } }
Requests
sent from your browser, in order- 1GET/suche/{{params.query | lower | urlencode}}/The search results page (server-rendered product tiles). Needs the site's session cookies, which the user's OTTO tab has; a cookie-less first request gets HTTP 400.
Parameters
from your agentReturns
to your agentWhere it can send
- www.otto.de
Anything else is blocked by the extension.
Reads from your session
Nothing. Your browser attaches the site's cookies by itself.
Used only in requests to the addresses on the left. Never sent to wield.run or your agent.
Checks
a run passes when- length(output.products) > `5`
- length(output.products[?price_eur > `0`]) == length(output.products)
- length(output.products[?sponsored]) == `0`
- length(output.products[?starts_with(url, 'https://www.otto.de/p/')]) == length(output.products)
- length(output.products[?brand != `null`]) > `3`
Raw recipe
Served as canonical JSON from /api/v1/recipes/otto.de/search-products, so its sha256 matches the ETag and the index.
curl -s https://wield.run/api/v1/recipes/otto.de/search-products | shasum -a 256 # ef3f06e17bddaf25606bfcc6b8465d5366723cb573c7aa8c76abcb875faaa92e
{ "description": "Searches OTTO, a large German online shop, like its search box: brand, product name, price and the manufacturer's list price (UVP) in euros, discount, number of reviews, labels such as 'Sehr beliebt', key facts, image and product link, for the products OTTO renders on the first results page (about 18; the rest of its list loads later in the page). Sponsored products are dropped by default.", "effect": "read", "id": "otto.de/search-products", "keywords": [ "otto", "kaufen", "preis", "angebot", "haushalt", "möbel", "technik", "kaffeemaschine", "shopping", "price", "deal", "buy online" ], "output": { "schema": { "properties": { "products": { "items": { "properties": { "article_number": { "type": [ "string", "null" ] }, "brand": { "type": [ "string", "null" ] }, "discount_pct": { "type": [ "integer", "null" ] }, "facts": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "image": { "type": [ "string", "null" ] }, "label": { "type": [ "string", "null" ] }, "list_price_eur": { "description": "UVP, when OTTO shows one", "type": [ "number", "null" ] }, "name": { "type": [ "string", "null" ] }, "price_eur": { "type": [ "number", "null" ] }, "rating_count": { "type": [ "integer", "null" ] }, "sponsored": { "type": "boolean" }, "title": { "type": [ "string", "null" ] }, "url": { "type": [ "string", "null" ] } }, "type": "object" }, "type": "array" }, "query": { "type": "string" } }, "type": "object" }, "value": "let $inc = params.include_sponsored == `true`, $max = params.max_price in {query: params.query, products: map(&(let $p = @, $pr = @.price_cents && to_number(@.price_cents), $lp = @.list_price_cents && to_number(@.list_price_cents) in {id: $p.id, article_number: $p.article_number || `null`, name: $p.name || `null`, brand: $p.brand || `null`, title: $p.title || `null`, price_eur: ($pr && $pr / `100`) || `null`, list_price_eur: ($lp && $lp > `0` && $lp / `100`) || `null`, discount_pct: ($pr && $lp && $lp > $pr && floor((`1` - $pr / $lp) * `100` + `0.5`)) || `null`, rating_count: ($p.rating_count && to_number(replace(replace(replace($p.rating_count, '(', ''), ')', ''), '.', ''))) || `null`, label: $p.label || `null`, facts: $p.facts || `null`, sponsored: $p.origin == 'sponsored', image: $p.image || `null`, url: ($p.href && join('', ['https://www.otto.de', $p.href])) || `null`}), steps.search.products[?id != `null` && name != `null`])[?($inc || !sponsored) && (!$max || price_eur <= $max)]}" }, "params": { "additionalProperties": false, "properties": { "include_sponsored": { "default": false, "type": "boolean" }, "max_price": { "description": "Keep products at or below this price in EUR (within the returned page)", "minimum": 0, "type": "number" }, "query": { "description": "What to look for, e.g. 'kaffeemaschine', 'espresso maschine', 'boxspringbett 180x200'", "maxLength": 100, "minLength": 2, "type": "string" } }, "required": [ "query" ], "type": "object" }, "provenance": { "method": "browser-inspect", "notes": "Servers get HTTP 400 for /suche/<q>/, and so did a browser's first, cookie-less navigation; after the site's own session cookies are set (any OTTO page), a same-origin fetch of /suche/<q>/ returns 200 with 120 server-rendered tiles: article[data-qa=reptile-product-tile] with data-product-id, data-article-number and data-origin=sponsored for ads; brand, title, ofc-pricing-item-v1[retail-price|suggested-retail-price] in cents, .reptile-rating__amount '(101)', social-proof tag, top facts. Each tile also has ld+json (name, brand, offers, aggregateRating) that recipes cannot parse from inside html_items. v2 (2026-11-07 22:53): keywords only (online shop removed: they steered unrelated searches here, C1 ranking note).", "recorded_at": "2026-11-07T18:59:00+01:00", "recorded_by": "C4" }, "requires_login": false, "schema": "https://wield.run/schema/recipe/v1.json", "site": { "country": "DE", "id": "otto.de", "language": "de", "name": "OTTO", "origin": "https://www.otto.de", "origins": [ "https://www.otto.de" ] }, "steps": [ { "description": "The search results page (server-rendered product tiles). Needs the site's session cookies, which the user's OTTO tab has; a cookie-less first request gets HTTP 400.", "expect": { "assert": "contains(body, 'reptile-product-tile') || contains(body, 'keine Treffer') || contains(body, 'leider nichts gefunden')", "content_type": "html", "status": [ 200 ] }, "extract": { "html_items": { "products": { "fields": { "article_number": { "attr": "data-article-number", "selector": ":scope" }, "brand": { "selector": ".reptile-product-brand" }, "facts": { "selector": "dl.reptile-top-info" }, "href": { "attr": "href", "selector": "oc-link-v2 a" }, "id": { "attr": "data-product-id", "selector": ":scope" }, "image": { "attr": "src", "selector": "img" }, "label": { "selector": ".reptile-social-proof-badges oc-tag-v1" }, "list_price_cents": { "attr": "suggested-retail-price", "selector": "ofc-pricing-item-v1" }, "name": { "attr": "aria-label", "selector": "oc-link-v2 a" }, "origin": { "attr": "data-origin", "selector": ":scope" }, "price_cents": { "attr": "retail-price", "selector": "ofc-pricing-item-v1" }, "rating_count": { "selector": ".reptile-rating__amount" }, "title": { "selector": ".reptile-product-title" } }, "max": 100, "selector": "article[data-qa=\"reptile-product-tile\"]" } } }, "id": "search", "request": { "headers": { "Accept": "text/html" }, "method": "GET", "url": "/suche/{{params.query | lower | urlencode}}/" } } ], "task": "Search products on OTTO with price, list price and ratings", "tos": { "notes": "One search page per call in the user's own browser session, as a person browsing would. No cart, no account.", "reviewed": false }, "verify": { "checks": [ "length(output.products) > `5`", "length(output.products[?price_eur > `0`]) == length(output.products)", "length(output.products[?sponsored]) == `0`", "length(output.products[?starts_with(url, 'https://www.otto.de/p/')]) == length(output.products)", "length(output.products[?brand != `null`]) > `3`" ], "example_params": { "query": "espressomaschine" }, "max_ms": 6000 }, "version": 2 }