Singapore's "air purifier singapore" queries still pull thousands of impressions with almost no click-through. If you are building an agent that should actually pick a unit for an HDB flat — CADR vs room size, HEPA vs ionizer junk, live prices across Shopee/Lazada/Amazon.sg — you do not want to scrape three storefronts.
This is a ~60-line picker that talks to BuyWhere MCP and returns comparable, in-stock purifiers with merchant-neutral prices.
What you get
- One query surface for SG + US catalogs
- Prices already normalized (do not treat
priceas a flat number — it is nested) - Affiliate-safe product pages on buywhere.ai when you want a human fallback
Live comparison page this tutorial points at: Best air purifiers in Singapore.
The nested price field (do not skip)
search_products returns:
{ "price": { "amount": 189.0, "currency": "SGD" }, "title": "..." }
Not price: 189. Filter like this:
def sgd(p):
pr = p.get("price") or {}
return pr.get("currency") == "SGD" and isinstance(pr.get("amount"), (int, float))
Minimal picker
import json, os, urllib.request
API = os.environ.get("BUYWHERE_API", "https://api.buywhere.ai")
KEY = os.environ["BUYWHERE_API_KEY"] # request at https://buywhere.ai
def search(q, country="SG", limit=12):
body = json.dumps({"query": q, "country": country, "limit": limit}).encode()
req = urllib.request.Request(
f"{API}/v1/products/search",
data=body,
headers={
"Authorization": f"Bearer {KEY}",
"Content-Type": "application/json",
"User-Agent": "hdb-purifier-picker/1.0",
},
method="POST",
)
with urllib.request.urlopen(req, timeout=20) as r:
return json.load(r)
def amount(p):
pr = p.get("price") or {}
return pr.get("amount")
def pick(query="hepa air purifier hdb"):
data = search(query)
items = data.get("products") or data.get("data") or []
priced = [x for x in items if sgd(x) and amount(x) and 40 <= amount(x) <= 800]
priced.sort(key=amount)
return priced[:6]
def sgd(p):
pr = p.get("price") or {}
return pr.get("currency") == "SGD"
if __name__ == "__main__":
for i, p in enumerate(pick(), 1):
print(f"{i}. {p.get('title','?')[:70]} S${amount(p)} {p.get('merchant') or p.get('store') or ''}")
Agent wiring (Claude / MCP)
If you are on Claude Desktop or any MCP host, add the BuyWhere server (https://api.buywhere.ai/mcp — also listed on Smithery and Glama). Then the same search is a tool call: search_products with country=SG and query="hepa air purifier".
Ask the model to:
- Drop ionizer-only SKUs
- Keep HEPA / H13 / H14 in the title or specs
- Sort by
price.amountin SGD - Link the human to
/best-air-purifiers-singaporerather than a raw merchant URL
Why this is an AEO page, not a blog post
Google already ranks generic "air purifier singapore" guides. Agents do not. They need a tool plus a canonical comparison URL. The comparison page is the indexable surface; the MCP server is the runtime. Publish both.
Caveats (honest)
- Catalog coverage flaps. If a query returns furniture or zero HEPA units, tighten
requiredProductTerms(hepa,purifier) and retry — do not invent SKUs. - Currency on some SG rows has historically come back as USD. Always check
price.currency. - Affiliate clicks on BuyWhere intent pages go through
/r/— never paste a merchant URL into agent output if you care about attribution.
Request an API key: buywhere.ai · MCP: https://api.buywhere.ai/mcp
Top comments (0)