GUIDE № 16 · STRUCTURED DATA
Are Your Shopify Reviews Visible to AI? A Five-Minute Check
You have 2,000 five-star reviews. If your widget loads via JavaScript and your theme doesn't emit Review schema, AI crawlers may see an empty div where those reviews should be.
Your reviews are arguably the single highest-trust signal on your store. But if your review widget loads reviews via JavaScript after page render — and most of them do — AI crawlers see an empty div where your reviews should be. This guide walks through why that happens, the two fixes that work, how to check your own store without DevTools, and the app-by-app state of Yotpo, Judge.me, Stamped, Loox, Okendo, and Junip.
Why your review widget is invisible to AI
AI crawlers prefer server-rendered HTML. When GPTBot, ClaudeBot, or PerplexityBot fetches a product page, it reads the HTML the server returned and stops there. It doesn't execute JavaScript. It doesn't wait for an XHR call. It doesn't scroll to trigger a lazy-load. If your reviews aren't in the first HTML response, they don't exist as far as the crawler is concerned.
Most Shopify review apps default to a client-side widget because it keeps the initial page fast. The trade-off is that the review content lands in the DOM after the crawler has already taken its snapshot. When an assistant indexes your product page, it sees a <div id="yotpo-widget"></div> with nothing inside it. Your 4.8-star average and 2,143 reviews are invisible.
Clean, structured, machine-readable product data gives AI the raw material it needs. A widget that only exists after JavaScript runs is the same failure mode as FAQs that lazy-load after a click. For the broader schema work this guide plugs into, see the JSON-LD structured data guide and the semantic HTML for AI guide.
The two fixes
There are two reliable paths. Most stores can do one; a handful can do both, which is the strongest configuration.
Fix 1: switch the widget to server-rendered mode. Several review apps offer an "SEO widget" or "server-rendered" tier where the initial HTML response includes the rendered reviews — stars, counts, individual review text — instead of an empty placeholder div. The widget still hydrates on the client for interactivity, but the content is already there for a crawler that never runs the hydration step. Usually a single toggle.
Fix 2: emit AggregateRating and Review JSON-LD. Independent of how the widget renders, include review data in structured form inside a <script type="application/ld+json"> block. The schema lives in the page source regardless of whether JavaScript runs, so crawlers pick it up on the first pass. Works even when the widget is stuck in client-only mode.
If you can only pick one, the JSON-LD path is the safer floor — it doesn't depend on the app supporting server rendering at all.
How to check yours (no dev tools needed)
You can confirm whether your reviews are visible to AI in under a minute, without ever opening DevTools. Two browser-native methods:
View source. Open any product page, right-click anywhere that isn't an image or link, and pick View Page Source (or press Cmd+U on Mac, Ctrl+U on Windows). You're looking at the raw HTML the server returned — exactly what a crawler sees. Use Cmd+F to search for a snippet of a specific review you know exists. If the review text is in the source, you're fine. If the search returns zero matches, the reviews aren't server-rendered.
Disable JavaScript. In Chrome, press Cmd+Shift+P (Mac) or Ctrl+Shift+P (Windows) to open the command palette. Type Disable JavaScript, pick the command, then reload. If your reviews are gone — blank widget, loading spinner, nothing at all — that's what a crawler sees. If the stars and review text still render, the widget is server-rendered. Re-enable JavaScript afterwards from the same palette. (These instructions assume Chrome on desktop. Disable-JS workflows differ on Safari and on most mobile browsers.)
From the terminal, the one-liner version is a curl with no JS context at all:
curl -s https://yourstore.com/products/whey-isolate-vanilla-2lb \
| grep -oE '(AggregateRating|ratingValue|reviewCount|"@type":"Review")' | sort -u
That returns any schema-level review markers in the raw HTML. If it prints AggregateRating, ratingValue, and reviewCount, your JSON-LD fallback is working. If it prints nothing, neither the widget nor the schema is emitting anything AI can use.
How to fix it: app by app
Every major Shopify review app has a different answer for server rendering. Per-app states described here change frequently as vendors update plan tiers and SSR options. Always confirm current behavior in each app's docs before relying on this guide. (Last reviewed: 2026-05.)
Yotpo. Yotpo offers an "SEO-friendly" widget tier on its paid plans that server-renders the review content and emits JSON-LD schema alongside it. On the free tier, reviews are client-side only. If an upgrade isn't on the table, the JSON-LD fallback covers the schema side regardless.
Judge.me. Judge.me renders its review widget in HTML by default on most themes and emits AggregateRating plus Review JSON-LD out of the box. Open view-source and confirm the review text and schema are both present. If they aren't, check the app settings for SEO boost or rich snippets.
Stamped. Stamped offers a dedicated SEO widget option that server-renders the reviews and wraps them in schema. Enable it in the widget settings — the non-SEO widget looks visually similar but only renders after JavaScript runs.
Loox. Loox is primarily a client-side photo-review widget; the visible stars and gallery typically load via JavaScript. Loox historically did not emit JSON-LD by default — star-rating schema has been a paid feature on some plans, and as of 2025–2026 availability still varies by tier. Confirm in your Loox dashboard, then run the curl check above to verify AggregateRating actually lands in the page source. If it doesn't, fall through to the JSON-LD fallback below.
Okendo. Okendo offers a server-rendered widget option on higher tiers and emits schema by default. Check the app's installation settings for Server-side rendering or similar wording; if it's available on your plan, turn it on. If not, the JSON-LD path still gets the structured data in front of crawlers.
Junip. Junip supports schema emission for AggregateRating and individual reviews out of the box. Check the app's SEO or Rich snippets settings and confirm the schema is enabled; check their docs for the current state of server-rendered widget support.
If your app isn't listed or doesn't support server rendering. Most of them expose the underlying review data via an API or a Liquid object. That data is what you feed into the JSON-LD fallback below. Schema-only is a legitimate configuration — you don't need the widget itself to be server-rendered if the structured review data is in the page source.
The JSON-LD fallback when server rendering isn't available
AggregateRating and Review are schema.org types designed exactly for this problem. They live inside your Product JSON-LD block and give AI crawlers a structured summary without any dependency on how the widget renders. The minimum useful shape:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "NutriPure Whey Isolate Protein Powder Vanilla 2lb",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.8",
"reviewCount": "2143"
},
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Jamie R." },
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Mixes cleanly, no chalky aftertaste. Using it post-workout for 3 months."
}
]
}
The aggregateRating object is the summary every crawler wants — average stars and total count. The review array is optional depth. Three to five recent reviews are plenty — enough for the assistant to quote from, not so many that the JSON-LD block becomes bloated.
In a Shopify theme, this goes in sections/main-product.liquid or a dedicated snippets/review-schema.liquid. Pull ratingValue and reviewCount from the review app's Liquid object (Judge.me, Stamped, and Okendo all expose these) or from a product metafield. A few rules to keep the schema valid:
- Values in
aggregateRatingmust match the rendered page. A schema-only claim of a higher rating than the widget shows is a policy violation that can get the markup ignored. - Individual
Reviewentries need anauthor, areviewRating, and areviewBody. Missing any of those will fail Rich Results Test. - Don't embed HTML in
reviewBody. Plain text only; strip any markup the app emits.
Edge cases: low volume, unsupported apps, multi-variant reviews
Fewer than 10 reviews. The schema is still worth emitting. A store with 6 reviews averaging 4.7 stars is just as useful to an AI assistant as a store with 600 — the buyer asking "is this well-reviewed" gets a concrete answer either way. Emit AggregateRating as soon as you have more than one review.
Apps that don't support server rendering at all. Schema-only is the path. Pull the review data from the app's API or Liquid object, build the JSON-LD in your theme, and skip the widget question entirely. The visible widget stays client-side for shoppers; the crawler reads the schema. Legitimate, common configuration.
Multi-variant reviews. If each variant has its own review stream, the schema should reflect the variant scope a shopper lands on. Judge.me and Okendo both support per-variant filtering; Yotpo aggregates at the product level by default. Match the schema to whatever the widget shows — don't inflate a single variant's count by summing across variants.
Star ratings in Google Shopping. If you sync to Google Merchant Center, review stars can also come through a separate Product Reviews feed. Complementary, not a replacement — on-page schema still matters for AI crawlers that don't go through Merchant Center. For the off-site feed side, see off-site signals for AI recommendations.
Incentivized reviews. Google and the FTC both treat undisclosed incentivized reviews as a policy violation. If you hand out discount codes for reviews, disclose it in the review or the surrounding copy. A clean JSON-LD feed that later gets flagged is worse than no schema — the markup gets ignored across the board.
Verify the fix worked
After the widget change or the JSON-LD deploy:
- Re-run the view-source or disable-JavaScript check from earlier. Stars, count, and individual review text should be visible in the source with JS off. If they aren't, the server-rendering toggle didn't take — check the app settings or fall back to the JSON-LD path.
- Run the product URL through Google's Rich Results Test. Under the Product card, look for
AggregateRatingwith a non-zeroratingValueandreviewCount. Zero errors. - Run it through validator.schema.org for a stricter schema.org-native pass. Rich Results Test is more lenient; this one catches missing
@typeon nested objects. - A week or two later, ask ChatGPT or Claude a review question: "what do people say about the flavor of the NutriPure Whey Isolate?" A store with clean schema often gets a specific answer — "rated 4.8 stars across 2,100 reviews, buyers describe the vanilla as clean and not chalky." Without schema, usually a generic "I don't have review data for that product."
Reviews are the highest-trust on-page signal you have. If AI crawlers can't see them, you're burning your single best asset at the exact moment a buyer is deciding. An afternoon of widget-setting changes or a server-side snippet fixes that. Run a free audit on your store →