Review is the Schema.org type for an individual rating of a product, service, or other item1. It complements AggregateRating: AggregateRating is the average; Review is one data point. On Shopify, individual Review objects are rarely necessary — AggregateRating alone is enough for a product's review snippet. Review JSON-LD is worth emitting when AI engines benefit from the full review text, or when a few representative reviews are shown prominently on the page.
Google's self-serving rule is narrower than it's often described2. It covers a business controlling reviews about itself on pages marked up as LocalBusiness or Organization. Customer reviews of a product, collected from shoppers and shown on your own product page, are not self-serving under that rule, whichever review app collects them. What Google does rule out for any type: ratings that aren't sourced directly from users, reviews copied from other websites, and fake or undisclosed incentivized reviews.
§01Definition
What Review schema is
Per Schema.org v30.0, Review is 'a review of an item — for example, of a restaurant, movie, or store.' Inheritance: Thing > CreativeWork > Review. Key properties: author (Person or Organization), datePublished, reviewBody (Text — the full review text), reviewRating (Rating with ratingValue), itemReviewed (the Product being reviewed), publisher. Optional: positiveNotes, negativeNotes for extraction-friendly pro/con summaries.
Mental model: Review is one record; AggregateRating is the rollup. A Shopify PDP with 47 reviews could carry 47 Review objects plus one AggregateRating. In practice, AggregateRating alone is sufficient for the star snippet, and emitting 47 individual Reviews bloats the page. Reserve individual Review emission for cases where AI engines benefit from the review text directly — high-consideration purchases, complex products, or pages where reviews are the dominant content.
§02Self-serving
The self-serving policy applied to individual Reviews
Google's review snippet guidelines apply to individual Reviews and AggregateRating alike. The self-serving rule is specific: if the entity being reviewed controls the reviews about itself, its pages that use LocalBusiness or any other Organization markup are ineligible for the star feature. That catches a store marking up testimonials about the store itself. It doesn't catch product reviews: a Review of a Product, written by a customer and shown on the product page, is eligible whether it was collected by Judge.me, Yotpo, Okendo or an in-house system.
§03Fields
Review fields
The Review properties Google requires: author (a Person or Organization with a valid name), reviewRating (a Rating with ratingValue), and itemReviewed with its name (handled implicitly when Review is nested inside Product). Recommended: datePublished and reviewBody. bestRating and worstRating default to 5 and 1 when omitted. A Review missing a required property is reported as an error in the Rich Results Test; a missing recommended one is not.
author — required. Person object with name, shorter than 100 characters, and a real name rather than text like "50% off until Saturday". First name plus last initial is fine.
datePublished — recommended. ISO 8601 date.
reviewBody — recommended. The review text.
reviewRating — required. Rating object with ratingValue (1–5 by default).
itemReviewed — implicit when nested in Product; explicit, with a name, if emitted top-level.
publisher — optional Schema.org property; Google doesn't use it for review snippets.
positiveNotes / negativeNotes — optional. ItemList of strings. Google shows pros and cons only for editorial product review pages, "not merchant product pages or customer product reviews"6, so on a Shopify PDP they won't produce a Search feature.
§04Example
JSON-LD example — Review array inside Product
The block below shows a Review array inside a Shopify Product block. Shopify's standard product_review metaobject (fields such as rating, body, author_display_name, published_at) is where review apps are asked to syndicate reviews, but each entry points at its product, not the other way round, so Liquid on a product page can't look them up directly. The example reads a list metafield, custom.recent_reviews, that a review app or your own automation keeps filled with that product's latest entries; swap in whatever your app provides. Limit it to the 3–5 reviews shown on the page.
JSON-LDReview array nested in Product, from a list of product_review metaobject entries
Review text is customer-written, so it goes through | json: the filter adds the quotes and escapes quotes and line breaks inside the review5. | escape is an HTML filter and would break the block on the first multi-line review. The rating field is a rating-type value, so the score, the top of the scale and the bottom of the scale come from its rating, scale_max and scale_min properties8.
§05Validation
Validation
Rich Results Test against a PDP with individual Reviews should report Product detected with its Review objects parsed and no errors. Errors come from missing required properties: an author with a name, or reviewRating.ratingValue. A missing datePublished or reviewBody is a recommended-field warning, not an error. A clean test means the markup is eligible; Google still decides whether to show stars.
A subtle gotcha: the Rich Results Test does not always reliably flag missing or malformed dates. If datePublished serializes as an empty string (because the Liquid metafield is null on older reviews), the markup validates, but Google's main index downstream may demote the snippet. Always branch with {% if r.published_at %} before emitting datePublished.
§06Gotchas
Shopify gotchas on Review
Three gotchas catch most Shopify Review schema work. First: emitting too many Reviews — 50+ individual Review objects bloat the page and add no rich-result benefit beyond what AggregateRating already provides. Cap the loop at 3–5. Second: emitting Reviews without escaping reviewBody, which breaks the JSON when customers leave quotes or backslashes in their text. Third: marking up reviews that shoppers can't see on the page, or reviews imported from another website. Google requires review content to be readily available on the marked-up page and sourced directly from users.
If your store still runs a template built for Shopify's own Product Reviews app, note that the app is no longer available on the App Store3; check where the review data now comes from before you trust the markup.
A fourth gotcha for multi-language stores: Review.inLanguage should be set when the review text is in a non-default language. Shopify's translation infrastructure handles the product copy, but customer review text retains the language the reviewer wrote in — mark it explicitly with "inLanguage": {{ r.locale | default: request.locale.iso_code | json }} so AI engines parse the language correctly. Don't fall back to shop.locale: Shopify deprecated it in favour of request.locale7.