Why the price on your comparison listing lags behind the price on your site
Feed price and on-site price drift apart for predictable reasons: generation schedules, caching, VAT rounding and promotions that start at midnight. Here is where the lag comes from and how to close it.
A shopper clicks through from a comparison listing expecting to pay 149. The product page says 164. They go back, click the next shop, and you have paid for a click that was never going to convert. If it happens often enough, a comparison site will flag your feed, suppress the offers it cannot trust, or ask you to fix it before you are listed again.
Price mismatch is rarely caused by someone typing the wrong number. It is almost always a timing or definition problem: the feed was generated at one moment and read at another, or the number in the feed means something slightly different from the number on the page. Both are fixable, but only once you can see where the delay actually sits.
The four clocks between your database and the listing
There is no single moment at which your price becomes visible on a comparison site. There are at least four, and each one adds lag.
Generation. Most shops build the XML on a schedule — a cron job at 03:00, say — and write it to a static file. Everything that changes after 03:00 is invisible until the next run. If you only generate once a day, your worst-case staleness is 24 hours before anything else is taken into account.
Fetch. The comparison site reads the file on its own schedule, which may or may not line up with yours. If you generate at 03:00 and the fetch happens at 02:30, your listings are running a full day behind your file, not a few minutes.
Caching. This is the one that catches people out. A CDN or reverse proxy in front of your feed URL will happily serve a cached copy for hours after you have written a fresh file. The file on disk is correct, the file your own browser shows is correct because you are hitting origin, and the version the crawler receives is from yesterday. Check the response headers on your feed URL from outside your network: Cache-Control, Age and Last-Modified will tell you immediately whether something in the middle is holding a copy.
Import processing. Large feeds take time to parse, match and index. That is usually minutes rather than hours, but it is not zero.
Add them up honestly. A shop that generates daily and is fetched daily has a real-world staleness window of up to two days, not "about a day". A shop that generates hourly, serves the feed uncached and is fetched every few hours is within a few hours of live.
Decide your tolerance, then pick a schedule
The right generation frequency depends on how fast your prices move. If you repricing against competitors automatically, a daily feed is not defensible — you will be advertising a price you abandoned before lunch. If you set prices by hand and change them a few times a month, hourly generation buys you nothing.
A practical rule: your generation interval should be shorter than the time it takes for a price change to matter commercially. For most shops that means hourly for price and stock, with the heavier descriptive fields rebuilt less often.
If generating the whole catalogue hourly is expensive, split the job. Build the full feed once a day, and keep the price and availability fields updated on a tighter loop — either by regenerating only those fields into the same file, or by publishing a separate lightweight feed if the comparison site supports one. Check what the channel accepts before building it; not every one will take a delta.
Make sure the number means the same thing in both places
Timing aside, a second class of mismatch comes from the price being calculated differently in the feed than on the page.
- VAT. The feed must carry the price the consumer pays, inclusive of VAT. The classic failure is an export that reads the net price from the database and applies VAT with different rounding than the storefront does, producing a listing at 82.64 against a page showing 82.65. One cent is enough to trip an automated price check.
- Rounding and formatting. Use a dot as the decimal separator, two decimal places, no thousands separator, no currency symbol inside the number unless the specification asks for it.
1,299.00and1 299,00 €cause parse failures or, worse, silent misreads. - Customer-group pricing. If your shop shows different prices to logged-in customers, trade accounts or newsletter subscribers, the feed must carry the price an anonymous visitor sees. Exports that run under an admin session sometimes pick up a staff discount tier.
- Discount codes. A price that only applies with a code at checkout is not the feed price. Listing it is a fast way to lose trust with both shoppers and the channel.
- Variant pricing. If a product page defaults to the cheapest variant but your feed exports the parent at an average or highest price, the two will never agree. Export each variant as its own item with its own price and its own identifier.
- Shipping. Keep delivery cost in the shipping field, not folded into the price. Shoppers often sort by total cost, and the comparison site needs the two numbers separately to calculate it.
Promotions are where most mismatches are born
A sale that starts at midnight and a feed that regenerates at 03:00 means three hours of listings at the old price — tolerable. A sale that ends at midnight with the same schedule means three hours of advertising a price you are no longer honouring, which is the version that generates complaints.
Two habits help. First, schedule a feed regeneration immediately after any promotion boundary, not just on the regular interval. Second, be careful with server time zones: if your shop runs on UTC and your campaigns are set in local time, your promotion starts an hour early or late twice a year. Check what time zone the cron server thinks it is in, not what time zone you are in.
If the feed format supports a sale price with a validity window, use it. Letting the channel know a price is valid from a given date to a given date is more reliable than racing to regenerate the file at the right moment.
Stock status deserves the same care as price
A click on an out-of-stock product is wasted in exactly the same way as a click on a wrong price. Availability usually changes faster than price, so if you are updating one field frequently, make it this one.
Be precise rather than optimistic. "In stock" should mean you can ship it; a supplier lead time of two weeks is a different state and should be declared as such if the specification allows. Where a feed only accepts in stock or out of stock, decide the rule deliberately — most shops are better off marking long lead times as unavailable than disappointing a shopper who expected next-day delivery.
The other half of the job is removal. Discontinued products should drop out of the feed entirely rather than linger at zero stock, and the URL for anything removed should return a proper 404 or redirect to something relevant, not a blank template.
A monitoring routine that takes ten minutes a week
You cannot fix drift you cannot see. Set up a simple comparison between the feed and the live site:
- Fetch your own feed URL from outside your network, the way a crawler would, and note the
Ageheader. - Pick a sample — say fifty items, weighted towards your bestsellers and anything recently repriced.
- For each, scrape or manually check the live page price and stock status, and diff them against the feed values.
- Investigate anything that differs by more than rounding, and anything whose feed timestamp is older than your stated generation interval.
Run it as a scheduled script if you can, and alert on a threshold rather than on every single difference — a handful of items mid-update is normal, fifty percent of the catalogue is not. Keep an eye on the total item count between runs too: a feed that suddenly loses a third of its products usually means a generation job failed partway rather than a genuine catalogue change.
The shops that have the least trouble on comparison channels are not the ones with the most elaborate feeds. They are the ones where the number in the file is the number on the page, every hour of the day.