Blog/Ecommerce
11 min read

How to Monitor Competitor Prices Automatically

Two sources agreed the price was 54.99. One also said the list price was 79.99. Store only the first and you cannot tell a price cut from a discount.

How to Monitor Competitor Prices Automatically

Copy this line to your agent to pull current prices for a keyword.

set up https://monid.ai/SKILL.md and use apify axesso_data/amazon-search-scraper for a keyword

Two sources asked about the same product on 2026-09-07 both returned 54.99. They agreed, which is reassuring and is not the interesting part. One of them also returned 79.99 as the list price, and that second number is the difference between a tracker that tells you something and a column of numbers nobody trusts. This guide runs through Monid, the OpenRouter for agent tools.

What actually counts as a price change?

Four different events look identical if you store one number per product per day.

The price came down

The thing everyone is trying to detect. A genuine reduction in what a buyer pays.

The discount changed, not the price

The seller moved the reference price the discount is computed against. The number a buyer pays may not have moved at all, or may have moved less than the headline suggests.

The offer moved to a different seller

On a marketplace the visible price belongs to whoever currently holds the buy box, so a change can mean a different merchant won it rather than anyone repricing.

The page localised differently

Prices vary by region, and a request that resolved to a different country returns a different number for reasons that have nothing to do with the competitor. That is the same exit-geography effect measured in the proxy guide.

Only the first is a competitive event. A tracker that cannot separate them produces alerts nobody acts on, which is how price monitoring quietly gets switched off.

📖 See also Extract Pricing and Free Trial Information From Websites

Why do two sources give the same price and a different story?

Because they return different field sets, and the extra field is the one that carries the meaning.

The measurement

The same product, two routes, on 2026-09-07.

apify/axesso_data/amazon-search-scraper returned sixteen rows for one keyword. The row for our product:

{
  "asin": "B09B93ZDG4",
  "price": 54.99,
  "retailPrice": 79.99,
  "productRating": "4.7 out of 5 stars",
  "countReview": 198959,
  "salesVolume": "10K+ bought in past month",
  "sponsored": false,
  "searchResultPosition": 1
}

context.dev/brand/ai/product pointed at the same product returned is_product_page: true, platform: "amazon", and a product object with name, price: 54.99 as a number, currency: "USD", plus features and tags.

What agrees and what does not

Both say 54.99. Neither is wrong. But only one carries retailPrice: 79.99, and 54.99 against 79.99 is a 31% discount rather than a price.

Store only price and next week's 59.99 looks like a 9% increase. It might instead be the same list price with a smaller promotion, or a promotion that ended, or a different seller. You have recorded the number and lost the event.

The other fields that carry meaning

sponsored tells you whether a position was paid for, so a competitor "appearing at the top" may have bought that. searchResultPosition is where it sat. salesVolume is a demand signal the platform publishes and few trackers capture. None of these is a price and all of them change what a price change means.

The rule this produces

Store the whole record, not the number you think you need. Storage is the cheapest thing in this pipeline and re-deriving a field you discarded is impossible after the fact. That is the same argument made about keeping raw posts rather than a computed rate.

How do you build a price tracker?

Three steps. Discovery is free.

For agents

Grab an API key at app.monid.ai, then paste this to your agent and hand it the key:

set up https://monid.ai/SKILL.md

It learns the whole discover, inspect, run workflow itself. More in the agent quickstart.

For humans

npm install -g @monid-ai/cli
monid keys add -k <your-api-key> -l main

Step 1. Pull a whole category, not one product

What it does. Returns competitors alongside their prices and positions in one call.

The endpoints. apify/axesso_data/amazon-search-scraper, billed per result.

The call.

monid run -p apify -e /axesso_data/amazon-search-scraper -w \
  -i '{"input":[{"keyword":"echo dot","domainCode":"com","maxPages":1}]}'

What comes back. On 2026-09-07, sixteen products with price, list price, rating, review count, sales volume, sponsored flag and search position.

A keyword search is the right unit for monitoring. It costs one call for a whole competitive set, it surfaces entrants you were not tracking, and it captures position, which a per-product lookup cannot.

What it costs. Per result. Current figures at monid.ai/tools.

Step 2. Read a specific product when you need depth

What it does. Gets one product with a numeric price and a clean field set.

The endpoints. context.dev/brand/ai/product, per call. Note the parameters go in the body, not the query string; sending them as query returns a 400 naming the missing field.

The call.

monid run -p context.dev -e /brand/ai/product -w -i '{"url": "https://www.amazon.com/dp/<asin>"}'

What comes back. price as a number rather than a formatted string, plus currency. It also works across retailers rather than one platform, which is what you want when your competitive set is not all on one marketplace.

What it costs. A fraction of a cent per call.

Step 3. Store the record and diff the fields, not the number

What it does. Turns a table of numbers into events you can act on.

The call. No endpoint:

WATCH = ("price", "retailPrice", "sponsored", "searchResultPosition")

def changes(prev, cur):
    return {f: (prev.get(f), cur.get(f))
            for f in WATCH if prev.get(f) != cur.get(f)}

ev = changes(yesterday[asin], today[asin])
if "price" in ev and "retailPrice" not in ev:
    alert("real price move", ev)          # the competitive event
elif "retailPrice" in ev:
    log("reference price changed", ev)    # usually promotional mechanics

Two fields and a comparison separate the event you care about from the one you do not. That is the whole difference between an alert people read and an alert people mute.

Give this to your agent

