Sign inTry it

Search BIPA drugstore products.

Searches the BIPA Austria online shop like its search page: product name, price in euros, rating and number of ratings, and link. First page of results (about 20 products). Returns an empty list when nothing matches.

No reports yetRead-only, no login
Site
BIPA, Austria
Version
v1
Runs, last 7 days
No reports yet
sha256
d104607a3117…

Run it with your agent

after installing Wield

Ask in plain words. Your agent finds this recipe and calls it:

“Search BIPA drugstore products.”

Read-only: it changes nothing on the site. No login needed.

{
  "tool": "run",
  "arguments": {
    "recipe_id": "bipa.at/search-products",
    "params": {
      "query": "shampoo"
    }
  }
}

Requests

sent from your browser, in order
  1. 1GET/suche?qServer-rendered search results page /suche?q=…; read-only GET. Product tiles are div[data-testid=product-tile]; name comes from the link title, price from the price paragraph, rating from its aria-label.

Parameters

from your agent
querystringrequiredProduct, brand or category term, e.g. 'shampoo', 'head & shoulders', 'zahnpasta'

Returns

to your agent
productsobject[]name, price_eur, rating, ratings_count, url
querystring

Where it can send

  • www.bipa.at

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) > `0`
  • length(output.products[?price_eur > `0`]) > `0`
  • length(output.products[?starts_with(url, 'https://www.bipa.at/p/')]) == length(output.products)
  • length(output.products[?name != `null`]) == length(output.products)

Raw recipe

Served as canonical JSON from /api/v1/recipes/bipa.at/search-products, so its sha256 matches the ETag and the index.

Check it yourself
curl -s https://wield.run/api/v1/recipes/bipa.at/search-products | shasum -a 256
# d104607a3117d96ed1b3e02299b78cf8016a8b6455af1ace7227b78909d3091c
bipa.at/search-products.json, v1
{
  "description": "Searches the BIPA Austria online shop like its search page: product name, price in euros, rating and number of ratings, and link. First page of results (about 20 products). Returns an empty list when nothing matches.",
  "effect": "read",
  "id": "bipa.at/search-products",
  "keywords": [
    "bipa",
    "drogerie",
    "drogeriemarkt",
    "shampoo",
    "kosmetik",
    "körperpflege",
    "parfum",
    "bipa.at",
    "österreich",
    "drugstore",
    "cosmetics",
    "pharmacy",
    "austria",
    "beauty"
  ],
  "output": {
    "schema": {
      "properties": {
        "products": {
          "items": {
            "properties": {
              "name": {
                "type": "string"
              },
              "price_eur": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "rating": {
                "description": "Average stars, 0 to 5",
                "type": [
                  "number",
                  "null"
                ]
              },
              "ratings_count": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "name",
              "url"
            ],
            "type": "object"
          },
          "type": "array"
        },
        "query": {
          "type": "string"
        }
      },
      "required": [
        "query",
        "products"
      ],
      "type": "object"
    },
    "value": "{query: params.query, products: steps.search.products[?name != `null` && href != `null`].{name: name, price_eur: (price && to_number(replace(replace(replace(replace(price, '€', ''), ' ', ''), '.', ''), ',', '.'))) || `null`, rating: (rating_label && to_number(split(rating_label, ' ')[1])) || `null`, ratings_count: (rating_label && contains(rating_label, '(') && to_number(split(split(rating_label, '(')[1], ' ')[0])) || `null`, url: join('', ['https://www.bipa.at', href])}}"
  },
  "params": {
    "additionalProperties": false,
    "properties": {
      "query": {
        "description": "Product, brand or category term, e.g. 'shampoo', 'head & shoulders', 'zahnpasta'",
        "maxLength": 100,
        "minLength": 2,
        "type": "string"
      }
    },
    "required": [
      "query"
    ],
    "type": "object"
  },
  "provenance": {
    "method": "har",
    "notes": "GET /suche?q=…: the HTML already contains the first page of product tiles (div[data-testid=product-tile]). Name = link title attribute; URL = link href (relative /p/… joined to the origin); price = p[aria-label^='Preis:'] text such as '€ 7,49'; rating from the aria-label 'Produktbewertung 5 von 5 Sternen (8 Bewertungen).'. Brand, size and unit price are not returned because only hashed CSS-in-JS classes identify them. The 'Mehr laden' button loads more products by a request not in the trace, so only the first page is returned. Hashed classes were avoided. No cross-site hosts are called. Products carrying the sponsored-footnote marker were not seen in the trace; none are filtered. Builder notes: - The trace is a server-rendered search page (`/suche?q=`) with product tiles, so I use HTML extraction. There is no JSON API call in the trace. - Selectors avoid the hashed CSS-in-JS classes, which change on deploy. They rely on `data-testid`, `aria-label` and link attributes. - Only the first page (about 20 products) is in the HTML. \"Mehr laden\" is a UI action whose request is not in the trace, so the recipe does not page. - Brand and unit size are not extracted because they only have hashed-class selectors.",
    "recorded_at": "2026-11-08T14:59:47.916Z",
    "recorded_by": "wield-build (claude-haiku-5-5)"
  },
  "requires_login": false,
  "schema": "https://wield.run/schema/recipe/v1.json",
  "site": {
    "country": "AT",
    "id": "bipa.at",
    "language": "de",
    "name": "BIPA",
    "origin": "https://www.bipa.at",
    "origins": [
      "https://www.bipa.at"
    ]
  },
  "steps": [
    {
      "description": "Server-rendered search results page /suche?q=…; read-only GET. Product tiles are div[data-testid=product-tile]; name comes from the link title, price from the price paragraph, rating from its aria-label.",
      "expect": {
        "assert": "status == `200` && (contains(body, 'product-list-page') || contains(body, 'Suchergebnis'))",
        "content_type": "html",
        "status": [
          200
        ]
      },
      "extract": {
        "html_items": {
          "products": {
            "fields": {
              "href": {
                "attr": "href",
                "selector": "a[data-testid^='product-tile']"
              },
              "name": {
                "attr": "title",
                "selector": "a[data-testid^='product-tile']"
              },
              "price": {
                "selector": "p[aria-label^='Preis:']"
              },
              "rating_label": {
                "attr": "aria-label",
                "selector": "[aria-label^='Produktbewertung']"
              }
            },
            "max": 60,
            "selector": "[data-testid='product-tile']"
          }
        }
      },
      "id": "search",
      "request": {
        "headers": {
          "Accept": "text/html"
        },
        "method": "GET",
        "query": {
          "q": "{{params.query}}"
        },
        "url": "/suche"
      }
    }
  ],
  "task": "Search BIPA drugstore products",
  "tos": {
    "notes": "Not reviewed. One search page per call, the same page a visitor loads; no basket, account or checkout calls. The site's terms on automated access were not checked.",
    "reviewed": false
  },
  "verify": {
    "checks": [
      "length(output.products) > `0`",
      "length(output.products[?price_eur > `0`]) > `0`",
      "length(output.products[?starts_with(url, 'https://www.bipa.at/p/')]) == length(output.products)",
      "length(output.products[?name != `null`]) == length(output.products)"
    ],
    "example_params": {
      "query": "shampoo"
    },
    "max_ms": 5000
  },
  "version": 1
}