SEO debugging
Why your Shopify product review stars don't show in Google Search
Star ratings in Google Search results - the yellow stars visible directly under a product listing - dramatically increase click-through rates. If your store has reviews but no stars in Google, the problem is almost always in how your review data reaches (or fails to reach) Googlebot. This article walks through the exact failure modes and how to fix them.
Audience: merchants, developers, SEO practitioners. Reading time: ~7 minutes.
1. What review rich snippets are
Product rich results are enhanced search listings that show star ratings, review counts, price, and availability directly in the SERP - before a user ever clicks your link. They are powered by structured data embedded in your page: a machine-readable description of your product and its aggregate review score.
Google does not invent this data. It reads it directly from your HTML - specifically from a <script type="application/ld+json"> block containing schema.org/Product markup with a nested AggregateRating property. If that markup is absent, malformed, or not visible at crawl time, no stars appear.
2. How Google decides to show star ratings
Google's Product rich result guidelines require the following to be true before stars can appear:
- The page contains a valid
Productschema with anaggregateRatingproperty that includes bothratingValueandreviewCount(orratingCount) - The
ratingValuemust be within the statedbestRating/worstRatingrange - The structured data is readable by Googlebot at crawl time - not injected by client-side JavaScript after the initial HTML is parsed
- The page content visibly matches the structured data (Google cross-references both)
The third point is where the vast majority of Shopify stores fail.
3. The two reasons they go missing
Failure mode 1: No structured data at all
Many Shopify themes ship without any aggregateRating markup. The theme renders a visual star rating on the page, but outputs no machine-readable equivalent. From Google's perspective, the stars do not exist - it sees text or SVG icons, not data.
This is common with themes that pre-date Online Store 2.0, or themes that have a built-in "review section" powered by a custom app that does not emit structured data.
Failure mode 2: Structured data rendered by JavaScript
This is the more insidious failure, and the one that affects stores using standard review apps (Loox, Judge.me, Stamped, Yotpo, reviews.io). These apps inject a JavaScript widget that fetches review data from an external server after the HTML has loaded. The structured data is generated and injected into the DOM by that JavaScript.
Googlebot does process JavaScript - but not always, not immediately, and not reliably for third-party origins. The rendering queue for JavaScript pages is separate from the HTML crawl queue. In practice:
- New and recently updated pages may sit in the JS rendering queue for days before Googlebot processes their JavaScript
- Requests to third-party CDN domains (the review widget's API endpoint) may be blocked or rate-limited during Googlebot's render
- Even when JS rendering succeeds, the structured data lands in Google's index later than your product's other content
- Any gap in structured data visibility means a gap in rich snippet eligibility
FiveOh Reviews on Metaobjects renders structured data server-side in Liquid - your AggregateRating is in the initial HTML, not injected by JavaScript after page load.
Get more information →4. How to audit your store right now
Step 1: Google's Rich Results Test
Go to search.google.com/test/rich-results, enter a product URL, and run the test. Look for a "Products" result. If aggregateRating is missing or shows a warning, your stars will not appear.
Importantly, this tool renders the page without JavaScript by default. Run it both ways (with and without JS). If rating data appears in the JS-rendered version but not in the raw HTML version, you have failure mode 2.
Step 2: Google Search Console URL Inspection
In Google Search Console, use "URL Inspection" on a product page and click "View crawled page". Switch to the "More info" tab and check "Detected structured data". If Product → aggregateRating is absent, Google has not indexed it.
Step 3: View page source
In your browser, go to a product page and press Ctrl+U (or Cmd+U) to view the raw HTML source - not the DevTools DOM which reflects JavaScript execution. Search for aggregateRating. If it is absent from the raw source but present in the DevTools inspector, JavaScript is the only thing generating it.
5. The fix: server-side structured data
The reliable fix is to output aggregateRating structured data server-side - directly in the HTML that Shopify sends on the first byte - rather than generating it in a JavaScript widget.
This is possible when your review aggregate data is stored in Shopify itself, accessible to Liquid during the server-side render. Shopify's standard product review Metaobjects store exactly this: the reviews.rating and reviews.rating_count Metafields on the product object are available in Liquid without any API call.
When you use a review app that stores data in third-party servers, this path is unavailable - the aggregate rating does not exist inside Shopify, so Liquid cannot access it. The only option is the JavaScript widget, with all the crawlability downsides that entails.
6. Liquid implementation
Add the following to your theme's product.json template or product.liquid template, inside a <head> block or directly in the body:
{%- if product.metafields.reviews.rating.value != blank -%}
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "Product",
"name": {{ product.title | json }},
"image": {{ product.featured_image | image_url: width: 800 | prepend: 'https:' | json }},
"description": {{ product.description | strip_html | json }},
"sku": {{ product.selected_or_first_available_variant.sku | json }},
"offers": {
"@type": "Offer",
"priceCurrency": {{ cart.currency.iso_code | json }},
"price": {{ product.selected_or_first_available_variant.price | divided_by: 100.0 }},
"availability": "https://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "{{ product.metafields.reviews.rating.value }}",
"bestRating": "5",
"worstRating": "1",
"reviewCount": "{{ product.metafields.reviews.rating_count.value }}"
}
}
</script>
{%- endif -%}This block outputs nothing if no reviews exist (the != blank guard), and outputs a complete, valid Product schema when they do. Googlebot reads it on the first crawl of the page - no JavaScript execution required.
snippets/structured-data.liquid file. Check if your theme has it and add the aggregateRating block to the existing structure rather than creating a duplicate Product schema.FiveOh Reviews on Metaobjects handles all of this automatically - structured data, Metaobject storage, and server-side rendering included out of the box.
Get more information →7. After the fix: what to expect
Once server-side structured data is in place, the timeline to seeing stars in search results typically looks like:
- Days 1–3: Google re-crawls the page and picks up the structured data in the first HTML pass
- Days 3–14: Rich Results Test and Search Console URL Inspection start reporting
aggregateRatingas detected - Weeks 2–6: Star ratings begin appearing in search results for pages that Google has re-indexed
The timeline depends on how frequently Google crawls your store. High-traffic stores with fresh content are re-crawled more often. You can request re-indexing for individual URLs via Google Search Console's URL Inspection tool to speed this up.
Once stars appear, they typically increase organic click-through rate by 10–30% on product listings - the visual trust signal is significant at the point where a user is deciding which result to click.
Written by Marius Korbmacher
Lead Developer at FiveOh Reviews on Metaobjects
FiveOh Reviews on Metaobjects
Reviews stored in Shopify. Rendered in Liquid. Yours to keep.
The review app that writes to Shopify's standard product review Metaobjects - server-side rendering, no JavaScript widget, no external dependency, no vendor lock-in.