$Set up https://monid.ai/SKILL.md, and then use Monid to pull the top 20 results for these 5 category keywords, and tell me which products changed price without their list price changing.

📖 See also Amazon ASIN Scraper: What to Do When It Returns Nothing

How often should you check?

Match the interval to how fast the number moves and to what you will do about it.

Daily is right for most people

Prices on competitive listings move on a daily rhythm, and a daily pull gives you a clean series where each point is comparable. It is also cheap enough that you can cover a whole category rather than a handful of products, and the arithmetic is the same one worked through in the real cost of scraping YouTube yourself.

Hourly only if you reprice automatically

If nothing downstream reacts within the hour, an hourly pull is buying resolution you never use, at twenty-four times the cost. Hourly earns its price when a repricing engine consumes it.

Weekly is enough for positioning work

If the output is a monthly competitive review, weekly sampling is plenty and leaves budget for breadth.

The thing that matters more than the interval

Pull everything on the same schedule. A mixed-age dataset produces a comparison table where some rows are today and some are from last week, and nothing on the row shows you which. Stamp every record with the time it was fetched, the same discipline argued in the fundamentals guide.

Which endpoint should I use for which job?

EndpointWhat it doesInputOutputBest forBilling
apify/axesso_data/amazon-search-scraperA category by keywordKeyword, domain, pagesPrice, list price, rating, sales volume, position, sponsoredTracking a competitive setPer result
context.dev/brand/ai/productOne product, any retailerA URL (in the body)Numeric price, currency, featuresDepth, and non-Amazon retailersPer call
apify/axesso_data/amazon-reviews-scraperReviews for a productASIN, domainReview recordsWhy a price move worked or did notPer result
context.dev/web/scrape/markdownThe raw pageA URLMarkdownDebugging what was actually servedPer call

Every row was verified with monid inspect on 2026-09-07. The table gives billing shape rather than figures; shape drives design and current numbers live on monid.ai/tools.

One route worth naming as not working: api.strale.io/x402/price-compare describes cross-merchant comparison, which is exactly what this article wants, and it returned HTTP 400 with valid product and country parameters on both 2026-09-03 and 2026-09-07. Two failures four days apart is a broken route rather than a bad afternoon, so it is not in the table. Checking a second route before depending on it is the argument in not depending on one vendor.

When is monitoring the wrong tool?

Three cases.

You cannot act on the answer. If your prices are set quarterly by a committee, a daily feed changes nothing. The cadence of your response should set the cadence of your collection.

You are matching products by name. Across retailers the same item has different titles, bundles and pack sizes, and name matching produces comparisons between things that are not the same product. Solve identity first or the price series is fiction.

You are tempted to coordinate. Watching a competitor's published price is ordinary research. Agreeing with a competitor about prices is an antitrust problem, and automation makes the line easier to cross without noticing. Keep the system observational.

And the disclosure: this is Monid's blog and we sell per-call access to the endpoints above, including one route that has been broken for at least four days and is named as such. The most valuable recommendation here, storing the whole record and diffing two fields, is code you write yourself.

Conclusion

Both sources agreed the price was 54.99, and agreement was the least useful thing they told us. The field that decides whether a tracker works is the second one: 79.99 as a list price makes 54.99 a 31% discount rather than a price, and a tracker holding one number per product per day cannot tell a price cut from a change in promotional mechanics.

So store the whole record, watch price and retailPrice together, and treat a move in the first without a move in the second as the real competitive event. Keep sponsored and searchResultPosition too, because a competitor rising up the page may have bought the position rather than won it.

Then match the interval to your ability to respond, and pull everything on one schedule so the rows are comparable.

Free next step: pull one category keyword and look at how many rows carry a retailPrice different from price. That ratio tells you how much of your market is running on discounts, and it costs one call. Start at monid.ai.

FAQ

Is it legal to monitor competitor prices?

Observing published prices is ordinary competitive research, and prices are among the most public facts a business produces. The care is in how you collect rather than whether you may look: respect the site's terms, do not hammer a page, and remember a retailer's terms can restrict automated access even to public pages. The genuinely risky behaviour is not collection at all, it is coordination: agreeing with a competitor on price, or using shared software in a way that has that effect, is an antitrust problem in most jurisdictions and has nothing to do with scraping.

How do you match the same product across different retailers?

Identifiers first, text last. A GTIN, EAN, UPC or MPN is authoritative when present and should be your join key. Failing that, brand plus model number gets you most of the way. Product titles are the worst option because retailers add bundles, pack counts and marketing words, so title matching silently compares a two-pack against a single unit. Where you must fall back to fuzzy matching, store the confidence and exclude low-confidence pairs from any headline number rather than letting them dilute it.

Should you track an ASIN or a product?

They are not the same thing and mixing them is a common source of wrong series. On Amazon a colour or size is frequently its own ASIN under a parent, so a "price change" can be your tracker following a link to a different variant. Decide early whether your unit of analysis is the parent product or the specific variant, record both identifiers, and never compare across the two. The same field-level care applies to what a listing actually carries, covered in what the listing carries.

How much storage does price history actually need?

Far less than people expect, which is why storing the whole record is the right default. A thousand products sampled daily with a full record of perhaps a kilobyte is under half a gigabyte a year uncompressed, and price series compress extremely well because most days nothing changes. Storing only changed records shrinks it further, though keeping every observation is worth the space because "we checked and it was the same" is itself information you lose otherwise. The expensive resource in this pipeline is calls, not disk.

Last updated September 2026.

competitor price monitoringprice trackingrepricingecommerce datalist price