Search fashion products (HTML fallback without GraphQL hashes).
Fallback for zalando.de/search-products when Zalando's GraphQL hashes rotate: loads the server-rendered catalogue page (first 24 products) and reads brand, name, price, discount and link from the product cards. Size and price filters work through the page URL. Fewer fields than the GraphQL recipe (no sizes list or badges).
- Site
- Zalando, Germany
- Version
- v1
- Runs, last 7 days
- No reports yet
- sha256
- 249a64884b71…
Requests
sent from your browser, in order- 1GET/katalog/__groesse-{{params.size | lower | urlencode}}/?price_from&price_to&qTwo variants because the size is a path segment (/katalog/__groesse-42/); only one runs.
- 2GET/katalog/?price_from&price_to&q
Parameters
from your agentmax_priceintegerEUR
min_priceintegerEUR
querystringrequiredSearch text, e.g. 'sneakers'
sizestringOne size, e.g. '42' or 'M'
Returns
to your agentcurrencyany
productsobject[]brand, discount_pct, name, price_eur, price_from, reference_price_eur, url
querystring
Where it can send
- www.zalando.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) > `10`
- output.products[0].price_eur > `0`
- length(output.products[?price_eur > `80`]) == `0`
- starts_with(output.products[0].url, 'https://www.zalando.de/')
Raw recipe
Served as canonical JSON from /api/v1/recipes/zalando.de/search-products-html, so its sha256 matches the ETag and the index.
Check it yourself
curl -s https://wield.run/api/v1/recipes/zalando.de/search-products-html | shasum -a 256 # 249a64884b71c9c85ec86a6e4cadfb5d933c474f07adf7accfa858b51e7659e5
zalando.de/search-products-html.json, v1
{ "description": "Fallback for zalando.de/search-products when Zalando's GraphQL hashes rotate: loads the server-rendered catalogue page (first 24 products) and reads brand, name, price, discount and link from the product cards. Size and price filters work through the page URL. Fewer fields than the GraphQL recipe (no sizes list or badges).", "effect": "read", "id": "zalando.de/search-products-html", "keywords": [ "zalando", "mode", "kleidung", "schuhe", "sneaker", "jacke", "online shopping", "fashion", "clothes", "shoes", "shopping", "buy clothes", "fallback" ], "output": { "schema": { "properties": { "currency": { "const": "EUR" }, "products": { "items": { "properties": { "brand": { "type": "string" }, "discount_pct": { "description": "Discount in percent vs reference_price_eur ('bis zu' = up to)", "type": [ "number", "null" ] }, "name": { "type": "string" }, "price_eur": { "description": "Current price ('ab' = from, for products with several prices)", "type": [ "number", "null" ] }, "price_from": { "description": "Shown as 'ab' (lowest of several sizes or colours)", "type": "boolean" }, "reference_price_eur": { "description": "Struck-through or median reference price, when shown", "type": [ "number", "null" ] }, "url": { "format": "uri", "type": "string" } }, "type": "object" }, "type": "array" }, "query": { "type": "string" } }, "required": [ "query", "products" ], "type": "object" }, "value": "let $p = steps.page || steps.page_nosize in {query: params.query, currency: 'EUR', products: $p.items[?url != `null` && name != `null`].let $seg = split(price_all || '', '€'), $d = (split(price_all || '', '€')[?contains(@, '%')] | [0]) in {name: name, brand: brand, price_eur: to_number(replace(replace(trim(replace(split(price_text || '', '€')[0], 'ab', '')), '.', ''), ',', '.')), price_from: starts_with(price_text || '', 'ab'), reference_price_eur: length($seg) > `2` && contains($seg[1], ':') && to_number(replace(replace(trim(split($seg[1], ':')[-1]), '.', ''), ',', '.')) || `null`, discount_pct: $d && abs(to_number(trim(split(split($d, '%')[0], 'zu')[-1]))) || `null`, url: split(url, '?')[0]}}" }, "params": { "additionalProperties": false, "properties": { "max_price": { "description": "EUR", "minimum": 1, "type": "integer" }, "min_price": { "description": "EUR", "minimum": 0, "type": "integer" }, "query": { "description": "Search text, e.g. 'sneakers'", "maxLength": 100, "minLength": 1, "type": "string" }, "size": { "description": "One size, e.g. '42' or 'M'", "maxLength": 10, "type": "string" } }, "required": [ "query" ], "type": "object" }, "provenance": { "method": "browser-inspect", "notes": "No hashes: the SSR catalogue page (~1.2 MB) has 24 <article> product cards. The hydration JSON (#re-concurrent-data-hydrate) is wrapped in a JS call, so embedded_json cannot read it; cards are read by semantic tags (article, a[href], h3 > span, section p) because class names are obfuscated. Size is a German path segment (__groesse-42); price via price_from/price_to.", "recorded_at": "2026-11-07T12:25:00+01:00", "recorded_by": "C4" }, "requires_login": false, "schema": "https://wield.run/schema/recipe/v1.json", "site": { "country": "DE", "id": "zalando.de", "language": "de", "login_url": "https://www.zalando.de/login", "name": "Zalando", "origin": "https://www.zalando.de", "origins": [ "https://www.zalando.de" ] }, "steps": [ { "description": "Two variants because the size is a path segment (/katalog/__groesse-42/); only one runs.", "expect": { "content_type": "html", "status": [ 200 ] }, "extract": { "html": { "heading": { "selector": "h1" } }, "html_items": { "items": { "fields": { "brand": { "selector": "h3 > span:first-child" }, "name": { "selector": "h3 > span:last-child" }, "price_all": { "selector": "section" }, "price_text": { "selector": "section p" }, "url": { "attr": "href", "selector": "a[href]" } }, "max": 30, "selector": "article" } } }, "id": "page", "parse": "html", "request": { "headers": { "Accept": "text/html" }, "method": "GET", "query": { "price_from": "{{params.min_price}}", "price_to": "{{params.max_price}}", "q": "{{params.query}}" }, "url": "/katalog/__groesse-{{params.size | lower | urlencode}}/" }, "when": "params.size" }, { "expect": { "content_type": "html", "status": [ 200 ] }, "extract": { "html": { "heading": { "selector": "h1" } }, "html_items": { "items": { "fields": { "brand": { "selector": "h3 > span:first-child" }, "name": { "selector": "h3 > span:last-child" }, "price_all": { "selector": "section" }, "price_text": { "selector": "section p" }, "url": { "attr": "href", "selector": "a[href]" } }, "max": 30, "selector": "article" } } }, "id": "page_nosize", "parse": "html", "request": { "headers": { "Accept": "text/html" }, "method": "GET", "query": { "price_from": "{{params.min_price}}", "price_to": "{{params.max_price}}", "q": "{{params.query}}" }, "url": "/katalog/" }, "when": "!(params.size)" } ], "task": "Search fashion products (HTML fallback without GraphQL hashes)", "tos": { "notes": "Zalando's terms forbid automated extraction of content. One user-initiated search at a time from the user's browser (2 requests); Akamai scores automated traffic (an automated test browser was tagged traffic_type=aggressive-crawler), so keep it human-paced. Buying stays on zalando.de.", "reviewed": false }, "verify": { "checks": [ "length(output.products) > `10`", "output.products[0].price_eur > `0`", "length(output.products[?price_eur > `80`]) == `0`", "starts_with(output.products[0].url, 'https://www.zalando.de/')" ], "example_params": { "max_price": 80, "query": "sneakers", "size": "42" }, "max_ms": 6000 }, "version": 1 }