Price is the single biggest lever in ecommerce. A 1% price advantage can mean the difference between winning and losing the buy box on Amazon, or converting a customer on your own store. Yet most businesses still check competitor prices manually — if they check at all.
In this guide, we'll build a price monitoring dashboard that automatically tracks product prices across ecommerce sites and alerts you when competitors change their pricing.
What We're Building
By the end of this tutorial, you'll have:
- A Python script that pulls product prices from Amazon, eBay, and other retailers via MultiCartAPI
- A SQLite database that stores price history over time
- A simple dashboard that visualises price trends
- Email alerts when prices drop below your thresholds
Architecture Overview
MultiCartAPI ──→ Price Collector (Python) ──→ SQLite Database
│
Dashboard (Flask)
│
Email Alerts
The system runs on a simple cron job. Every hour, the collector fetches current prices and stores them. The dashboard reads from the same database.
Step 1: Set Up the Price Collector
First, install the dependencies:
pip install requests sqlite3 smtplib
Create the collector script:
import requests
import sqlite3
import json
from datetime import datetime
API_KEY = "your_multicartapi_key"
BASE_URL = "https://multicartapi.com/api/v1"
# Products to monitor
PRODUCTS = [
{"asin": "B0DFJJFL4M", "domain": "com.au", "name": "AirPods Pro 2"},
{"asin": "B0CHX3QBCH", "domain": "com.au", "name": "iPad Air M2"},
{"asin": "B0BDJ279KF", "domain": "com.au", "name": "Kindle Paperwhite"},
]
def init_db():
conn = sqlite3.connect("prices.db")
conn.execute("""
CREATE TABLE IF NOT EXISTS price_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
asin TEXT NOT NULL,
domain TEXT NOT NULL,
product_name TEXT,
price REAL,
currency TEXT,
in_stock BOOLEAN,
seller TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS alerts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
asin TEXT NOT NULL,
threshold REAL NOT NULL,
email TEXT NOT NULL,
active BOOLEAN DEFAULT 1
)
""")
conn.commit()
return conn
def fetch_price(asin, domain):
response = requests.get(
f"{BASE_URL}/amazon/product",
params={"asin": asin, "domain": domain},
headers={"Authorization": f"Bearer {API_KEY}"},
)
if response.status_code == 200:
data = response.json()
return {
"price": data.get("price", {}).get("current"),
"currency": data.get("price", {}).get("currency", "AUD"),
"in_stock": data.get("availability", {}).get("in_stock", False),
"seller": data.get("availability", {}).get("fulfilment", "Unknown"),
}
return None
def collect_prices():
conn = init_db()
for product in PRODUCTS:
result = fetch_price(product["asin"], product["domain"])
if result and result["price"]:
conn.execute(
"""INSERT INTO price_history
(asin, domain, product_name, price, currency, in_stock, seller)
VALUES (?, ?, ?, ?, ?, ?, ?)""",
(
product["asin"],
product["domain"],
product["name"],
result["price"],
result["currency"],
result["in_stock"],
result["seller"],
),
)
print(f" {product['name']}: ${result['price']} {result['currency']}")
conn.commit()
conn.close()
if __name__ == "__main__":
print(f"Collecting prices at {datetime.now()}")
collect_prices()
print("Done.")
Step 2: Schedule Regular Collection
Add a cron job to run the collector every hour:
crontab -e
0 * * * * cd /path/to/project && python collect_prices.py >> /var/log/price-monitor.log 2>&1
This gives you 24 data points per day per product — enough to spot trends without burning through API credits.
Step 3: Build the Dashboard
Create a minimal Flask dashboard to visualise the data:
from flask import Flask, render_template_string
import sqlite3
import json
app = Flask(__name__)
DASHBOARD_HTML = """
<!DOCTYPE html>
<html>
<head>
<title>Price Monitor</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body { font-family: system-ui; max-width: 1200px; margin: 0 auto; padding: 20px; }
.product-card { border: 1px solid #e0e0e0; border-radius: 8px; padding: 20px; margin: 16px 0; }
.price { font-size: 2em; font-weight: bold; color: #2563eb; }
.change-up { color: #dc2626; }
.change-down { color: #16a34a; }
canvas { max-height: 300px; }
</style>
</head>
<body>
<h1>Price Monitor Dashboard</h1>
{% for product in products %}
<div class="product-card">
<h2>{{ product.name }}</h2>
<div class="price">${{ "%.2f"|format(product.current_price) }} {{ product.currency }}</div>
{% if product.price_change != 0 %}
<span class="{{ 'change-up' if product.price_change > 0 else 'change-down' }}">
{{ "%.2f"|format(product.price_change) }} ({{ "%.1f"|format(product.price_change_pct) }}%)
</span>
{% endif %}
<canvas id="chart-{{ loop.index }}"></canvas>
</div>
<script>
new Chart(document.getElementById('chart-{{ loop.index }}'), {
type: 'line',
data: {
labels: {{ product.dates | tojson }},
datasets: [{
label: 'Price',
data: {{ product.prices | tojson }},
borderColor: '#2563eb',
tension: 0.1
}]
}
});
</script>
{% endfor %}
</body>
</html>
"""
@app.route("/")
def dashboard():
conn = sqlite3.connect("prices.db")
products = []
for row in conn.execute("SELECT DISTINCT asin, domain, product_name FROM price_history"):
asin, domain, name = row
history = conn.execute(
"SELECT price, currency, timestamp FROM price_history WHERE asin=? ORDER BY timestamp DESC LIMIT 168",
(asin,)
).fetchall()
if not history:
continue
current = history[0][0]
previous = history[1][0] if len(history) > 1 else current
products.append({
"name": name,
"current_price": current,
"currency": history[0][1],
"price_change": current - previous,
"price_change_pct": ((current - previous) / previous * 100) if previous else 0,
"dates": [h[2][:10] for h in reversed(history)],
"prices": [h[0] for h in reversed(history)],
})
conn.close()
return render_template_string(DASHBOARD_HTML, products=products)
if __name__ == "__main__":
app.run(port=5000, debug=True)
Step 4: Add Price Drop Alerts
Extend the collector to check thresholds and send alerts:
import smtplib
from email.mime.text import MIMEText
def check_alerts(conn, asin, current_price, product_name):
alerts = conn.execute(
"SELECT email, threshold FROM alerts WHERE asin=? AND active=1",
(asin,)
).fetchall()
for email, threshold in alerts:
if current_price <= threshold:
send_alert(email, product_name, current_price, threshold)
def send_alert(to_email, product_name, price, threshold):
msg = MIMEText(
f"{product_name} has dropped to ${price:.2f}, "
f"which is below your threshold of ${threshold:.2f}.\n\n"
f"Check your dashboard for details."
)
msg["Subject"] = f"Price Alert: {product_name} is now ${price:.2f}"
msg["From"] = "[email protected]"
msg["To"] = to_email
with smtplib.SMTP("localhost") as server:
server.send_message(msg)
Scaling Beyond Amazon
The same approach works for any retailer that MultiCartAPI supports. Add Walmart, eBay, or specialty retailers to your monitoring list:
# Monitor the same product across multiple retailers
CROSS_RETAILER = [
{"source": "amazon", "id": "B0DFJJFL4M", "domain": "com.au"},
{"source": "ebay", "id": "12345678", "domain": "com.au"},
{"source": "walmart", "id": "987654", "domain": "com"},
]
This gives you a complete picture of competitive pricing across the market, not just within a single marketplace.
Key Takeaways
- Automate early — Manual price checking doesn't scale. Set up automated collection from day one.
- Store history — Current prices are useful. Price trends over time are powerful. Always store historical data.
- Alert, don't poll — Build alerts so you only look at the dashboard when something changes.
- Use structured data — MultiCartAPI returns clean JSON, so you spend time analysing data instead of parsing HTML.
Next Steps
- Add more products and retailers to your monitoring list
- Build weekly price reports that summarise trends
- Integrate with your pricing engine to auto-adjust prices based on competitor movements
- Check out our API documentation for the full list of supported retailers and data fields
