Home / Blog / Amazon Competitor Monitoring via API: A Daily Report of Price, Buy Box and Rank

Amazon Competitor Monitoring via API: A Daily Report of Price, Buy Box and Rank

Monitor your Amazon competitors with one daily report: Buy Box price and holder, number of sellers, rating and sales rank for each competitor ASIN, written to CSV, with a list of what changed since yesterday - two credits per competitor per day.

September 28, 2026
4 min read
SellerMagnet Team
Share & Bookmark
Blueprint flow from a competitor list through lookup and offers calls to a daily CSV report and change list

To monitor Amazon competitors, run one report a day: for each competitor ASIN, read /api/amazon-product-lookup for rating and sales rank and /api/amazon-product-offers for the Buy Box price, its holder and the number of New sellers on the first offer page. Write the rows to a dated CSV and compare them with yesterday's, so you read only what changed. Two credits per competitor per day - about 60 a month - and the script below needs only Python, requests and the helper from the Python quickstart.

Key Takeaways

  • Two calls per competitor cover the essentials: lookup for rating and rank, offers for Buy Box price, holder and sellers.
  • A dated CSV per day keeps the history; the change list keeps the reading short.
  • Compare against the last successful row, so a failed call never shows up as a price change.
  • Two credits a day is about 60 per competitor a month; lookup alone halves that and still names the holder's seller ID, but not the landed price, seller name or seller count.
  • For deeper questions - stock-outs, repricers, listing edits - the same list feeds the specialised monitors.

What should a competitor report contain?

Five columns answer most daily questions: what the featured offer costs, who holds it, how many sellers compete, how the product is rated and how well it sells. Each comes from one of two calls; the offers call reads the first page of the offer listing, which the offer listing guide explains.

Report columns and where each comes from (September 2026).
ColumnSourceAnswers
buybox_priceoffers: buyBox.totalPriceLanded price of the featured offer
buybox_selleroffers: buyBox.sellerNameWho holds the Buy Box
new_sellersoffers: New offersHow many compete (first page)
rating · ratingslookup: reviewsStars and ratings count
ranklookup: bestsellerRanksMain-category sales rank

How do I build a daily competitor report in Python?

row() makes the two calls for one competitor and returns a flat dict; a failed call becomes a row with an error instead of stopping the run. changes() compares today's rows with the last successful ones and lists what moved. The report runs four competitors at a time and stores the baseline in a JSON file, keeping yesterday's row when today's call failed. get_with_retry() retries a 429 or 5xx a few times before a row counts as failed; it, new_session() and ApiError come from the Python quickstart.

competitor_report.py - daily CSV and change list

"""Daily competitor report: price, Buy Box, sellers, rating and rank per ASIN, and what changed since yesterday."""
import csv
import json
import threading
from concurrent.futures import ThreadPoolExecutor
from datetime import date
from pathlib import Path

import requests

from sellermagnet import ApiError, get_with_retry, new_session

COMPETITORS = [("B0CL61F39H", "ATVPDKIKX0DER"), ("B0CLTBHXWQ", "APJ6JRA9NG5V4")]   # (asin, marketplaceId)
LAST = Path("last_report.json")
WATCH = {"buybox_price": "price", "buybox_seller": "Buy Box", "new_sellers": "New sellers", "rank": "rank"}
_local = threading.local()


def session():
    if not hasattr(_local, "session"):
        _local.session = new_session()
    return _local.session


def row(asin: str, marketplace_id: str) -> dict:
    base = {"asin": asin, "marketplace": marketplace_id, "error": ""}
    try:
        p = get_with_retry(session(), "amazon-product-lookup", asin=asin, marketplaceId=marketplace_id)["productInfo"]
        o = get_with_retry(session(), "amazon-product-offers", asin=asin, marketplaceId=marketplace_id)
    except ApiError as err:
        return {**base, "error": err.status}
    except requests.RequestException as err:
        return {**base, "error": type(err).__name__}
    box = o.get("buyBox") or {}
    price = box.get("totalPrice")
    new = {x.get("sellerId") for x in o.get("offers") or [] if x.get("condition") == "New"}
    reviews = p.get("reviews") or {}
    return {**base,
            "title": (p.get("title") or "")[:50],
            "buybox_price": round(price, 2) if isinstance(price, (int, float)) and price > 0 else None,
            "currency": (o.get("currency") or {}).get("code"),
            "buybox_seller": box.get("sellerName") or None,          # None: no featured offer
            "new_sellers": len(new),
            "rating": reviews.get("averageRating"),
            "ratings": reviews.get("totalReviews"),
            "rank": ((p.get("bestsellerRanks") or {}).get("main_category") or {}).get("rank") or None}


