DEV Community

Maxime Lacoste
Maxime Lacoste

Posted on

The price on my shop page was not the price at checkout

I sell a few digital products from a WooCommerce store I host myself. Nothing exotic: three downloads, a handful of countries, real customers. A week after it went live I was clicking through it the way a buyer would, and I noticed something that should not have been possible. The product page said €49. The checkout said €51.85.

Same product. Same session. Two different prices, eight seconds apart. Nothing had errored, nothing had warned me, and if I had not happened to be shopping from a test account set to Hungary I would never have seen it.

This is the story of why that happens, why it is not a bug in the usual sense, and the one line of configuration that fixes it. If you sell digital products to consumers in the EU on WooCommerce, it is almost certainly happening to you right now.

The rule that makes this hard

A digital product sold to a consumer in the EU is taxed where the buyer is, not where the seller is. That is the VAT One Stop Shop rule, and the rates are not close to each other: 17% in Luxembourg, 27% in Hungary, with everything else in between.

Now hold two things you want to be true at the same time:

  1. The price a customer sees is a round, deliberate number. €49, not €48.72.
  2. Your margin on each sale is predictable.

You cannot have both. If the tax rate changes per country and the pre-tax price is fixed, the final price moves. If the final price is fixed, the pre-tax amount, and therefore your margin, moves. Something has to give, and WooCommerce quietly decides which one for you.

What WooCommerce decides by default

By default, WooCommerce protects your margin.

When I entered €49 as a tax-inclusive price, WooCommerce stored it as €40.83 excluding tax (49 ÷ 1.20, using my shop's base rate of 20%). From then on, €40.83 was the number it treated as real. The €49 was just €40.83 wearing my country's tax rate.

So when a Hungarian customer arrived, WooCommerce did exactly what it was told: take the real pre-tax price, apply the customer's rate.

€40.83 + 27% = €51.85
Enter fullscreen mode Exit fullscreen mode

The shop page, still rendering my base country's rate, said €49. The cart, now knowing the customer was in Hungary, said €51.85. Both were internally consistent. Neither was wrong about its own arithmetic. The store was doing precisely what it had been configured to do, and the result was a price that grew €2.85 between the shelf and the till.

Why this is worse than an ordinary bug

An ordinary bug throws an error, or produces something obviously broken. This produces a perfectly formed, plausible number. You only catch it if you are looking at the shop and the checkout from the same non-base country at the same time, which you almost never do while building the thing, because you build it from one place with one tax rate.

It also has a business edge that a purely technical bug does not. In the EU, the advertised price to a consumer is supposed to be the price they pay. A price that inflates at checkout is not just untidy, it is the single most reliable way to lose a €12 sale: the customer feels the number move and closes the tab.

So this is a real decision, not a glitch. Do I show a price that moves by country, or do I keep my margin fixed and let the price move? WooCommerce made that decision for me, silently, in favour of the margin. For a store selling round-priced digital goods to EU consumers, that is the wrong default.

The fix

WooCommerce exposes exactly this decision through a filter:

add_filter( 'woocommerce_adjust_non_base_location_prices', '__return_false' );
Enter fullscreen mode Exit fullscreen mode

Returning false flips the choice. Now the tax-inclusive price stays fixed everywhere, and the margin is what varies. The Hungarian customer and the French customer both see €49 and both pay €49. Behind the scenes:

  • France: €49 inclusive → €40.83 net, €8.17 tax
  • Hungary: €49 inclusive → €38.58 net, €10.42 tax

I earn €2.25 less on the Hungarian sale. That is the cost of honouring my own price tag, and for a €49 download it is a cost I will happily pay to not lose the sale at checkout.

Proving the fix, and proving it the right way

Here is the part I care about most, because it is the part that separates "I changed a setting and it looked better" from "I know this is correct".

I did not just re-check Hungary. A green result on Hungary alone would have been dangerous, because there is a second bug that looks identical from the outside: if no tax were being calculated at all, every country would also show €49. "€49 everywhere" is what success looks like, and it is also what one particular failure looks like.

So I tested the six most extreme countries by rate, and then I wrote a counter-test: a test that removes the filter and asserts that Hungary goes back above €49. If that assertion ever fails, it means the tax engine has stopped calculating, and my nice consistent €49 is a lie. The counter-test is the thing that lets me trust the green.

That habit generalises well beyond VAT: when the correct state and a broken state produce the same reading, you have not finished testing until you have made the broken state show up differently on purpose.

Takeaways

  • If you sell digital products to EU consumers on WooCommerce with tax-inclusive pricing, check the price on a product page and at checkout from a non-base country. If they differ, this is why.
  • woocommerce_adjust_non_base_location_prices is the switch. Default protects margin; __return_false protects the displayed price. For round-priced consumer goods, you almost certainly want the second.
  • When a passing test and a failing state can look the same, write the test that makes them look different. A green you cannot break is not yet a green you can trust.

I build and self-host small commerce and SaaS projects, and I write up the sharp edges I hit along the way.

Top comments (0)