DEV Community

BuyWhere
BuyWhere

Posted on

Build a Real-Time Price Alert Engine with BuyWhere MCP

Build a Real-Time Price Alert Engine with BuyWhere MCP

Price drops happen fast. A product that's $50 today can be $35 tomorrow — and if your
shopping agent isn't watching, your users miss the window.

In this post we'll build a real-time price alert engine using BuyWhere MCP. It monitors
products you care about, checks prices at a configurable interval, and fires a webhook
(or prints to console) when the price crosses your threshold.

What we're building

User adds: "Sony WH-1000XM5 headphones"
Alert threshold: -15% from current price
→ Bot checks prices every 6 hours
→ Fires alert when price drops ≥ 15%
Enter fullscreen mode Exit fullscreen mode

Full source: ~120 lines of Python. No cron service required — the loop runs in a single script.

Prerequisites

pip install buywhere-mcp mcp  # or import from the MCP server directly
Enter fullscreen mode Exit fullscreen mode

You'll also need a BuyWhere API key. Free tier at api.buywhere.ai.

Step 1 — Search and pick the product

import json
from buywhere import MCPClient

client = MCPClient()

# Search across all markets
results = client.search_products(
    query="Sony WH-1000XM5",
    markets=["SG", "MY", "TH", "US"],
    limit=3
)

# Pick the lowest-priced listing
best = min(results, key=lambda p: p["price"])
print(f"Tracking {best['name']} @ {best['price']} {best['currency']} ({best['market']})")
print(f"  URL: {best['url']}")
print(f"  Last updated: {best['price_updated_at']}")
Enter fullscreen mode Exit fullscreen mode

The response includes price_updated_at — a timestamp of when the price was last confirmed.
This is critical for alert quality: don't alert on stale prices.

Step 2 — Set up the monitoring loop

import time
from datetime import datetime, timedelta

class PriceAlertEngine:
    def __init__(self, api_key, check_interval_hours=6, drop_threshold_pct=15.0):
        self.client = MCPClient(api_key=api_key)
        self.interval = check_interval_hours * 3600
        self.threshold = drop_threshold_pct / 100.0
        self.watched = {}  # product_id -> baseline

    def add_product(self, product_id, name):
        """Register a product and capture baseline price."""
        product = self.client.get_product(product_id)
        self.watched[product_id] = {
            "name": name,
            "baseline": product["price"],
            "currency": product["currency"],
            "market": product["market"],
            "url": product["url"],
        }
        print(f"[+] Watching {name}: baseline ${product['price']}")

    def check_all(self):
        """Poll all watched products and fire alerts on threshold breach."""
        for pid, info in self.watched.items():
            current = self.client.get_product(pid)
            baseline = info["baseline"]
            price_now = current["price"]
            pct_change = (price_now - baseline) / baseline

            print(f"  {info['name']}: ${price_now} (was ${baseline}, {pct_change*100:+.1f}%)")

            if pct_change <= -self.threshold:
                self._fire_alert(info, price_now, baseline, pct_change)
                # Update baseline so we don't re-alert on same drop
                self.watched[pid]["baseline"] = price_now

    def _fire_alert(self, product_info, current, baseline, pct):
        print(f"\n🚨 PRICE DROP ALERT: {product_info['name']}")
        print(f"   Was: ${baseline} → Now: ${current} ({pct*100:.1f}%)")
        print(f"   Shop: {product_info['url']}\n")
        # Replace with webhook POST, Slack message, email, etc.

    def run(self):
        """Main loop — runs forever, checks every self.interval seconds."""
        while True:
            print(f"\n[{datetime.utcnow().isoformat()}Z] Running price check...")
            self.check_all()
            print(f"Sleeping {self.interval/3600}h until next check.")
            time.sleep(self.interval)


# --- Usage ---
engine = PriceAlertEngine(
    api_key=os.environ["BUYWHERE_API_KEY"],
    check_interval_hours=6,
    drop_threshold_pct=15.0
)

# Add products by search (or load from a database/CSV)
results = client.search_products("Sony WH-1000XM5 headphones", markets=["SG"], limit=1)
engine.add_product(results[0]["product_id"], results[0]["name"])

engine.run()
Enter fullscreen mode Exit fullscreen mode

Key design decisions

Stale-price guard

The price_updated_at field is your staleness signal. Before alerting, check:

stale_cutoff = datetime.utcnow() - timedelta(hours=24)
price_time = datetime.fromisoformat(product["price_updated_at"].replace("Z", "+00:00"))
if price_time < stale_cutoff:
    print(f"[!] Price data is >24h old — skipping alert for {name}")
    continue
Enter fullscreen mode Exit fullscreen mode

An alert on a 3-day-old price is worse than no alert at all.

Baseline drift

After an alert fires, update the baseline to the new price. Otherwise a 20% drop followed
by a 5% recovery immediately triggers a second alert at the -15% mark. Updating baseline
prevents alert noise.

Multi-market aggregation

If you're watching the same product across SG, MY, and TH, alert on the lowest current
price — your users care about where to buy, not which market's price changed.

cross_market = client.search_products(
    query=product_name,
    markets=["SG", "MY", "TH"],
    limit=5
)
lowest = min(cross_market, key=lambda p: p["price"])
Enter fullscreen mode Exit fullscreen mode

Deployment

This script runs on any VPS, Raspberry Pi, or even a laptop. For production use,
wrap it in a systemd service:

[Unit]
Description=BuyWhere Price Alert Engine
After=network.target

[Service]
Type=simple
User=alerts
WorkingDirectory=/opt/price-alerts
ExecStart=/usr/bin/python3 /opt/price-alerts/alert_engine.py
Restart=on-failure
Environment=BUYWHERE_API_KEY=<your-key>

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Or deploy to Railway — the MCP client connects to api.buywhere.ai from anywhere.

What's next

  • Multi-user mode: store baselines per-user in a Postgres table, expose a simple REST API for adding/removing watches
  • Telegram/Slack integration: swap _fire_alert for requests.post() to your bot endpoint
  • Threshold learning: store the last 30 days of prices per product and alert on statistical drops (e.g., price below 1 standard deviation) rather than fixed percentages

The full code (with imports, error handling, and environment config) is on GitHub.
Link in the comments.


This is part of the "BuyWhere MCP in practice" series. Previous posts covered
building a Discord shopping bot,
building a Slack deal-alert bot,
and query pattern strategies.

Top comments (0)