How to Add Review Schema Markup for Star Ratings in Google
Search for a competitor’s product and you see it right there under their result: a row of gold stars and a review count. You see it under yours too, except yours has none. So you do what every tutorial tells you: copy a block of JSON-LD, paste it into your page, and wait for the stars to appear. They never do. The frustrating truth is that the code is the easy part, and pasting it alone accomplishes nothing. Google shows star ratings only when the markup describes real reviews a visitor can actually see on the same page. Skip that, and at best nothing happens, at worst you earn a penalty. Here is the path that actually works.
Why star ratings show up (and why pasting code alone does nothing)
Those stars are called rich results, or rich snippets. Google generates them from structured data: a machine-readable description of the page, written in a vocabulary called Schema.org and usually delivered as JSON-LD in a <script> tag. The structured data tells Google “this page is about a product, and here is its aggregate rating and the reviews behind it.”
The catch most guides ignore: Google treats review structured data as a claim about content that exists on the page. The crawler renders the page, looks for the reviews you described, and only considers showing stars if the markup and the visible content line up. Markup with no matching reviews on the page is not a shortcut. It is the thing Google is actively looking to ignore or punish.
The prerequisite: real, visible reviews on a crawlable page
Before any schema can do anything, you need genuine reviews a human can read on a public, crawlable URL. Not in a private database. Not in your CRM. On a page Googlebot can fetch and render.
This is the step that takes real work, and it is where most makers get stuck. If you are starting from zero, the groundwork is its own task: see how to collect product reviews that actually convert for the asking, timing, and publishing side. The schema you are about to write is only a description of that page. If the page has nothing real to describe, there is nothing to mark up.
A crawlable review page means a stable URL, allowed in robots.txt, present in your sitemap, with the reviews rendered in the HTML (not loaded by a script Google may not execute).
What the markup looks like
Once the reviews are visible, the JSON-LD mirrors them. Here is a realistic shape using obvious placeholder values. Replace every placeholder with numbers that match exactly what is on the page.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "YOUR PRODUCT NAME",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "X.X",
"reviewCount": "NN",
"bestRating": "5",
"worstRating": "1"
},
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "REVIEWER NAME" },
"reviewRating": {
"@type": "Rating",
"ratingValue": "5",
"bestRating": "5"
},
"reviewBody": "THE ACTUAL REVIEW TEXT SHOWN ON THE PAGE"
}
]
}
</script>
AggregateRating is the summary (the average rating value and the count). The review array holds individual Review objects, each with its own Rating. The X.X and NN are placeholders: do not invent figures, and never write a count larger than the reviews actually on the page.
The rule that keeps you safe
Here is the single rule that matters more than any field name: the markup must match the visible content. If your JSON-LD says forty reviews and a visitor sees three, you are violating Google’s structured data policies. The documented consequence is a structured data manual action, a penalty applied by a human reviewer that can strip rich results from your site entirely and is reported in Search Console.
This is why “just paste this and add some impressive numbers” advice is dangerous. Aggregate ratings must be based on reviews genuinely present on the page. The safe version is boring and effective: every rating in the markup corresponds to a rating a person can read on the page.
Validate and ship
When the page and markup agree, test before you celebrate:
- Run the live URL (or the raw code) through Google’s Rich Results Test. It tells you whether the page is eligible for review snippets and flags missing or invalid fields.
- Fix every error and review the warnings.
- In Google Search Console, use the URL Inspection tool to request indexing so Google recrawls the updated page.
One honest caveat: eligibility is not a guarantee. Passing the Rich Results Test means your markup qualifies. Whether Google actually displays stars, and when, is its decision. No tutorial, plugin, or service can promise the snippet will appear.
The shortcut, honestly
All of the above is doable by hand. It is also fiddly: keeping the JSON-LD in sync with the page every time a review comes in, getting the crawlability details right, and not tripping the manual-action wire.
This is the gap XLens Review fills, and the honest framing matters. XLens does not inject schema into your own site. Instead it gives you a hosted public reviews page at getxlens.com/review/<your-product>. You collect first-party reviews (one to five stars) through a submission form with email verification and spam controls, approve the ones you want, and they publish to that page. The page is built to be crawlable (canonical tag, meta description, in the sitemap, allowed in robots.txt) and it automatically outputs valid Schema.org JSON-LD: a Product with AggregateRating plus individual Review objects, built only from approved reviews. With zero reviews it emits no rating at all, so it never fakes anything. There is also a copy-paste rating badge (an SVG image plus backlink) for your own site.
In other words, it ships the exact schema Google uses for review snippets, on a page that already follows the visibility rule, so you skip the hand-rolling. Google still decides whether to show the stars. But you will have done the one thing that gives those stars a chance: surfaced reviews you actually earned, described accurately. Schema is the last ten percent of plumbing. The reviews come first.