Part 3 of 4 in a series on the data layer behind defensible retail pricing. Check out part 1 and part 2.
A promotions manager at a CPG brand once sent us a spreadsheet with a simple request: “Tell me which of our competitors are running deeper discounts than us this week.” The complication showed up within an hour. One retailer’s feed called its offer a “Rollback.” Another called an economically identical mechanic a “Clearance.” A third ran a “Buy 2, Save $5” that looked nothing like either label but produced a comparable effective discount once you did the arithmetic.
None of these labels map onto each other by string comparison, and none of them tell you, on their own, whether the promotion is retailer-funded, brand-funded, or a temporary price cut with no promotional funding behind it at all. Getting to “who is discounting harder than us” required building a coding scheme first: the same problem, one layer up from the attribute normalization we covered in Part 2 of this series, and it doesn’t stop at promotions.
Knowing a product is priced right and promoted competitively will not add value if the product isn’t actually there when the shopper looks for it, which is why this post also covers the second signal that has to be normalized the same way: availability, down to the store and ZIP code.
Retailers don’t just use different words for the same mechanics: they structure genuinely different mechanics under labels that look interchangeable from the outside. A “Rollback” might be a retailer-funded temporary price reduction with no end date communicated to shoppers. A “Clearance” might signal inventory liquidation rather than a competitive price response, which matters enormously if you’re trying to infer competitive intent from promotional cadence. A “Member Price” is gated behind a loyalty program and isn’t available to the general shopper at all, which means comparing it directly to a public shelf price overstates the real accessible discount. Tiered and bundled promotions, such as “Buy 2, Save $5” or “3 for $10,” don’t even present as a discount off a single unit price; they require reconstructing an effective per-unit price before they’re comparable to anything else.
A coding scheme that just captures the retailer’s own label is capturing vocabulary, not mechanics. What’s needed instead is a promotion taxonomy that sits above the retailer-specific labels and classifies each observed promotion along dimensions that are actually comparable:
Once promotions are coded this way, “who is discounting harder than us” becomes an answerable question, because you’re comparing effective discount depth within the same mechanic category, not comparing a headline label to another headline label that happens to use different words.
Coding assumes you’ve already detected that a promotion exists, and that turns out to be harder than it sounds, because retailers don’t reliably expose promotion state as a clean field. A price cut with no accompanying label at all still needs to be caught by comparing today’s shelf price against a rolling baseline for that SKU: if a product has held a stable price for six weeks and drops 15% this week with no explicit label, that’s a promotion whether or not the retailer bothered to say so. Other promotions are only visible in a banner image on the category page rather than in any structured field.
This means catching them requires optical character recognition against banner creative, extracting brand names and offer text from images the way a shopper would read them, not the way a structured feed would expose them. Still others are gated behind a coupon-clip interaction that never appears in the base price at all unless the crawl simulates that click. Each of these is a different detection method feeding the same downstream taxonomy, and a coding scheme is only as good as its ability to actually see the promotion in the first place.
Here’s the failure mode that catches teams who’ve solved pricing and promotion coding but stop there: a price comparison is only meaningful for products that are actually in stock. A “competitively priced” analysis that includes out-of-stock listings is quietly comparing your live price against a competitor’s price for a product nobody can currently buy: which either understates or overstates the real competitive picture depending on which side is out of stock.
Availability data has to answer three separate questions, and conflating them is a common mistake:
That third layer is where most availability data falls short, because it requires geographically distributed observation rather than a single retailer-level crawl. A national retailer might show a product as “in stock” at the chain level while a specific store in a specific ZIP code has been sold out for two weeks: a distinction that matters enormously for a brand deciding where to focus replenishment or a retailer deciding where a rival is vulnerable on shelf presence.

The point where promotion coding and availability meet is effective price. A shelf price of $24.99 next to a “3 for $60” tiered promotion isn’t a $24.99 product: it’s a $20.00-per-unit product, but only if the shopper buys three, and only if all three are actually in stock at that location. Get the tier arithmetic wrong, or ignore that two of the three units are out of stock at the ZIP code in question, and we face problems. The “effective price” a pricing engine reports in such cases is fiction dressed up as a number.

This is also where retailer-specific promotion structures create real engineering complexity rather than just labeling complexity. A points-based loyalty discount that translates to a variable dollar amount depending on a shopper’s accumulated balance can’t be reduced to a single effective price at all: it has to be represented as a range or a typical-case estimate, with that uncertainty carried forward rather than silently collapsed into a false precision.
Availability detection runs into a parallel version of the same problem: retailers rarely expose a clean “in stock: true/false” field either. Some signal out-of-stock through an absent or greyed-out add-to-cart button. Others quietly remove the listing rather than marking it unavailable, which means a naive pipeline reads “product not found” as “product doesn’t exist” instead of “product is out of stock here” (a meaningfully different fact for a replenishment or competitive analysis.) Others impose a quantity limit (“limit 2 per customer”) that signals constrained supply without ever claiming to be out of stock at all.
And because in-store and online inventory are frequently managed as separate systems even within the same retailer, an item can be truly out of stock at a specific store while showing as available for ship-to-home from a regional warehouse) two different facts that a store- or ZIP-level availability signal has to keep separate rather than collapsing into one chain-wide flag.
For a brand, inconsistent promotion coding means a competitive-intelligence dashboard that looks precise but is quietly comparing incompatible things: a loyalty-gated discount against a public shelf price, or a clearance liquidation against a deliberate price-matching move, as though they were the same competitive signal. That’s not a rounding error; it changes what a pricing team decides to do in response.
For availability specifically, the store and ZIP-level layer is what turns “we think we might be losing sales to out-of-stocks somewhere” into “we are out of stock at these 40 stores in these three states, and it started 11 days ago.” That’s the difference between a hypothesis and a replenishment ticket. It’s also, not incidentally, a leading indicator worth watching in its own right: a competitor’s sudden availability gap in a category is often the earliest visible sign of a supply issue or a deliberate assortment pullback, well before it shows up in their pricing.
Part 4 of this series moves from time-bound signals (promotions and stock) to structural ones: how assortment overlap gets tracked across retailers whose catalogs never line up product-for-product, and what content quality inputs actually predict conversion probability rather than just looking complete.
If effective pricing and true availability are two numbers your team is currently reconstructing by hand from retailer labels, that’s exactly the layer we build: reach out and we’ll show you what the coded version looks like against your own catalog.
Part 4 of this series moves from time-bound signals (promotions and stock) to structural ones: how assortment overlap gets tracked across retailers whose catalogs never line up product-for-product, and what content quality inputs actually predict conversion probability rather than just looking complete. If your team is trying to build pricing or assortment intelligence on top of retailer data that doesn’t yet agree with itself, this is the layer worth getting right first: reach out to us and we can walk through what that looks like for your catalog.
For accounts configured with Google ID, use Google login on top.
For accounts using SSO Services, use the button marked "Single Sign-on".