E-commerce
Omnibus 30-day reference price: 15 ways agents fail audits
Fifteen ways a Dutch e-commerce automation agent breaks the Omnibus 30-day reference-price rule, ranked by who can fix it in an hour and who cannot.

A merchandiser at a mid-size Dutch beauty etailer staged 600 SKUs for the Sinterklaas weekend on a Tuesday afternoon. The process-automation agent flipped the SALE banners on at 02:00 Wednesday morning. By 09:14 there was an email from de Consumentenbond. They had run a steekproef during the night. Of the 600, sixty-three banners cited a "van" price the storefront had never actually charged in the past 30 days.
This is the standard shape of an Omnibus-richtlijn failure. The agent did its job. The price-rules engine did its job. Together they walked the company into an audit failure before the merchandiser had finished her first coffee.
What follows is a field guide to the fifteen ways that conversation goes wrong, ranked by who has to fix it. Eight of these a merchandiser can resolve before lunch, inside the price-rules engine. Seven of them need a backend engineer to first build something most Dutch e-com stacks still lack: a proper kortingshistorie ledger.
The rule in one paragraph
Article 6a of the EU Price Indication Directive, as amended by Directive 2019/2161 (Omnibus), requires that any announcement of a price reduction includes the lowest price applied during at least the 30 days preceding the reduction. The Dutch implementation sits in the Besluit prijsaanduiding producten. ACM enforces it, with maximum fines under Omnibus set at 4% of annual turnover, and de Consumentenbond audits it informally with a published steekproef once or twice a year.
The rule is simple in print and brutal in production. Every "van EUR X, nu EUR Y" pair, every percentage chip, every strikethrough, every "korting" label, has to mathematically reconcile to the same 30-day-lowest reference for that product. Across storefront, app, category page, syndicated feed, and email. Concurrently. For every variant.
Failures the merchandiser can fix in the price-rules engine
These are configuration drifts. The data exists; the agent is reading it from the wrong field.
1. MSRP as the strikethrough van-price
The most common one. The agent pulls the manufacturer's advised retail price from the PIM and uses it as the strikethrough. Convenient, because every product has one. But unless you actually sold at MSRP within the last 30 days, it is not a legal reference. Fix: bind the strikethrough field to the 30-day-lowest field, not to MSRP.
2. Percentage chip computed against MSRP
Same root cause, different surface. The "minus 40%" chip is computed against the same wrong number. The chip and the strikethrough have to be wrong together or right together. Most rule engines let you override the chip basis in one line of configuration.
3. Member-price treated as ordinary
You run a Friends-of-the-brand programme. Members pay EUR 39, non-members pay EUR 49. The agent picks EUR 49 as the "normal" price and stages a SALE banner against it during a drop to EUR 35. The 30-day-lowest across all customers was actually EUR 39, which is what most of your purchasers paid. The math is wrong for everyone except non-members buying on day one.
4. Free-shipping savings folded into the discount headline
"Bespaar EUR 12,95" sounds like a price reduction. It is not, when EUR 7,95 of it is shipping. Omnibus reference-price rules apply to the product price. Shipping savings sit under separate consumer-information obligations. Keep them in separate widgets.
5. Voucher code applied at checkout rendered as was/now
A KORTING25 code applied in cart drops the line item by 25%. Some templates rerender the PDP with a fresh "was EUR 80, now EUR 60" pair once the code is active. That is a price-reduction announcement and triggers the 30-day rule. Show the discount as a discount, not as a new reference price.
6. Category-page vanaf pricing
Category tiles show "vanaf EUR 12,50" based on the current cheapest variant. If that variant is on sale, the vanaf is the sale price, but the tile still shows a strikethrough that reflects the parent product. Reference-price logic has to apply at the variant being displayed, not at the parent.
7. Per-locale van-prijs without per-locale history
You sell .nl, .be, and .de off the same catalog. The agent localizes the strikethrough with a static FX or VAT adjustment. The 30-day lowest in EUR for a Belgian customer might be a different number than for a Dutch one, once you account for promos run only in NL. The reference price has to be the lowest price actually shown to that locale.
8. Bundle reference as the sum of parts
A bundle of three SKUs is sold at EUR 79. The agent shows the strikethrough as the sum of individual van-prijzen (EUR 99). But the bundle itself has its own 30-day price history, and the sum is not the legal reference. Either show the bundle's own van-prijs, or do not announce a reduction on the bundle.
The "merchandiser fixable" label is misleading if your rules engine has no field for thirty-day-lowest at all. The fix is one rule; the prerequisite is a column that actually exists. Check before promising the marketing lead it can ship today.
Failures that need a kortingshistorie ledger first
These are not display bugs. They are data-model bugs. No amount of UI logic can resolve them, because the underlying truth is not being stored.
9. SKU re-listing to reset history
A sourcing manager archives an old article number after each cycle and re-creates the SKU under a new code. The agent reads the new article-number, sees zero history, and stages whatever van-prijs the merchandiser wants. ACM treats this as evasion. The only fix is a ledger that follows the product, not the article number, with a stable product identity that survives re-listing.
10. Variant axes treated as independent SKUs
Same shirt, size M and size L. Two SKUs. M was on sale last week, L was not. The agent reads the L variant's history and announces a discount against an older L-price, ignoring that the parent product had a discounted week. Reference-price logic should follow the parent product across variant axes that share consumer perception.
11. Consecutive sales without a reset window
You run "20% off" the first half of the month and "30% off" the second half. The agent computes the strikethrough during the second sale using the 30-day-lowest, which is the 20%-off price from two weeks ago. The chip now says "minus 12.5%". The marketing lead asks the agent to "use the proper van-prijs" and the agent obliges. The obliging is the violation.
12. Flash sale shorter than the prior sale's tail
A 48-hour flash sale runs at EUR 29. The previous sale at EUR 34 ended 28 days ago. The 30-day-lowest two days into the flash is EUR 29, and for the next 26 days every subsequent promotion has to reference EUR 29 as the floor. Agents that recompute the strikethrough nightly without sliding-window awareness will drift.
13. Feed exports diverging from the storefront
Your Google Shopping feed, Beslist export, and Bol seller feed pull from a different snapshot than the storefront renderer. The storefront has the right van-prijs; the feed shows yesterday's. Consumentenbond and ACM both compare across surfaces. A ledger that is the single source of truth, queried by renderer and exporter alike, is the only way out.
14. Pre-orders going to SALE before any history exists
A pre-order opens on day one. There is no 30-day history. The agent should refuse to stage a SALE banner. Many do not, because the rules engine treats absence of history as zero, and zero is lower than the current price. Fix: the ledger has to expose "history exists for at least 30 days" as an explicit boolean, and the agent has to gate on it.
15. Personalization breaking the single reference
You A/B test prices per user segment. Segment A sees EUR 49. Segment B sees EUR 45. You then put both on sale at EUR 35. The legal reference is the lowest price actually charged to consumers in the last 30 days, which is EUR 45. Showing segment A a "van EUR 49" is a violation, even if it is true for that segment. A ledger that aggregates across personalization branches is the prerequisite for any kind of segmented pricing.
A workable kortingshistorie ledger
The smallest table that survives an ACM audit looks like this:
create table price_history (
product_id uuid not null,
locale text not null,
observed_at timestamptz not null,
shown_price_eur numeric(10,2) not null,
channel text not null,
segment text,
primary key (product_id, locale, observed_at, channel, coalesce(segment, ''))
);
create index price_history_window
on price_history (product_id, locale, observed_at desc);
Three points about this shape. First, product_id is the stable identity, not the article number, so SKU re-listing does not reset anything. Second, every channel writes its own row, so feed and storefront divergence is auditable. Third, the segment column is nullable but indexed, so personalized pricing can be aggregated for the legal reference without losing the per-segment data.
The 30-day-lowest query then is one line, and the agent reads it before staging any banner:
select min(shown_price_eur)
from price_history
where product_id = $1
and locale = $2
and observed_at >= now() - interval '30 days';
If the query returns null, no banner. If it returns a number higher than the planned sale price, the strikethrough is that number. If it returns a number equal to or lower than the planned sale price, the sale is not a reduction and the banner is illegal.
The five-minute audit you can run today
Pick ten products currently on SALE. For each, open the PDP, the category tile, the Google Shopping listing, and the Bol seller listing if you have one. Photograph all four. The van-prijs should match across all four. If it does not, you have at least failure 13 in production. Then pull the last 30 days of price changes from your PIM for those ten products and confirm the strikethrough on the PDP equals the minimum. If your PIM cannot produce that report in under a minute, you do not have a ledger yet, and you are exposed to failures 9 through 15 the moment the merchandiser stages the next campaign.
When we built the price-history ledger for a mid-market Dutch beauty etailer last winter, the thing we ran into was variant-axis collapse: the rules engine treated colourways as independent products, and the popular blue SKU's 30-day window made the niche red SKU's discount math illegal. We solved it by binding the ledger to parent product identity and exposing variant divergence as an explicit override flag, so the merchandiser sees the violation in staging instead of in a Consumentenbond email. If you want a closer look at how the automation agent writes to that ledger before it stages a single banner, the shape is the same for any e-com catalog past about a thousand SKUs.
Key takeaway
Eight Omnibus failures live in the price-rules engine and a merchandiser can fix them. Seven live deeper and need a kortingshistorie ledger first.
FAQ
What does the Omnibus 30-day rule actually require?
Every advertised price reduction must reference the lowest price the seller charged during the 30 days before the sale, on the same channel and to the same audience. The strikethrough and the percentage chip both have to reconcile to that number.
Can I reset the 30-day window by re-listing a SKU under a new article number?
No. ACM treats SKU re-listing to escape the reference window as evasion. Your price history has to follow stable product identity, not the article number, which is why the ledger needs its own product_id.
Does the rule apply to bundles?
Yes. A bundle has its own price history. You cannot use the sum of individual reference prices as the bundle's strikethrough. Either show the bundle's own van-prijs or do not announce a reduction on it.
What about pre-orders that have no 30-day history yet?
The agent should refuse to stage a SALE banner until the 30-day window exists. Treating absence of history as a price of zero is the most common reason pre-order pages fail a steekproef.