Schema and rich snippets

aggregateRating, Done Right: The Field Google Quietly Rejects

aggregateRating is where most star snippets silently fail. The required fields, the honesty rules, and why your stars are not showing.

Updated 2026-06-017 min

What fields does aggregateRating actually require?

aggregateRating is a small object, and the parts that matter are few. You need a ratingValue, the average score, and a count of how many ratings produced it. That count can be expressed as reviewCount (the number of written reviews) or ratingCount (the number of scores, including star-only ratings with no text), but you must provide at least one of them.

Everything else is optional. bestRating and worstRating default to 5 and 1, so you only declare them if your scale differs. Most stores never need to.

  • ratingValue: the average, for example "4.6".
  • reviewCount or ratingCount: at least one is required.
  • bestRating: optional, defaults to 5.
  • worstRating: optional, defaults to 1.

reviewCount or ratingCount: which one do I use?

Use ratingCount when your number includes star-only ratings with no written text, and reviewCount when every entry in the total is an actual written review. The distinction matters because the two numbers are often different, and declaring the wrong one inflates your total in a way that is easy to catch.

If a hundred people left a star rating and forty of them wrote something, reviewCount is 40 and ratingCount is 100. You can declare both. What you cannot do is put 100 in reviewCount when only 40 reviews exist, because the field name is a claim about what the number represents.

What is the count-must-match-visible rule?

Google's structured data guidelines require that the aggregateRating reflect reviews a user can actually see on that page. The count in your markup and the reviews rendered on the page are meant to be the same set. When they diverge, the markup is treated as not representative of the page, which is grounds for the star snippet to be withheld.

This trips up stores that show ten reviews on a product page but declare a count of two hundred in the schema. The intent may be honest (the product really does have two hundred reviews somewhere), but if the page only surfaces ten, the markup overstates what the page contains.

Why does a sitewide or inflated aggregate get rejected?

A common rejection is applying one global rating to every product. A store computes a single average across all reviews and stamps it onto each product page, so a brand-new product inherits the reputation of a bestseller. Google considers this misleading, because the aggregateRating on a Product is a claim about that product, not the store.

Inflation works the same way: padding the count, carrying over ratings from a discontinued variant, or counting reviews that are no longer shown. Each one makes the visible page and the declared markup disagree, and disagreement is what gets the snippet pulled.

  • One sitewide average reused on every product page.
  • A count larger than the reviews the page renders.
  • Ratings carried over from a different product or variant.
  • Counts that include hidden, removed, or unpublished reviews.

How do I check my aggregateRating is valid?

Read the rendered HTML, not the widget. Open the product page, view source or use the Rich Results Test, and confirm the aggregateRating object is present in the server HTML with a ratingValue and a count. Then count the reviews actually shown on the page and check the two numbers tell a consistent story.

The Rich Results Test will flag missing required fields, but it will not catch an honest-looking number that overstates the page. That part is on you: the tool validates shape, not truthfulness. A count of three hundred next to twelve visible reviews passes the validator and still risks a manual rejection.

Why are my stars still missing when the markup validates?

Validation confirms the syntax, not the eligibility. Your aggregateRating can be perfectly formed and still produce no stars if the count contradicts the visible page, if the markup is injected by a script the crawler does not run, or if Google simply chooses not to show the snippet for that query. The first two are fixable; the third is theirs to decide.

The injection problem is the quiet one. Many review apps render the rating into a JavaScript widget after load, so the aggregateRating a shopper sees never reaches the HTML a crawler reads. The field is correct. It is just not where the crawler looks.

What gets aggregateRating right, every time?

A correct aggregateRating is server-rendered, per-product, and honest: the ratingValue and count sit in the page HTML before any script runs, they describe that one product rather than the whole store, and the count matches the reviews on the page. Most review apps were built for the on-page shopper and render stars into a widget, which looks right and reads wrong to a crawler. Getting the rating you already have rendered into readable, per-product, count-accurate markup (so it earns the snippet in search and stays quotable in AI) is the gap BetterReviews is built to close.

2 fields
ratingValue plus a reviewCount or ratingCount: the minimum a valid aggregateRating requires
Google structured data guidelines, 2024
1:1
The count in markup must match the reviews actually visible on the page
Google structured data guidelines, 2024
Sitewide
Applying one store-wide or inflated average to a product is a common rejection reason
Schema rejection synthesis, 2025
Common questions
Do I need both reviewCount and ratingCount?
No, you need at least one. Use reviewCount when every entry is a written review, ratingCount when the total includes star-only ratings with no text. You can declare both if you have both numbers, but providing neither makes the aggregateRating invalid.
Can I use my store-wide average on every product?
No. The aggregateRating on a Product is a claim about that product, so a single sitewide average stamped onto every page is treated as misleading and is a common reason stars are withheld. Each product needs its own rating and its own count.
Do I have to declare bestRating?
Only if your scale is not out of 5. bestRating defaults to 5 and worstRating defaults to 1, so a standard five-star store can omit both. Declare them when you rate out of 10 or any other scale, so the ratingValue is read correctly.
My markup validates but I still have no stars. Why?
Validation checks syntax, not eligibility. The likely causes are a count that contradicts the visible reviews, markup injected by a script the crawler never runs, or Google electing not to show the snippet for that query. Check the rendered HTML and the visible count first.