Schema Review Markup: How to Earn Star Ratings Without Getting a Manual Action

schema review markup

Star ratings in the search results are one of the few visual differentiators left on a page-one listing, and schema review markup is how you tell Google those stars exist. It is also one of the most misused vocabularies in the entire Schema.org catalog. Half the implementations I audit are technically valid JSON-LD that Google will never render, because the rules that govern review schema markup are policy rules, not syntax rules.

Valid code is table stakes. Eligibility is the actual game. Here is what determines whether your stars appear.

What Review Markup Actually Does

Review markup is structured data that describes an evaluation of a thing. There are two related types. Review describes a single evaluation by one author with one rating. AggregateRating summarizes many evaluations into an average score and a count. Most sites want the second one, because “4.6 out of 5, 213 reviews” is the snippet that moves click-through rate.

Both types are nested inside the thing being reviewed. You do not publish a floating Review object. You publish a Product, a Recipe, a Course, or a Movie, and you attach the rating to it. That nesting is where most implementations break: the review is present but the parent entity is missing required fields, so Google discards the whole block.

The Self-Serving Review Rule Nobody Reads

In September 2019 Google stopped showing review rich results for reviews an entity writes about itself. If your markup describes LocalBusiness or Organization and the reviews are collected on your own site about your own business, they are not eligible. That policy has not been reversed. It is still the single most common reason a technically perfect implementation produces zero stars.

You cannot route around it by embedding a third-party widget and marking up the average it displays, either. Google’s guidance is explicit that ratings sourced from another site and republished on yours do not qualify. If you want stars for your business as a whole, the realistic path is earning them on the platforms Google already trusts, not marking them up on your homepage.

Which Page Types Are Eligible

Review snippets are supported for a bounded list of content types. The practical set most sites will use:

  • Product — physical or digital goods, the highest-volume use case by far
  • Recipe — still one of the most reliably rendered rich result families
  • Book — individual titles, not category pages
  • Movie — including critic review markup
  • Course — individual courses with a provider and description
  • SoftwareApplication — apps with a category and operating system
  • Event — dated, located occurrences

Notice what is absent. Blog posts, service pages, category listings, and agency homepages are not on the list. Adding AggregateRating to an Article is not a clever hack; it is invalid markup that risks a structured data manual action if the pattern looks deliberately deceptive.

A Minimal Implementation That Passes

JSON-LD in the <head> or anywhere in the body is Google’s preferred format. Here is a compact product example with an aggregate rating and one individual review:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Trail Runner 400",
  "image": "https://example.com/img/tr400.jpg",
  "description": "Lightweight trail shoe with a 6mm drop.",
  "sku": "TR400-BLK-10",
  "brand": { "@type": "Brand", "name": "Example Athletics" },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.6",
    "bestRating": "5",
    "ratingCount": "213"
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "Dana K." },
    "datePublished": "2026-04-11",
    "reviewRating": {
      "@type": "Rating", "ratingValue": "5", "bestRating": "5"
    },
    "reviewBody": "Held up over 300 miles of wet singletrack."
  }]
}
</script>

Three details matter more than they look. ratingCount must be a real integer that matches what a human sees on the page. bestRating defaults to 5 if omitted, so declare it whenever your scale differs. And author must be a person or organization name — never the name of the site itself, which Google treats as a self-serving signal.

The Visibility Requirement

Structured data must describe content the user can see. If your markup claims 213 reviews and the page shows a bare product description with no reviews anywhere, that is a policy violation, not an optimization. Google has issued manual actions for exactly this pattern, and recovery means removing the markup, filing a reconsideration request, and waiting out a review queue that can run several weeks.

The safe test is simple. Load the page with JavaScript disabled if your reviews render client-side, and ask whether a person could verify every number in your JSON-LD by reading the page. If they cannot, fix the page before you touch the schema.

Aggregate Ratings Versus Individual Reviews

Deciding between the two comes down to what the page contains. A product page with 200 customer ratings wants AggregateRating, because the average and the count are the summary a searcher can act on. A single editorial review of someone else’s product wants a standalone Review nested in the item being reviewed, with a named author who is a real person.

You can supply both, and on high-value product pages you usually should — the aggregate for the star display, a handful of individual reviews for context Google may use elsewhere. Do not include hundreds of individual reviews in the markup; there is no benefit and you bloat the page payload for no return. Ten to twenty is plenty.

Rating scales trip people up. If you run a 10-point scale, declare "bestRating": "10" and "worstRating": "1" explicitly. Omitting them means Google assumes a 5-point scale, and an 8.4 rating gets interpreted as 8.4 out of 5 — which will fail validation or render nonsensically. Schema markup for reviews is unforgiving about implied defaults.

Validating Before You Ship

Two tools, two jobs. The Schema Markup Validator at validator.schema.org checks whether your JSON-LD is well-formed against the vocabulary — it will catch a misspelled property or a broken nesting. Google’s Rich Results Test checks something different: whether Google considers the page eligible for a specific rich result today. A page can pass the first and fail the second, and the second is the one that determines what appears in search.

After deployment, Search Console’s rich result reports are the source of truth. They show what Googlebot parsed on the live URL, not what your staging environment produces. Give it a few days; the reports lag crawling. If a page shows “valid” in Search Console but no stars appear in the SERP, you are almost certainly hitting an eligibility or quality threshold rather than a code bug. Rich results are earned, never guaranteed.

Rolling It Out Across a Real Site

On a template-driven site, review markup is a template change, so a single mistake replicates across every product URL at once. That is why the sequence matters: validate one representative URL by hand, deploy to a small subset, confirm in Search Console, then roll out site-wide.

Scale is where auditing gets awkward. Checking 40 product pages by hand is tedious; checking 4,000 is impossible. This is where a crawler earns its place — SEO Rocket runs full-site crawls of 900+ pages and reports concrete evidence per issue, including the actual titles, URLs, and H1 text behind each finding, so you can see which templates diverged instead of guessing. It will not write your JSON-LD for you, but it will tell you exactly where the pattern broke.

Set a recurring check, too. Theme updates, plugin changes, and CMS migrations quietly strip structured data more often than anyone expects. A quarterly pass over your highest-value templates costs an hour and protects the one snippet element your competitors probably do not have.