Product Structured Data for Malaysian Online Stores, Explained
How Product structured data works, what Google requires for rich results, and why a mismatched price is a policy violation, not a glitch.
What Product Structured Data Is Actually For
Product structured data is a block of code on a product page — usually JSON-LD — that describes the product to Google directly, in a format it doesn't have to guess at, rather than leaving Google to infer the price from wherever "RM199" happens to sit visually on the rendered page. Done correctly, it's how a product can show a price, star rating, or stock status directly in a search result. Done incorrectly, or left to drift out of sync with the actual page, it's ignored at best — and at worst, for a store also running Google Merchant Center, it becomes the reason products get disapproved.
Google's documentation splits this into two related but distinct experiences: product snippets, for pages where a visitor can't purchase directly, and merchant listings, for pages where they can — the relevant category for a Malaysian WooCommerce or Shopify store selling directly to shoppers.
What Google Actually Requires
For a merchant listing, Google's documentation lists the required properties plainly. At the product level: name and image, plus a nested offers object. Inside that offers object: price (or priceSpecification.price), which must be a real number greater than zero, and priceCurrency, specified as a three-letter ISO 4217 currency code.
For a Malaysian store, that currency code is MYR — not "RM," which is a currency symbol and label, not the code Google's specification calls for, and not left blank, which makes the item ineligible outright.
Beyond those strict requirements, Google lists a set of recommended-but-increasingly-important properties: availability, itemCondition, priceValidUntil, hasMerchantReturnPolicy, and shippingDetails. None of these are in the hard "required" list, but the last two in particular matter more each year for a listing to display with its full set of features — a store that only ever fills in the required minimum tends to get a plainer result than one that also declares its return policy and shipping details in structured data.
Availability Has to Reflect Reality, Not a Snapshot
Schema.org defines a specific set of values for availability: InStock, OutOfStock, PreOrder, BackOrder, Discontinued, and a few others. The value needs to come from the same live stock data your storefront uses, updated as it changes — not a value set once when the product was first created and left alone. A product marked InStock in its structured data while the visible page says "Out of stock" is exactly the kind of mismatch the next section covers, and it's a genuinely common one on stores where the schema markup and the stock display pull from different parts of the codebase.
The Validation Errors That Come Up Most Often
A few patterns account for most of the structured data problems we see on Malaysian product pages:
- Missing
priceCurrency. Google doesn't assume a default currency — an offer without it isn't eligible for the merchant listing experience at all, regardless of how correct everything else is. - Price left at zero or blank for "contact for price" products. Google's requirement that price be greater than zero means "POA" or enquiry-based pricing schemes simply don't qualify for this particular feature — there's no workaround that keeps the rich result while hiding the number.
- Two currencies on one URL. Google's own guidance is explicit that a distinct URL is needed per currency when a product is offered in more than one; a single page can't validly carry two price/currency pairs for the same offer.
- Structured data describing the wrong variant. On a configurable product (different sizes or colours at different prices), markup that doesn't match what the shopper is actually looking at on that specific URL is a mismatch in the same family as the price problem below.
Why a Mismatched Price Is a Policy Violation, Not a Rounding Error
Google's general structured data guidelines are direct about this: "don't mark up content that is not visible to readers of the page," and don't use structured data to deceive or mislead users. A price in your JSON-LD that doesn't match the price a visitor actually sees on the page isn't a technical glitch in Google's eyes — it's the specific kind of inaccuracy this policy exists to catch.
For stores that also run Google Merchant Center — feeding products into free listings or Shopping ads — this isn't just a policy statement, it's actively enforced. Google routinely crawls the landing page, checks the structured data on it, and compares both against the price submitted in your product feed. A discrepancy shows up as "Mismatched value (page crawl) [price]" in Merchant Center, and it can get the individual item disapproved until it's fixed.
This kind of mismatch is usually accidental rather than deliberate: a caching plugin serving a stale version of the page after a price change, a theme update that overwrites the visible price display but not the structured data template underneath it, or a sale that was ended in the store's admin panel but was hardcoded into a promotional snippet that never got removed. None of that requires bad intent to cause a problem — it requires the two systems (visible page and structured data) to be checked against each other, because incorrect structured data usually doesn't break anything visually. The page still looks fine. It just quietly fails the moment Google, or a testing tool, actually checks it.
Keeping Structured Data and the Visible Page in Sync
Because price and stock status change constantly, structured data should be generated dynamically from the same source of truth as the price a shopper sees — the product database — rather than written once by hand and left in place. Most well-built WooCommerce and Shopify themes handle this automatically. Where drift tends to creep in is on a heavily customised theme, a page builder that renders the price separately from the schema, or a manually edited product template that someone updated on one side and not the other.
The practical habit worth having is periodic testing, not a one-time check at launch — Google's Rich Results Test will show exactly what it's currently reading from a live URL, which is the only way to actually confirm the two sides still agree.
If you'd like your product pages checked against Google's current requirements — currency codes, availability accuracy, and whether the structured data still matches what's on the page — that's a concrete, scoped piece of our Essential System Review, RM1,500 (RM999 until 16 September 2026). For catching this kind of drift on an ongoing basis rather than once, JagaWeb Care starts at RM450/month.
Ready to verify who owns your website?
Replace uncertainty with a decision-ready ownership and access report. The fixed Ownership & Access Review is RM1,500 before SST and includes a 30-day action plan.