Home › Blog › AggregateRating on Shopify: which review apps inject it correctly
AggregateRating on Shopify: which review apps inject it correctly and which silently break it
9 in 10 Shopify stores in our launch scan fail this signal — and almost every one of them has a reviews app installed, with visible stars on every product detail page. The on-page stars and the schema-readable stars are two different things, and AI shopping agents only read the second one. This guide is the per-app anatomy: what Judge.me, Yotpo, Loox, Stamped, and Okendo inject by default, where each rich-snippets toggle lives, the HTML-source-vs-JSON-LD diff that decides whether your reviews count, and a 30-day playbook for verifying the fix actually landed.
bestRating/worstRating by default, which AI shopping agents weight more strictly than Google does. The 30-day verification playbook at the bottom of this post is how you make sure the fix actually rendered.
In this guide
- The two kinds of stars on every Shopify PDP
- Why AggregateRating is the tie-breaker signal AI agents use
- What we found scanning 100 top DTC stores
- The HTML-source-vs-JSON-LD diff anatomy
- Per-app investigation: Judge.me, Yotpo, Loox, Stamped, Okendo
- The correct shape, written out
- How to fix in cost order
- Five mistakes we keep finding
- The 30-day verification playbook
The two kinds of stars on every Shopify PDP
Open any Shopify product page that has a reviews widget. You'll see something like “★★★★★ 4.7 (3,284 reviews).” Those stars are pixels — DOM elements, often SVGs or background images, rendered by JavaScript that your reviews app injected into the page. They're for humans.
There's a second set of stars on the same page that you can't see. They live inside a <script type="application/ld+json"> tag, written as JSON, structured according to schema.org/AggregateRating. This is what ChatGPT Shopping's crawler, Perplexity's PerplexityBot, Google's Googlebot, and every AI shopping agent we've inspected actually reads when they want to know whether your product has reviews.
The two are completely independent. A reviews widget can show 3,284 reviews on the page while your JSON-LD says nothing at all. We've scanned hundreds of stores; this is the rule, not the exception.
Why? Almost every reviews app ships with a setting called something like “rich snippets,” “schema markup,” or “SEO,” and almost every one of them ships it off by default. Some of them gate the toggle behind a higher plan tier. Some of them have it on by default but inject the schema as a separate floating block instead of slotting it into your existing Product JSON-LD, which strict parsers reject. The result is the same: visible stars, invisible reviews.
The investigation in this post is which apps fail in which way, and what to actually click in each one to fix it. If you'd rather read the per-signal reference first, we keep the canonical AggregateRating signal page updated with the toggle table for every major reviews app.
Why AggregateRating is the tie-breaker signal AI agents use
Of the 15 signals CatalogScan scores, AggregateRating is the highest-failing — but it's also one of the highest-leverage in the 60–80 score band where most stores live. Here's why:
Confidence weighting. When an AI shopping agent answers “what's the best running shoe for flat feet?”, it has dozens of products that clear the floor signals (Product JSON-LD present, GTIN populated, structured Offers). It has to rank them. AggregateRating is the first sortable input it gets after price and availability — a 4.7-star, 3,200-review product carries materially more confidence than a 4.9-star, 12-review one. But agents can only weight what they can read; no AggregateRating in JSON-LD means your product is invisible to that ranking.
Review-count thresholds. Some agent query types have minimum review counts. “Best”-style queries filter more aggressively than “where to buy” queries, but the trigger is consistent: if your reviewCount isn't in the JSON-LD, the filter treats your product as having zero reviews, even if your widget shows 3,284. We've seen this with our own scan-driven tests against ChatGPT Shopping: products with the AggregateRating off entirely consistently lose to lower-rated, lower-reviewed competitors that have it on.
Rich-card rendering. When ChatGPT Shopping or Perplexity Shopping cite your product, the star line in the rich card is rendered from ratingValue in your JSON-LD. Missing the field means the star line disappears from the card. The card looks weaker. Click-through drops.
Stack those three effects and AggregateRating ends up doing more ranking work than its 10-out-of-70 signal weight suggests. The signal weight is what we score; the downstream effect on agent ranking is roughly “you exist or you don't” in the 60–80 band where the marginal product is decided.
What we found scanning 100 top DTC stores
We ran the CatalogScan free scan against the top 100 DTC Shopify stores by traffic the week before launch. AggregateRating's failure rate was the highest of any signal we tested:
| Result | Stores | Notes |
|---|---|---|
| Passes (full credit) | ~9 / 100 | Has aggregateRating with both ratingValue and reviewCount in Product JSON-LD |
| Has reviews app, fails the signal | ~78 / 100 | Visible stars on every PDP, no aggregateRating in JSON-LD |
| No reviews app at all | ~13 / 100 | Honestly missing — fix is install a reviews app, then enable the toggle |
The 78% number is the interesting one. These are stores doing $1M to $50M+ a year, almost all with paid teams running their site, with a reviews app installed and paid for. The cost of the fix is one toggle, no developer required. The cost of doing nothing is being invisible to the review-weighted slice of every AI agent's ranking model.
Reviews-app market share in our 100-store sample tracks roughly to industry surveys: Judge.me about 28%, Yotpo about 22%, Loox about 19%, Stamped about 11%, Okendo about 8%, and a long tail of Reviews.io, Trustpilot embeds, Shopify's deprecated Product Reviews app, and custom Liquid setups making up the rest. Those five apps cover >95% of Shopify reviews installs we encounter, which is why this guide focuses on them.
The HTML-source-vs-JSON-LD diff anatomy
To know which failure mode you're in, you have to read both layers of the page. The page-rendered stars and the JSON-LD stars usually disagree in one of four shapes:
Shape A — visible stars, no JSON-LD
<!-- visible widget -->
<div class="jdgm-prev-badge"
data-average-rating="4.78"
data-number-of-reviews="3284">
★★★★★ 4.78 (3,284)
</div>
<!-- JSON-LD on the page -->
{
"@type": "Product",
"name": "Wool Runner",
"offers": {...}
/* no aggregateRating field */
}
Score: 0/10. The most common shape (≈78% of failing stores). The widget has the data; nobody injected it into JSON-LD.
Shape B — orphaned floating AggregateRating
<!-- separate JSON-LD block -->
{
"@context": "https://schema.org",
"@type": "AggregateRating",
"ratingValue": "4.78",
"reviewCount": "3284"
}
<!-- Product JSON-LD elsewhere -->
{
"@type": "Product",
"name": "Wool Runner"
/* no aggregateRating field */
}
Score: 0/10. Some apps inject AggregateRating as a top-level orphan. Strict parsers reject it — schema.org requires AggregateRating to be embedded in or referenced by an itemReviewed.
Shape C — typed wrong, value is a string with units
<!-- inside the Product -->
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.78",
"reviewCount": "3284 reviews"
}
Score: partial credit at best, zero at worst. Strict parsers want reviewCount as an integer or numeric string. “3284 reviews” trips them.
Shape D — correct, embedded, fully typed
<!-- inside the Product -->
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.78",
"reviewCount": "3284",
"bestRating": "5",
"worstRating": "1"
}
Score: 10/10. Embedded inside Product, both required fields present, both bounds set. This is what AI agents want.
To know which shape you're in: open any product page on your store, view source, search for aggregateRating case-sensitive. If you find it inside a <script type="application/ld+json"> block whose @type is Product, with both ratingValue and reviewCount set to numeric values, you're Shape D — done. Anything else is one of A, B, or C.
Per-app investigation: where the toggle is, what gets injected, what to watch out for
Here's the toggle path for each of the five reviews apps that cover >95% of Shopify stores. We've tested each one against a fresh demo store; the path notes are current as of the date on this post.
Judge.me toggle requiredfree + $15/mo
Judge.me is the most-installed reviews app on Shopify and the easiest fix in this list. The default-off rich snippets toggle is one click.
Toggle path
- Shopify admin → Apps → Judge.me
- Settings → SEO & Rich Snippets
- Tick “Enable rich snippets” (also labelled “Show ratings in Google search results” on older versions of the app)
- Save. Re-render any PDP within 5 minutes.
What it injects when on
Judge.me injects a self-contained aggregateRating node embedded in your existing Product JSON-LD via the {% raw %}{{ shop.metafields.judgeme.widget }}{% endraw %} Liquid include. The shape is correct (Shape D) — both ratingValue and reviewCount set, plus bestRating/worstRating.
main-product.liquid (or the equivalent section). If you removed the call when customizing the theme, the toggle is on but no schema injects. Verify by viewing source on a PDP: if you don't see Judge.me's badge HTML at all, the include is missing.
Yotpo Reviews tier-gated$15–$1,200/mo
Yotpo is the trickiest of the five because its rich-snippets injection depends on plan tier. Free and Starter plans inject a partial schema (Shape C — ratingValue only, no reviewCount) by default. Growth and Premium plans get the full embedded shape, but require a separate toggle.
Toggle path (Growth plan or higher)
- Yotpo dashboard → Reviews → Settings → On-site display → SEO
- Section “SEO settings” → enable “Schema markup”
- Optionally enable “Star ratings in Google search” (legacy Google-snippet feature, doesn't affect AI agents)
- Save. Force-refresh a PDP and view source.
What it injects when on
Yotpo injects a separate JSON-LD block by default (Shape B — orphan AggregateRating with no parent Product reference). Even on the highest plan, you need a second setting — “Inline schema in product object” — to switch to Shape D. This setting is buried under Settings → On-site display → Advanced → Schema; it's not in the same place as the main toggle.
main-product.liquid. If you're on the free plan and not planning to upgrade, the cheapest path is the inline-template fix in the “How to fix” section below.
Loox toggle required, hidden label$10–$300/mo
Loox's toggle exists, but it's labelled in a way that disguises what it does. Most operators don't realize the “Display in Google search results” setting also controls AI-agent visibility.
Toggle path
- Loox dashboard → Settings → Integrations → Rich snippets
- Toggle “Display in Google search results” on
- Save. Refresh a PDP within 60 seconds.
What it injects when on
Loox does a clean job — embeds AggregateRating directly inside the Product JSON-LD (Shape D), with all four fields. The injection happens server-side via Loox's Liquid include, so it's not gated on JavaScript execution.
loox-reviews) being present in your theme. If the snippet was removed during a theme customization, you'll see Loox stars rendered via JS but no JSON-LD on the server-side render — the injection silently no-ops.
Stamped Reviews toggle required$23–$479/mo
Stamped is structurally similar to Judge.me — one toggle, default off, correct shape when enabled.
Toggle path
- Stamped dashboard → Settings → Display → SEO
- Enable “Schema-org / Rich snippets”
- Save. Refresh a PDP within 60 seconds.
What it injects when on
Stamped emits a clean Shape D AggregateRating embedded in your existing Product JSON-LD. Both ratingValue and reviewCount always set; bestRating/worstRating set conditionally based on a separate setting under “Display advanced”.
Okendo on by default (most plans)$19–$299/mo
Okendo is the only one of the five that ships rich snippets on by default on Essentials and above. If you have Okendo and you're failing this signal, it's almost certainly because the schema injection point in your theme is broken or missing.
Verify path (rather than toggle)
- Okendo dashboard → Settings → SEO & integrations
- Confirm “Aggregate rating schema” toggle is on
- Confirm the Okendo widget snippet (
okendo-reviews-widget) is present in your theme'smain-product.liquid - If both are correct and you still don't see schema, check the “Inject inline” setting under “SEO & integrations → Advanced” — when this is off, Okendo emits the schema as a separate orphan block (Shape B).
What it injects when on
Okendo's default emission is Shape D — embedded inside the Product JSON-LD, all four fields set. The orphan-block fallback is only used if Okendo can't find the Product JSON-LD on the page.
{% raw %}{% schema %}{% endraw %} hooks, Okendo can't find the parent Product to embed into and falls back to the orphan block. Fix: check whether the SEO app exposes a hook for review-schema injection, or hand-inline the AggregateRating in your theme.
The correct shape, written out
If you're hand-injecting schema (because you're on a Yotpo plan that doesn't support it, because you've removed your reviews app's theme include, or because you'd rather not depend on the app's injection at all), this is the exact shape AI agents want to see, embedded inside your Product JSON-LD:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Wool Runner",
"sku": "WR-NAVY-10",
"brand": { "@type": "Brand", "name": "Allbirds" },
"offers": { "@type": "Offer", "price": "110.00", "priceCurrency": "USD",
"availability": "https://schema.org/InStock" },
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.78",
"reviewCount": "3284",
"bestRating": "5",
"worstRating": "1"
}
}
Four rules that separate Shape D from the other three:
aggregateRatingmust be a property of a Product, not a free-floating block.ratingValuemust be numeric — “4.78” or 4.78, not “4.78 stars”.reviewCountmust be an integer — “3284” or 3284, not “3,284” (comma trips strict parsers) or “3284 reviews”.- Set
bestRatingandworstRatingexplicitly. AI agents are stricter than Google's Rich Results Test about defaulting to 1–5.
If your store sells across multiple regions with different reviewers per region, you have a separate question to answer: do you aggregate globally or per-region? AI agents currently assume global. The schema doesn't have a clean way to express region-scoped reviews; if your French customers leave systematically lower ratings than your US customers, the global aggregate hides that. We don't have a great answer here — most stores aggregate globally and it's fine; some bigger stores split into separate Shopify shops per region and aggregate per shop.
How to fix, in cost order
$0 — flip the toggle in your reviews app (10 minutes)
This is the fix for ~80% of failing stores. Find your app in the table above, click through to the toggle, save. Verify within 5 minutes by viewing source on any PDP and grepping for aggregateRating. If it's there, you're done — no theme edit, no developer.
$0 — hand-inject in main-product.liquid (15–30 minutes)
If your reviews app doesn't expose a toggle (Yotpo free, Trustpilot embed) or you'd rather not depend on the app's injection, you can inline the AggregateRating into your theme's existing Product JSON-LD. The pattern is:
{% raw %}{%- if product.metafields.judgeme.badge -%}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": {{ product.title | json }},
"sku": {{ product.selected_or_first_available_variant.sku | json }},
{%- assign jm = product.metafields.judgeme.badge | parse_json -%}
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": {{ jm.value | json }},
"reviewCount": {{ jm.count | json }},
"bestRating": "5",
"worstRating": "1"
}
}
</script>
{%- endif -%}{% endraw %}
The metafield names differ per app — Judge.me uses judgeme.badge, Yotpo uses yotpo.reviews_average + yotpo.reviews_count, Loox uses loox.avg_rating + loox.num_reviews. Each app's docs list the exact metafield path. The general pattern is the same: pull rating + count from the app's metafield, slot into the AggregateRating node, embed inside Product.
$0–$25/mo — install a structured-data app
Apps like Smart SEO, SearchPie, or JSON-LD for SEO will write the Product schema for you and include AggregateRating from your reviews app's metafields. Useful if you want one place to manage all your structured data and you're already paying for one of these for other reasons. Avoid if you can fix it with the toggle — fewer moving parts is better.
$49/mo — CatalogScan Pro
CatalogScan Pro reads your live reviews data via Shopify Admin API metafields and patches the AggregateRating node into your Product JSON-LD without touching theme code. Useful if you're on a custom theme with multiple sources of truth or if you want server-side schema injection that survives theme upgrades. See Pro pricing.
Five mistakes we keep finding
1. Toggling on, but not redeploying or republishing the theme
Judge.me, Stamped, and Okendo write to the live theme via theme app extensions; the change usually propagates within 5 minutes. But if your theme is in “Customizing” mode in the Shopify editor, the changes don't go live until you publish. Always re-publish after toggling — this catches a surprising fraction of “the toggle is on but the schema isn't there” tickets.
2. Reviews live on a third-party domain (Reviews.io, Trustpilot widget) with the iframe embed
If your reviews are stored on a third-party domain (reviews.io, trustpilot.com) and the widget is loaded via an iframe rather than a Shopify-native app, the AggregateRating data isn't on your page — it's inside the iframe. AI agents don't read iframe content as part of the parent page's structured data. Fix: enable the on-site rich-snippets sync these services offer (Trustpilot's “Rich Snippets” tab in dashboard, Reviews.io's “Schema” tab) so the schema is injected into the parent page's JSON-LD, not the iframe's.
3. Setting ratingValue to 0 or omitting reviewCount on products with no reviews
Schema.org requires ratingValue ≥ 1 for AggregateRating to be valid. New products with zero reviews must omit the AggregateRating node entirely — emitting a zero-rating block silently fails validation. Most apps handle this correctly; Yotpo's free plan and some custom Liquid setups don't. Check your zero-review products specifically: if you see "ratingValue": "0" in the source, the schema is invalid for that product.
4. Multiple competing AggregateRating blocks on the same page
If you have both a reviews app's auto-injected schema and a hand-inlined block, the page can end up with two AggregateRating nodes — one in the Product, one orphan. Strict parsers may take the first they find; AI agents may average them; one might overwrite the other unpredictably. Fix: pick one source. If you've hand-inlined, turn off the app's auto-injection. If you're using the app's injection, remove your hand-inlined block.
5. Star rating shows in Google search but Rich Results Test reports “missing field”
Google has been historically flexible — it'll render stars in SERPs even when bestRating or worstRating is missing. AI shopping agents are stricter. If Rich Results Test reports a missing field, fix it — those agents will silently down-weight your product regardless of how Google handles it. Especially watch for bestRating/worstRating, which most apps don't emit by default.
The 30-day verification playbook
Flipping the toggle is the easy part. Verifying that the fix actually rendered, persisted across theme republishes, and is being read by AI agents takes 30 days. Here's the playbook we use on Pro stores:
Toggle on, immediate source check.
Toggle the rich-snippets setting on in your reviews app. View source on three different PDPs (one in-stock, one out-of-stock, one zero-reviews). For each, search for aggregateRating case-sensitive. Confirm Shape D: embedded in Product, both ratingValue and reviewCount set, integer-valued review count.
Rich Results Test pass.
Run one PDP through Google Rich Results Test. Should report “Page is eligible for rich results” with no AggregateRating warnings. If it reports missing bestRating or worstRating, return to your app's settings and check whether they're emitted optionally — if not, you'll need a hand-inlined block.
Re-scan with CatalogScan.
Run a fresh free scan against your store. Signal #5 (AggregateRating) should now read 10/10. If it reads 0/10 or 5/10, share the scorecard URL with our support; the per-app diagnosis will tell you which shape you're stuck in.
Search Console structured-data report.
If you have Google Search Console set up, the “Enhancements → Products” report should start showing reviewed products within 48–72 hours of the toggle. Watch for new errors in the same report — “Either ‘offers’, ‘review’, or ‘aggregateRating’ should be specified” should disappear; new warnings about bestRating/worstRating may appear (fix per Day 0).
Theme republish stress-test.
Make a small visible change in your theme (a copy edit somewhere outside the Product page), republish. Re-check one PDP for aggregateRating in the source. Theme republishes can occasionally strip schema injection if the include is misconfigured; this is the cheapest test that the fix is durable.
AI agent spot-check.
Open ChatGPT (in shopping mode) and ask: “Where can I buy [your specific product] online?” If your store appears in the response with a star rating in the rich card, the schema is being read end-to-end. If your store appears without stars while a competitor with the same product type shows them, you're emitting schema but not in a shape the agent likes — re-run Rich Results Test and check the AI-agent-strictness fields.
Re-scan, compare scores.
Run a fresh CatalogScan free scan. Compare the headline score to your Day 0 baseline. AggregateRating fix typically moves the headline score by 8–15 points depending on which other signals you were already passing. If your score didn't move at all, the fix didn't actually land — check whether the toggle is still on (some apps reset it during plan changes) and whether the theme include is still in place.
None of these checks individually proves your AI-agent visibility went up — that takes weeks of search-trend data we don't reliably have on a per-store basis yet. But they do prove the schema is correct, persistent, and parseable, which is the necessary condition for the agent's ranking model to see your reviews at all.
See also
- AggregateRating signal reference — the per-app toggle table
- Product JSON-LD: where AggregateRating must live
- JSON-LD validity — why one bad block invalidates the rest
- ProductGroup JSON-LD on Shopify: the related signal that's even higher-leverage
- Shopify metafields for AI shopping agents
- Shopify GTIN requirements for AI shopping agents
- The full 18-signal Agentic Storefronts checklist
- 100-store leaderboard — see who passes AggregateRating
- All 15 signals — full reference
Is your AggregateRating actually visible to ChatGPT?
Free 2-minute scan. We test the JSON-LD, not just the page-rendered stars — so you'll know within 90 seconds whether your reviews are scoring or invisible.
Scan my store → Read the signal reference