If you sell online, two systems are quietly deciding how your products look in Google: your Merchant Center feed, and the structured data sitting in your page code. Shoppers never see either one directly, but Google reads both, compares them, and decides how much to trust what it shows. When they disagree, the cost isn’t abstract. It’s a lower-visibility listing, a warning in Search Console, or a sale price that keeps showing after the sale has ended.
Google’s latest update to merchant listing structured data tightens exactly this connection. It’s a small spec change on paper. In practice, it’s a preview of where product SEO is heading: less tolerance for feed-and-page drift, more expectation that pricing claims are time-bound and verifiable.
What Changed: Category and Sale Duration
Google added a category property to Product markup. It accepts plain text, a custom label similar to the feed’s product_type, or a CategoryCode object, which lets a page declare a Google Product Category directly, using inCodeSet to point at Google’s taxonomy and codeValue to specify the category by ID or path. Both formats can be used together, and a page can include more than one value.
Alongside it, Google formalized how sale duration should be expressed: priceValidUntil, validFrom, and validThrough, all in ISO 8601 format, placed on the Offer or PriceSpecification node depending on how a sale price is structured. The logic is simple, a listing shouldn’t keep advertising a price that has already expired.
Neither property is strictly required, but both are recommended, and both point at the same underlying idea: markup and feed should agree with each other, and pricing claims should be time-bound and easy to verify.
Why This Keeps Happening
Almost no merchant chooses to keep their feed and their page markup out of sync, it just happens. The two are usually built by different people, at different times, from different data sources. The feed gets updated in Merchant Center on an ongoing basis. The page markup gets set once, by whoever built the template, and rarely gets touched again.
That’s how a page’s category quietly stops matching what’s declared in the feed. Google’s Merchant Listings report in Search Console exists largely because this drift is common, and matching the two by hand page by page, stops being realistic past a few dozen SKUs.
What This Means for Your Product Pages
If your catalog runs on WordLift, none of this requires action on your end.
Your category markup stays correct without a re-launch. You don’t need to brief a dev team or touch a template. Product classification already lives in one place, so adding CategoryCode support was a one-time mapping update, every product page reflects it automatically, going forward.
Sales stop advertising themselves after they end. validFrom and validThrough (or priceValidUntil) are drawn from the same pricing data driving your storefront. There’s no separate copy of “the sale price” sitting in a template waiting to go stale, so a listing can’t outlive its own discount.
One change, your whole catalog, no page-by-page QA. Because this update rolls out at the data layer, it reaches every product page at once. Nobody audits SKUs one at a time to confirm compliance.
Why This Happens Less on a Knowledge Graph
Markup that’s generated from one connected model can’t drift from the feed built off the same model, there’s only one source of truth to update.
If you’re not on WordLift, this is exactly the kind of drift that tends to surface quietly in the Merchant Listings report, a mismatch nobody caught because the feed and the markup are maintained by different people, on different schedules.
Check Your Own Catalog
Before anything else, it’s worth knowing where you actually stand:
- Category — does your
Productmarkup declare one, and does it match your Merchant Center feed? - Sale duration — do time-bound prices carry
validFromandvalidThrough, or does the markup just show a static price indefinitely? - Rendering — is any of this generated by JavaScript after page load? Google still recommends it be present in the initial HTML for merchant listings.
None of these are hard to fix individually. They’re hard to keep correct over time — which is the actual problem a connected product model is built to solve.