{
  "source_agent_id": "wsa_a91293334c1f445cab1e998a66c240d8",
  "exported_at": "2026-10-15",
  "agent_name": "retail-pdp-from-category",
  "display_name": "Retail PDP · category to product details",
  "description": "Given a retailer and a category or brand listing (URL or name), enumerates every product listed and returns one row of product detail page (PDP) data per product: identity, price, promotion, stock, size, rating, reviews and category path, each taken from the retailer's own PDP.",
  "use_case": "dataset_building",
  "effort": "high",
  "sources": {"allow": [], "block": [], "prioritize": "The named retailer's own category, brand listing and product detail pages", "avoid": "Other retailers, price-comparison sites, affiliate and coupon sites, Google Shopping"},
  "suggested_questions": ["Retailer: lookfantastic.com. Listing: the Medik8 brand page. Return PDP data for every Medik8 product listed."],
  "output_schema": {"type": "array", "items": {"type": "object", "required": ["retailer", "product_name", "brand", "product_url", "price", "currency", "in_stock", "observed_at"], "properties": {
    "size": {"type": ["string", "null"]},
    "brand": {"type": "string", "description": "Brand shown on the PDP. On a brand listing, retailer gift sets, advent calendars or other cross-brand tiles keep their true brand here so they can be filtered out."},
    "price": {"type": "string", "description": "Current PDP price, number only"},
    "rating": {"type": ["string", "null"]},
    "currency": {"type": "string"},
    "in_stock": {"type": "boolean"},
    "retailer": {"type": "string", "description": "Retailer domain, e.g. lookfantastic.com"},
    "image_url": {"type": ["string", "null"]},
    "was_price": {"type": ["string", "null"], "description": "Struck-through or RRP price shown on PDP"},
    "listing_url": {"type": "string", "description": "Category or brand listing URL the product was found on"},
    "observed_at": {"type": "string"},
    "product_url": {"type": "string", "description": "Canonical PDP URL without tracking parameters"},
    "product_name": {"type": "string"},
    "review_count": {"type": ["string", "null"]},
    "category_path": {"type": ["string", "null"]},
    "variant_count": {"type": ["string", "null"]},
    "promotion_text": {"type": ["string", "null"]},
    "is_listing_brand": {"type": ["boolean", "null"], "description": "True if the product's brand matches the brand of the listing (for brand listings); null for category listings"},
    "listing_position": {"type": ["string", "null"], "description": "1-based position on the listing in default sort"},
    "retailer_product_id": {"type": ["string", "null"]},
    "listing_total_reported": {"type": ["string", "null"], "description": "Product count the listing page itself reports"}
  }}},
  "skill": "Purpose: for the retailer and category or brand listing given in the input, list every product on that listing and return one row per product with data read from that product's own product detail page (PDP) on the same retailer.\n\nScope:\n- Retailer and listing are hard constraints. Use only the named retailer's domain (including its regional subdomain if given). A product counts only if it appears on the named listing.\n- Read the listing in full: every page of pagination, \"load more\" and infinite scroll, in the listing's default sort. Record the number of products the listing itself reports (e.g. \"69 results\") in listing_total_reported on every row.\n- Then open each product's PDP. Every field except listing_position and listing_total_reported must come from the PDP, not the listing tile.\n\nCoverage check (mandatory before finishing):\n- Compare your row count with listing_total_reported and check that listing_position runs 1..N with no gaps. Position 1 and the first tile of every page are the most often missed; sponsored or featured tiles at the top of the grid count as listed products.\n- If any position is missing, go back to the listing page that holds it, identify the product and read its PDP. Only finish with fewer rows than reported if a tile has no working PDP, and then say so in that row by returning it with product_url set to the tile link and price empty.\n\nRow granularity:\n- One row per listing tile. If the retailer lists strengths, sizes or refills of the same range as separate tiles with separate PDPs, each tile is its own row. Do not merge tiles; do not split one tile into several rows. variant_count records how many selectable options the PDP for that tile offers.\n\nField rules:\n- product_url is the canonical PDP URL on the retailer's domain, without tracking parameters.\n- retailer_product_id is the retailer's own SKU or product ID as shown on the PDP or in its URL. Leave empty if not shown.\n- price is the current selling price for the default selected variant, as a number string without currency symbol. was_price is the struck-through or RRP price only if the PDP shows one. promotion_text copies any promo or discount text shown on the PDP verbatim.\n- currency is the ISO code (GBP for lookfantastic.com).\n- in_stock is true only if the add-to-basket control is active for the default variant; false if out of stock or notify-me.\n- size is the pack size or volume of the default selected variant. If the product name does not include it, read it from the selected variant option or the product details section. For bundles and gift sets, leave empty.\n- rating and review_count are the retailer's own on-PDP values. Leave empty if the PDP shows none. Do not use third-party ratings.\n- category_path is the full PDP breadcrumb trail joined with \" > \" (e.g. \"Home > Brands > Medik8 > Medik8 Cleansers\"). If the PDP shows only \"Home\", look for the breadcrumb in the page's structured data before accepting \"Home\".\n- observed_at is the ISO 8601 UTC time that this specific PDP was read, not a single time for the whole run.\n- Never estimate, carry over from the listing tile, or fill from other retailers. Leave a field empty rather than guess."
}
