Your “30% off” is 12% off. A court has already said so.
Article 6a makes the lowest price of the last 30 days the reference for any announced reduction. C-330/23 added the part most storefronts still get wrong: the percentage has to be calculated from that same price. Pricepulse keeps the price series and returns the figure you may actually advertise.
1,000 variants on the free tier. Shopify webhook or plain REST.
Lawful claim
−12 %
Calculated from the lowest price in the 30 days before the reduction, as C-330/23 requires.
Same month, same prices. The only difference is which number you divide by — and only one of them is lawful.
What changed
Showing the 30-day low is not enough any more.
Many shops complied with Article 6a by printing the 30-day low somewhere on the page, while continuing to advertise a percentage computed from a higher, more recent price. On the face of it both numbers were true.
In C-330/23 the Court of Justice held that this is still misleading: where a price reduction is announced as a percentage, that percentage must be determined on the basis of the prior price the directive defines — the 30-day low. A truthful number in small print does not cure a misleading headline.
The practical consequence is that your discount figures get smaller, and the only way to know by how much is to have kept the price history. Most storefronts have not: Shopify’s compare_at_price is a free-text field with no memory of what it was last week.
How it works
Keep the series. Ask for the number.
Send every price change
A Shopify webhook, or a POST from your own stack. An unchanged price records nothing — storefronts send the whole product on every edit, and a history full of non-events makes the window meaningless.
We keep the series
Append-only. A correction is a new point, never an edit, because the history is what a regulator would examine. The anchor is derived from it on every request, never cached into a field that can drift.
Ask for the badge
One GET returns the lawful reference price, the lawful percentage, and ready-made text in German, English or French. It also returns what you would have advertised without it.
{
"anchor": {
"currentPrice": "70.00",
"anchorPrice": "80.00",
"isReduction": true,
"reductionPercent": "12",
"reductionPercentExact": "12.50",
"naivePercentFromPrevious": "30",
"windowDays": 30
},
"badge": {
"price": "70,00",
"anchorPrice": "80,00",
"anchorLabel": "Niedrigster Preis der letzten 30 Tage",
"percentLabel": "12 % reduziert"
}
}The rules we implement
Four decisions, each one testable.
The reference is the 30-day low
Not the previous price, not a recommended retail price, not the price before the promotion. Article 6a names the lowest price applied in the 30 days before the reduction, and that includes the prices from your own earlier sales.
The percentage divides by that low — C-330/23
The judgment settled the part everyone got wrong. Showing the 30-day low next to a percentage computed from a higher recent price is still misleading. The only lawful figure divides by the same number you display.
Rounded down, never up
A 33.4% reduction is advertised as 33%. Rounding a discount up overstates it, which is the practice the directive exists to stop, and a rounding is no defence.
The label is part of the obligation
A bare crossed-out number does not tell a consumer what it is. We generate "Niedrigster Preis der letzten 30 Tage", never "statt" or "was" — the wording that implies the price was higher until recently is exactly what gets fined.
Where this stands
New service. Not legal advice.
The engine is covered by a suite that states each rule as a scenario a regulator would examine: the window that ends when the reduction begins, the low that was still in force when the window opened, the shorter period for newly introduced goods, and the progressive-sale exemption.
What we will not claim: that using this makes a promotion lawful. Member states implement the directive with their own variations, national enforcement differs, and whether a particular campaign is compliant is a question for a lawyer. We compute the reference price and the percentage correctly, and show our working.