Sign inTry it

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.

No reports yetRead-only, no login
Site
OTTO, Germany
Version
v2 of 2
Runs, last 7 days
No reports yet
sha256
ef3f06e17bdd…

Run it with your agent

after installing Wield

Ask 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
  1. 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 agent
include_sponsoredboolean = false
max_pricenumberKeep products at or below this price in EUR (within the returned page)
querystringrequiredWhat to look for, e.g. 'kaffeemaschine', 'espresso maschine', 'boxspringbett 180x200'

Returns

to your agent
productsobject[]article_number, brand, discount_pct, facts, id, image, label, list_price_eur, name, price_eur, rating_count, sponsored, title, url
querystring

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

Check it yourself
curl -s https://wield.run/api/v1/recipes/otto.de/search-products | shasum -a 256
# ef3f06e17bddaf25606bfcc6b8465d5366723cb573c7aa8c76abcb875faaa92e
otto.de/search-products.json, v2
{
  "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
}