Monitor Amazon Competitor Pricing Daily
You sell 50 products on Amazon. You have 3-5 competitor ASINs per product. Manually checking 250 listings every morning is a 90-minute task that catches half the price moves and misses the ones that happen overnight. The fix is to push the work onto a scheduler and only look at the alerts.
This guide is for sellers — the persona who wants a dashboard of "where am I losing the Buy Box right now" without writing a scraper from scratch.
Why Competitor Pricing Is Harder to Track Than It Looks
Three problems compound:
Amazon's per-IP rate limits. Scraping 250 listings hourly from a single source gets you flagged within the first run. Even from a clean residential IP, you will need to slow each request to keep the connection alive over the day.
The Buy Box rotates. The price you see at the top of the page is not necessarily one seller's price — it is the current Buy Box winner, which can change every few minutes based on inventory, shipping speed, and seller rating. A price-only view loses this signal.
Variation listings. A single parent ASIN often has 5-20 child variations (sizes, colors, packs). The Buy Box price you see depends on which child is currently selected. Pulling "the price for ASIN X" can mean any of those, and the answer is non-deterministic unless you target a specific child ASIN.
Sale events vs permanent moves. A 20% drop during Prime Day is not the same signal as a 20% drop on a random Tuesday. Your alert logic needs to either de-prioritize known sale windows or compare against a rolling baseline.
The DIY Approach
For a small catalog (~10 ASINs, 2-3 competitors each), a Python loop with sleep works:
import csv
import time
import requests
from bs4 import BeautifulSoup
HEADERS = {
"User-Agent": "Mozilla/5.0 ... Chrome/127.0.0.0 ...",
"Accept-Language": "en-US,en;q=0.9",
}
def fetch_price(asin: str) -> float | None:
r = requests.get(f"https://www.amazon.com/dp/{asin}", headers=HEADERS, timeout=15)
if r.status_code != 200 or "validateCaptcha" in r.url:
return None
soup = BeautifulSoup(r.text, "html.parser")
el = soup.select_one("span.a-price > span.a-offscreen")
if not el:
return None
return float(el.get_text(strip=True).replace("quot;, "").replace(",", ""))
with open("competitors.csv") as f:
rows = list(csv.DictReader(f))
results = []
for row in rows:
price = fetch_price(row["asin"])
results.append({**row, "price": price})
time.sleep(5) # pace yourself
for r in results:
print(r)
Real Limitations
- Sequential scraping is slow. 250 ASINs × 5s pacing = 21 minutes per run. Run it 4× a day and you are at 84 minutes of wall time per day from a single source.
- CAPTCHAs cascade. Once you hit a CAPTCHA, every subsequent request from that IP fails too. You need a way to detect the block and switch IPs.
- No Buy Box winner data. The selector above gets you a price, not the seller. For competitive intelligence, the seller name matters.
What a "scaling failure" looks like in your logs:
2026-05-12 09:14:02 INFO scraping B09V3KXJPB
2026-05-12 09:14:03 WARN B09V3KXJPB returned validateCaptcha
2026-05-12 09:14:08 INFO scraping B0BN93GFMN
2026-05-12 09:14:09 WARN B0BN93GFMN returned validateCaptcha
... <every subsequent request fails>
You scrape 0 useful data points for the rest of the run, and your morning dashboard is empty.
Scaling Beyond a One-Off Script
For 50+ ASINs at hourly cadence, you will add:
Concurrent requests with a rate-limited proxy pool. Run 5-10 concurrent fetches against rotating residential IPs (Bright Data, Smartproxy, Oxylabs). Per-IP pacing matters more than total concurrency.
Persistent state per ASIN. Track the last scraped price, the rolling 30-day median, and the last Buy Box winner. Alert on percentage moves and seller flips, not absolute thresholds.
Webhook destinations. Email is too noisy for 250 watched listings. Pipe alerts into Slack, Discord, or a dedicated #pricing channel. Aggregate by hour during sale events.
Sale-window awareness. Mark known event windows (Prime Day, Black Friday, the seller's own promotional dates) and suppress or downgrade alerts during those. A 15% drop on Prime Day is not news.
A managed monitor system handles the scraping, scheduling, and webhook plumbing. Bulk-create one monitor per ASIN:
import os
import csv
import requests
API_KEY = os.environ["LOGPOSE_API_KEY"]
BASE = "https://api.logposervices.com/api/v1"
HEADERS = {"X-API-Key": API_KEY}
with open("competitors.csv") as f:
rows = list(csv.DictReader(f))
for row in rows:
payload = {
"url": f"https://www.amazon.com/dp/{row['asin']}",
"name": f"{row['product']} — {row['competitor']}",
"metric": "price",
"condition": "changes",
"check_interval_hours": 6,
"notify_channels": ["webhook"],
}
r = requests.post(f"{BASE}/monitors", headers=HEADERS, json=payload)
r.raise_for_status()
monitor_id = r.json()["id"]
print(f"created {monitor_id} for {row['asin']}")
The changes condition fires on any price change. For percentage-based alerts, use drops_below with a threshold calibrated to your rolling baseline — then update the threshold via PATCH /api/v1/monitors/{id} weekly.
To turn the webhook stream into a dashboard:
import sqlite3
from flask import Flask, request
app = Flask(__name__)
conn = sqlite3.connect("prices.db", check_same_thread=False)
conn.execute("""
CREATE TABLE IF NOT EXISTS prices (
monitor_id TEXT, observed_at TEXT, price REAL, url TEXT
)
""")
@app.route("/webhook", methods=["POST"])
def webhook():
data = request.json
conn.execute(
"INSERT INTO prices (monitor_id, observed_at, price, url) VALUES (?,?,?,?)",
(data["monitor_id"], data["observed_at"], data["value"], data["url"]),
)
conn.commit()
return "", 204
Pipe a daily report off the prices table — top 10 movers, longest unchanged, biggest gap to your own price. That is the dashboard.
Common Mistakes
- One monitor for many products. Monitors are per-URL. Bulk-create one per ASIN.
- Email channel for high-frequency events. Inbox dies after 50 alerts. Use webhook or Slack.
- Absolute thresholds. A $5 drop is huge on a $40 product, trivial on a $400 one. Use percentage.
- No suppression during your own sales. Self-induced alerts add noise.
- Forgetting variation listings. Track the specific child ASIN, not the parent.
The Landscape
For competitor price tracking on Amazon specifically:
- Keepa — best-in-class for Amazon price history; UI is sufficient and the metered API gives you raw data feeds.
- Price2Spy — broad e-commerce competitor monitoring; works well if Amazon is part of a multi-site catalog.
- RepricerExpress / Aura — sellers' tools that combine monitoring with auto-repricing through SP-API.
- DIY + Bright Data — full control, real engineering investment.
- LogPose — monitor system across 11 platforms; useful when Amazon is one of several places you sell.
For Amazon-only sellers, a specialized tool like Keepa or a repricer often beats a general scraping API. For multi-platform operators (Amazon + eBay + Etsy), a unified API is usually less ops work.
Get Started
- Sign up at logposervices.com, grab an API key.
- Export your ASIN list as a CSV with
product, competitor, asincolumns. - Run the bulk-monitor-create snippet above.
- Point the webhook URL at a Flask handler or a Zapier "Webhooks" trigger.
Related: scrape Amazon prices in Python, Amazon price tracker walkthrough, bulk ASIN extraction.
External: Amazon SP-API docs, Bright Data residential proxies.