What is a Price Alert System?
A price alert system notifies users when a tracked item’s price drops below their target threshold. Used by Amazon, Google Shopping, Honey, and Camelcamelcamel. The core challenge: millions of users have set alerts on millions of products. When any product’s price changes, efficiently find and notify only the users whose threshold has been crossed — without scanning all alerts.
Requirements
- Users set price alerts: “notify me when product X drops below $Y”
- Process 100K product price changes per hour
- Evaluate millions of alerts per price change in <5 seconds
- Send notifications via email, push, and in-app
- Deduplicate: don’t notify the same user twice for the same alert until the price recovers above their threshold
- Alert management: list, pause, delete alerts
Data Model
PriceAlert(
alert_id UUID PRIMARY KEY,
user_id UUID NOT NULL,
product_id UUID NOT NULL,
target_price DECIMAL(10,2) NOT NULL, -- notify when price <= this
status ENUM(ACTIVE, TRIGGERED, PAUSED, DELETED),
created_at TIMESTAMPTZ,
last_triggered_at TIMESTAMPTZ,
INDEX (product_id, target_price) -- critical for efficient evaluation
)
ProductPrice(
product_id UUID PRIMARY KEY,
current_price DECIMAL(10,2),
previous_price DECIMAL(10,2),
updated_at TIMESTAMPTZ
)
AlertNotification(
notification_id UUID PRIMARY KEY,
alert_id UUID,
user_id UUID,
product_id UUID,
triggered_price DECIMAL(10,2),
sent_via VARCHAR[], -- ['email', 'push']
sent_at TIMESTAMPTZ
)
Efficient Alert Evaluation
When product X’s price changes to $45: find all ACTIVE alerts for product X with target_price >= $45 (i.e., threshold crossed).
def evaluate_alerts(product_id, new_price, old_price):
if new_price >= old_price:
return # price went up — no alerts to trigger
# Find all alerts whose threshold is now crossed
alerts = db.query('''
SELECT * FROM PriceAlert
WHERE product_id = :pid
AND status = 'ACTIVE'
AND target_price >= :new_price
ORDER BY target_price DESC
''', pid=product_id, new_price=new_price)
for alert in alerts:
trigger_alert(alert, new_price)
def trigger_alert(alert, triggered_price):
# Mark as triggered (deduplication — won't fire again until price recovers)
db.update(PriceAlert, alert.id, status='TRIGGERED',
last_triggered_at=now())
# Queue notification
notification_queue.enqueue({
'user_id': alert.user_id,
'alert_id': alert.alert_id,
'product_id': alert.product_id,
'triggered_price': triggered_price,
'target_price': alert.target_price
})
Price Recovery Reset
Once triggered, the alert should re-arm when the price recovers above the threshold:
def on_price_change(product_id, new_price, old_price):
evaluate_alerts(product_id, new_price, old_price)
# Re-arm triggered alerts if price recovered above threshold
if new_price > old_price:
db.execute('''
UPDATE PriceAlert SET status='ACTIVE'
WHERE product_id=:pid
AND status='TRIGGERED'
AND target_price < :new_price
''', pid=product_id, new_price=new_price)
Handling Large Products (Hot Items)
For a popular product with 500K active alerts (e.g., iPhone), evaluating all on every price change is expensive. Optimize:
# Redis sorted set: product → alerts indexed by target_price
# Key: alerts:{product_id}
# Score: target_price
# Member: alert_id
# On price drop to $45: find all alerts with target_price >= 45
triggered_alerts = redis.zrangebyscore(f'alerts:{product_id}', 45, '+inf')
# Process in batches of 1000; publish to Kafka for async notification
for batch in chunks(triggered_alerts, 1000):
kafka.produce('alert-triggers', {'product_id': product_id,
'price': 45.0,
'alert_ids': batch})
Key Design Decisions
- Index on (product_id, target_price) — enables fast range query for alerts whose threshold was crossed
- TRIGGERED status for deduplication — prevents repeat notifications until price recovers above threshold
- Redis sorted set for hot products — O(log n + k) query for alerts with target_price >= new_price; faster than DB for products with many alerts
- Async notification via queue — decouples alert evaluation (fast, synchronous) from notification delivery (slower, may fail)
- Price recovery re-arms alerts — users don’t need to manually reset; alert re-triggers on the next price drop
Price alert and product tracking system design is discussed in Amazon system design interview questions.
Price alert and e-commerce notification systems are discussed in Shopify system design interview preparation.
Price tracking and alert notification system design is covered in Google system design interview guide.
Keep sharpening your system design:
