Overview
This workflow monitors product prices daily across Amazon and Walmart, compares against stored baselines, and fires alerts when prices change beyond a configurable threshold. It handles both price drops (deal alerts) and price increases (competitive intelligence), with separate notification channels for each direction.
Trigger
Cron schedule (daily at 8 AM UTC)
Schedule
Runs daily at 8 AM UTC
Workflow Steps
Load product watchlist
Read the list of products to monitor with their target platforms and alert thresholds.
Fetch current prices
Query Scavio for each product on Amazon and Walmart to get current listing prices.
Compare against baseline
Load yesterday's prices and compute absolute and percentage changes.
Categorize alerts
Separate price changes into drops (deals) and increases (competitive alerts) based on direction.
Send notifications
Route deal alerts and competitive alerts to their respective channels.
Update baseline
Store today's prices as the new baseline for tomorrow's comparison.
Python Implementation
import requests
import json
from pathlib import Path
from datetime import datetime
API_KEY = "your_scavio_api_key"
DEAL_WEBHOOK = "https://hooks.slack.com/services/YOUR/DEALS/WEBHOOK"
COMPETITIVE_WEBHOOK = "https://hooks.slack.com/services/YOUR/COMPETITIVE/WEBHOOK"
THRESHOLD_PCT = 5.0
def fetch_price(query: str, platform: str) -> float | None:
res = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"platform": platform, "query": query},
timeout=15,
)
res.raise_for_status()
for item in res.json().get("organic", []):
if item.get("price"):
return item["price"]
return None
def run():
watchlist = json.loads(Path("price_watchlist.json").read_text())
baseline_path = Path("price_baseline.json")
baseline = json.loads(baseline_path.read_text()) if baseline_path.exists() else {}
deals = []
increases = []
for item in watchlist:
for platform in item.get("platforms", ["amazon", "walmart"]):
key = f"{item['slug']}_{platform}"
current = fetch_price(item["query"], platform)
previous = baseline.get(key)
if current and previous:
pct_change = ((current - previous) / previous) * 100
if pct_change <= -THRESHOLD_PCT:
deals.append({
"product": item["query"],
"platform": platform,
"was": previous,
"now": current,
"drop_pct": round(abs(pct_change), 1),
})
elif pct_change >= THRESHOLD_PCT:
increases.append({
"product": item["query"],
"platform": platform,
"was": previous,
"now": current,
"increase_pct": round(pct_change, 1),
})
if current:
baseline[key] = current
baseline_path.write_text(json.dumps(baseline, indent=2))
if deals:
msg = f"Price Drop Alert ({len(deals)} products):\n"
for d in deals:
msg += f" {d['product']} on {d['platform']}: {d['was']} -> {d['now']} (-{d['drop_pct']}%)\n"
requests.post(DEAL_WEBHOOK, json={"text": msg}, timeout=10)
if increases:
msg = f"Price Increase Alert ({len(increases)} products):\n"
for i in increases:
msg += f" {i['product']} on {i['platform']}: {i['was']} -> {i['now']} (+{i['increase_pct']}%)\n"
requests.post(COMPETITIVE_WEBHOOK, json={"text": msg}, timeout=10)
print(f"Checked {len(watchlist)} products: {len(deals)} drops, {len(increases)} increases")
if __name__ == "__main__":
run()JavaScript Implementation
const API_KEY = "your_scavio_api_key";
const DEAL_WEBHOOK = "https://hooks.slack.com/services/YOUR/DEALS/WEBHOOK";
const COMPETITIVE_WEBHOOK = "https://hooks.slack.com/services/YOUR/COMPETITIVE/WEBHOOK";
const THRESHOLD_PCT = 5.0;
async function fetchPrice(query, platform) {
const res = await fetch("https://api.scavio.dev/api/v1/search", {
method: "POST",
headers: { "x-api-key": API_KEY, "content-type": "application/json" },
body: JSON.stringify({ platform, query }),
});
if (!res.ok) throw new Error(`scavio ${res.status}`);
for (const item of (await res.json()).organic ?? []) {
if (item.price) return item.price;
}
return null;
}
async function run() {
const fs = await import("fs/promises");
const watchlist = JSON.parse(await fs.readFile("price_watchlist.json", "utf8"));
let baseline = {};
try { baseline = JSON.parse(await fs.readFile("price_baseline.json", "utf8")); } catch {}
const deals = [];
const increases = [];
for (const item of watchlist) {
for (const platform of item.platforms ?? ["amazon", "walmart"]) {
const key = `${item.slug}_${platform}`;
const current = await fetchPrice(item.query, platform);
const previous = baseline[key];
if (current && previous) {
const pctChange = ((current - previous) / previous) * 100;
if (pctChange <= -THRESHOLD_PCT) {
deals.push({ product: item.query, platform, was: previous, now: current, dropPct: Math.round(Math.abs(pctChange) * 10) / 10 });
} else if (pctChange >= THRESHOLD_PCT) {
increases.push({ product: item.query, platform, was: previous, now: current, increasePct: Math.round(pctChange * 10) / 10 });
}
}
if (current) baseline[key] = current;
}
}
await fs.writeFile("price_baseline.json", JSON.stringify(baseline, null, 2));
if (deals.length) {
const msg = `Price Drop Alert (${deals.length} products):\n` + deals.map((d) => ` ${d.product} on ${d.platform}: $${d.was} -> $${d.now} (-${d.dropPct}%)`).join("\n");
await fetch(DEAL_WEBHOOK, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ text: msg }) });
}
if (increases.length) {
const msg = `Price Increase Alert (${increases.length} products):\n` + increases.map((i) => ` ${i.product} on ${i.platform}: $${i.was} -> $${i.now} (+${i.increasePct}%)`).join("\n");
await fetch(COMPETITIVE_WEBHOOK, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ text: msg }) });
}
console.log(`Checked ${watchlist.length} products: ${deals.length} drops, ${increases.length} increases`);
}
run();Platforms Used
Amazon
Product search with prices, ratings, and reviews
Walmart
Product search with pricing and fulfillment data