def changes(today: list[dict], yesterday: dict) -> list[str]:
    lines = []
    for r in today:
        old = yesterday.get(f"{r['marketplace']}:{r['asin']}")
        if not old or r["error"] or old.get("error"):
            continue                                             # no baseline, or one side failed
        for field, name in WATCH.items():
            if old.get(field) != r.get(field):
                lines.append(f"{r['marketplace']} {r['asin']} {name}: {old.get(field)} -> {r.get(field)}")
    return lines


if __name__ == "__main__":
    with ThreadPoolExecutor(max_workers=4) as pool:
        rows = list(pool.map(lambda c: row(*c), COMPETITORS))
    yesterday = json.loads(LAST.read_text()) if LAST.exists() else {}
    for line in changes(rows, yesterday):
        print(line)
    with open(f"competitors-{date.today()}.csv", "w", newline="", encoding="utf-8") as fh:
        fields = ["asin", "marketplace", "title", "buybox_price", "currency", "buybox_seller", "new_sellers",
                  "rating", "ratings", "rank", "error"]
        writer = csv.DictWriter(fh, fieldnames=fields, restval="")
        writer.writeheader()
        writer.writerows(rows)
    keep = {f"{r['marketplace']}:{r['asin']}": r for r in rows if not r["error"]}
    LAST.write_text(json.dumps({**yesterday, **keep}, indent=1))   # a failed row keeps yesterday's baseline

Example change list on a busy day (illustrative values)

ATVPDKIKX0DER B0CL61F39H price: 444.98 -> 419.83
ATVPDKIKX0DER B0CL61F39H Buy Box: Amazon -> Example Shop
ATVPDKIKX0DER B0CL61F39H New sellers: 2 -> 3
ATVPDKIKX0DER B0CL61F39H rank: 26 -> 21

price: ... -> None together with Buy Box: ... -> None means there is no featured offer today: a suppressed Buy Box, a stock-out or a page that could not be read. Confirm it on the next run before acting - the out-of-stock alert linked below waits for two checks in a row.

Blueprint table of the competitor report columns, the API field behind each and the question it answers
Five columns, two calls.

How much does monitoring competitors cost?

One credit per call. Lookup alone is 30 credits per competitor a month and still shows the featured offer's item price (without shipping), its seller ID, rating and rank; adding offers doubles it and adds the landed price, the seller's name and the New-seller count. A weekly statistics call on top adds recorded price and rank history for about 4 more (statistics covers 11 marketplaces; others get a free 400). Twenty competitors with lookup and offers cost about 1,200 credits a month - see pricing for plans.

Blueprint bar chart of monthly credits per competitor for three monitoring plans
Credits per competitor per month, daily report.

What else can the same competitor list feed?

Run the report every morning from cron (server clock)

# crontab -e: cron has no login environment, so set the key in the crontab
# SELLERMAGNET_API_KEY=your-key-here
# 0 7 * * * cd /opt/competitors && .venv/bin/python competitor_report.py >> changes.log 2>&1
cd /opt/competitors && .venv/bin/python competitor_report.py && ls competitors-*.csv | tail -3

Frequently Asked Questions

How can I monitor my Amazon competitors automatically?

Run a daily script that looks up each competitor ASIN and reads its offers, saves the rows to CSV and lists what changed since the day before.

Which data should a competitor report include?

At least the Buy Box price and holder, the number of sellers, rating and sales rank. Stock-outs and listing edits need their own checks.

How much does it cost per competitor?

Two credits a day with lookup and offers, about 60 a month. Lookup alone is about 30; it gives the holder's seller ID and item price, but no landed price, seller name or seller count.

What happens when a call fails?

The row gets an error and the last successful row stays the baseline, so a failed call is never reported as a price or rank change.

Can I monitor competitors on several marketplaces?

Yes. Each competitor is an ASIN plus a marketplaceId; list the same ASIN once per marketplace you care about.

Bottom line: two calls per competitor, one CSV a day and a short list of changes turn competitor monitoring into a five-minute morning read. A free account includes 150 credits to try it on your own list.

Ready to Extract Amazon Data at Scale?

Start building with SellerMagnet API today. Real-time product data, competitive pricing, and review analytics at your fingertips.

150 free API credits • No credit card required • Cancel anytime