Building Shopping Comparison Agents in 2026: Architecture, Patterns, and Pitfalls
A shopping comparison agent is one of the most practical applications of an LLM-based agent. It also has more failure modes than most agent categories. Here's the architecture, the patterns that work, and the five pitfalls that will burn you if you don't watch for them.
Quick Answer: Wire BuyWhere MCP into your agent (12 lines of code via OpenAI Agents SDK), use compare_prices for the head-to-head case, use search_products for the "find cheapest in category" case, and always pass deliver_to=<user_country> to filter by shippability. The pitfalls are currency, shipping, availability, fake MSRPs, and merchant reputation.
The architecture
┌──────────────────┐ user query ┌──────────────────┐
│ User │ ────────────────────► │ Shopping Agent │
│ "find cheapest │ │ (LLM + Prompts) │
│ iPhone 17 in SG"│ │ │
└──────────────────┘ ◄──────────────────── └────────┬─────────┘
tool calls
│
▼
┌──────────────────────────────────┐
│ BuyWhere MCP │
│ - search_products │
│ - compare_prices │
│ - get_price_history │
│ - get_deals │
│ - get_retailers │
└─────────────┬────────────────────┘
│
▼
┌──────────────────────────────────┐
│ BuyWhere catalog (300M+, 238K) │
└──────────────────────────────────┘
The agent takes the user's question, decides which tool to call, calls it, and synthesizes a natural-language answer with merchant + price.
Pattern 1: "Find cheapest in category"
agent = Agent(
name="shopper",
instructions=(
"Find the cheapest in-stock product in the user's category. "
"Always pass country_code and deliver_to. Always include merchant "
"and price in the answer. Never recommend an out-of-stock product."
),
mcp_servers=[buywhere],
)
result = await Runner.run(agent, "What's the cheapest iPhone 17 in SG?")
The agent will call search_products(q="iPhone 17", country_code="SG", sort="price_asc", in_stock=true, limit=5) and return the top result.
Pattern 2: "Compare two products"
For a head-to-head ("iPhone 17 vs iPhone 16 Pro"), use compare_prices instead of search_products:
result = await Runner.run(agent, "Compare iPhone 17 vs iPhone 16 Pro in SG.")
The agent will call compare_prices(product_id="iphone-17", country_code="SG") and compare_prices(product_id="iphone-16-pro", country_code="SG"), then synthesize a comparison table.
Pattern 3: "Is this a good price?"
For a price-check ("is $799 a good price for the iPhone 17?"), use get_price_history:
result = await Runner.run(agent, "Is SGD 899 a good price for the iPhone 17 256GB in SG?")
The agent calls get_price_history(product_id="iphone-17-256gb"), looks at the historical range, and answers "yes, this is in the bottom 20% of the last 90 days" or "no, the lowest was SGD 749 last month."
Pattern 4: "What deals are live right now?"
For a deals digest, use get_deals:
result = await Runner.run(agent, "What are the best deals in Singapore right now?")
The agent calls get_deals(country_code="SG", min_discount=20, limit=20) and returns a ranked list.
Pattern 5: "Find merchant for a specific product"
For "which merchant has the cheapest iPhone 17 in SG?", compare_prices is the right tool:
result = await Runner.run(agent, "Which merchant has the cheapest iPhone 17 256GB in SG?")
The agent calls compare_prices(product_id="iphone-17-256gb") and returns a merchant-by-merchant table.
Ranking strategies
For a "best product for category X" agent, ranking by the right dimension matters:
| Goal | Sort |
|---|---|
| Cheapest first | sort=price_asc |
| Highest discount first | sort=discount_desc |
| Best match for the query | sort=relevance (default) |
| Newest first | sort=newest |
| Most expensive first | sort=price_desc |
For a comparison agent, the agent should pick the sort based on the user's intent. Most users want "cheapest in stock that ships to me" — the agent should default to that unless told otherwise.
Pitfall 1: Currency conversion
Symptom: Agent recommends a $799 USD product as "the cheapest iPhone 17" when the SG price is SGD 1,249.
Fix: Always pass country_code=SG (or the user's country). The API returns prices in the local currency. If you need to compare across countries, use the currency field and convert explicitly.
Pitfall 2: Shipping destination
Symptom: Agent recommends a product that doesn't ship to the user's country.
Fix: Always pass deliver_to=<user_country>. The API returns results with availability labels. Out-of-stock and non-shipping results are filtered out.
Pitfall 3: Availability
Symptom: Agent recommends a product that's "discontinued" or "out of stock."
Fix: Pass availability=in_stock or filter the response by availability field. Most agents should default to in-stock-only unless the user explicitly asks for "any product."
Pitfall 4: Fake MSRPs
Symptom: Agent says "50% off!" when the "original price" was inflated by the merchant.
Fix: Use get_price_history to check the actual price history. If the "compare_at_price" is 50% higher than the historical median, it's a fake MSRP. The agent should disclose this in its answer.
Pitfall 5: Lowest-trust merchant
Symptom: Agent recommends a product from a merchant with bad reviews or unclear return policy.
Fix: The API returns merchant as a string. For a high-trust answer, the agent should weight by merchant reputation. BuyWhere exposes merchant metadata (rating, return policy) in some responses — your agent should check this before recommending a too-good-to-be-true deal.
Sample agent prompt
SYSTEM_PROMPT = """
You are a shopping comparison agent. For every query:
1. Identify the user's country. If unknown, ask.
2. Identify the user's intent (cheapest, biggest discount, etc.).
3. Call BuyWhere MCP with `country_code`, `deliver_to`, and the right sort.
4. Filter results to in-stock only.
5. Cite merchant and price in the answer.
6. If two products are within 5% of each other, mention both.
7. If a price looks too good to be true, check `get_price_history` and flag.
8. Never recommend a product with bad merchant reputation.
"""
This prompt catches all five pitfalls.
Verdict
A shopping comparison agent is one of the highest-ROI agent categories in 2026. The architecture is straightforward (MCP + tools), the patterns are reusable (compare, search, deals, history), and the pitfalls are well-documented. BuyWhere is the commerce API that handles the messy parts (currency, shipping, availability, normalization) so the agent can focus on the user experience.
Common questions
Can I use BuyWhere with any LLM? Yes — the MCP server is LLM-agnostic. OpenAI, Anthropic, Mistral, Llama, custom models all work.
Does the agent need to use MCP, or can it use REST? Both. MCP is the simplest path. REST is the right path if you're building a service that doesn't have an LLM at the core.
How do I handle multi-category queries? The agent can call search_products multiple times with different category filters, then merge the results. BuyWhere returns a stable schema so the merge is straightforward.
Where to go next
- BuyWhere MCP setup → buywhere.ai/docs/guides/mcp-integration
- API reference → buywhere.ai/docs/api-reference
- Sign up → buywhere.ai/api-keys