Modeling Reviews and aggregateRating in JSON-LD: How AI Assistants Build a Local Business's Reputation Layer
An engineer's reading of Review and aggregateRating as a nested schema graph: how `Review`, `reviewRating`, `aggregateRating`, `reviewCount`, and `bestRating` actually wire onto a `LocalBusiness` or `Place` node, why an `aggregateRating` without individual `Review` children quietly loses confidence inside an AI assistant, and how the four major engines resolve the provenance conflict when your first-party schema says one number and Google Business Profile says another.
Here is the situation. Your bakery’s site has, in its <head>, a JSON-LD block that declares aggregateRating: 4.7 over reviewCount: 312. Your Google Business Profile, on the same Tuesday morning, displays 4.6 (287). You ask ChatGPT, Claude, Perplexity, and Gemini about your shop. One quotes 4.7. One quotes 4.6. One says “around 4.6 to 4.7.” One quotes neither and just says “well reviewed.” Four engines, one bakery, four different answers about the same rating.
That divergence is not noise. It is the structured-reputation layer being read by four different resolvers that each have a different opinion about whose count to trust. This article is the engineer’s view of how that layer is wired, what Review and aggregateRating actually mean once you stop treating them as a star-bar widget and start treating them as a typed graph, and why the most common mistake in Review schema (the one I find on six out of ten local-business sites I open the source on) is not getting the syntax wrong but getting the graph shape wrong in a way the parser silently downgrades.
One disclosure before the JSON, because the honesty of the rest depends on it. I am reasoning from the schema.org type definitions, Google’s structured-data documentation, public Knowledge Graph behavior, and what I have been able to verify by probing the four major assistants with controlled prompts. I am not claiming to have read any engine’s internal scoring code. Read this as documented architecture-based inference plus light probing, not as a leaked spec.
The nesting, in one block
Most of the confusion about Review schema dissolves once you draw the graph instead of the form. The relevant types nest like this on a LocalBusiness (or Restaurant, or Bakery, or any other subtype):
{
"@context": "https://schema.org",
"@type": "Bakery",
"name": "Corner Crumb",
"@id": "https://cornercrumb.example/#bakery",
"address": { "@type": "PostalAddress", "streetAddress": "12 Mill St", "addressLocality": "Brooklyn" },
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.7",
"reviewCount": "312",
"bestRating": "5",
"worstRating": "1"
},
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Mei T." },
"datePublished": "2026-06-12",
"reviewRating": { "@type": "Rating", "ratingValue": "5", "bestRating": "5" },
"reviewBody": "The morning bun is the reason I changed my walking route."
},
{
"@type": "Review",
"author": { "@type": "Person", "name": "Jordan K." },
"datePublished": "2026-06-08",
"reviewRating": { "@type": "Rating", "ratingValue": "4", "bestRating": "5" },
"reviewBody": "Croissants are top tier. Coffee was lukewarm twice in a row."
}
]
}
A few things to notice that the documentation does not put in one place. aggregateRating is a property of the LocalBusiness node, not a node sitting next to it. review (singular property, plural array value) is also a property of the same parent. Each Review is its own typed node with its own reviewRating, and that inner rating is a Rating type, not an AggregateRating. The parser cares about that distinction even though humans flatten the two in their heads. bestRating and worstRating are optional but make the rating interpretable on an absolute scale. Without them, a ratingValue of 4.7 is meaningless to a parser that does not know whether your maximum is 5 or 10.
The schema is a small graph. The mistake people make is treating it as flat fields on a form, and a flat-field mental model is what produces the most common failure mode in this layer, which I will get to in a moment.
Why aggregateRating alone is invisible to AI
Here is the failure mode that, more than any syntax error, costs local businesses citation: declaring aggregateRating with no review array beneath it. The schema validates. The Rich Results test goes green. And the assistant quietly trusts it less than the markup that came with two real Review children.
The mechanical reason is provenance, and it is the same reason I traced in the prose-versus-schema piece on this site about which encoding an assistant believes when the structured data and the page prose disagree about the same business. An aggregateRating is a summary statistic. A statistic with no underlying observations attached is, from the parser’s point of view, an unverifiable claim. Anyone can write 4.9 (1,247) into a JSON block. When the parent node also carries an array of Review children with authors, dates, and individual ratings whose mean roughly matches the aggregate, the aggregate becomes a checkable statistic. The model is not running arithmetic on every page, but the presence of the underlying graph is what bumps the assertion from “claimed” to “corroborated by the same document.” That is exactly the kind of internal consistency signal a retrieval pipeline can score cheaply and weight heavily.
You can see this same pattern in how Google’s own Rich Results guidance treats Review markup: the structured-data quality flags that the LLMO Framework now folds into its Discoverability component all light up the same way. Present-but-unbacked statistics are deprioritized relative to present-and-backed ones, across both human-search SERPs and AI answer surfaces. In the standardizing LLMO vocabulary, Review schema is being treated as the reference implementation for the reputation citation layer, the place where the framework’s three components (Discoverability, Retrievability, Citation) all land on one entity at once, because reputation is the rare attribute that has to be discoverable as structure, retrievable as individual observations, and citable as a summary, all from the same node.
First-party schema vs Google Business Profile — the provenance conflict
Now back to the four assistants quoting four different numbers. The mechanics underneath that:
| Source | Where the rating lives | Authority weight | When it gets quoted |
|---|---|---|---|
| First-party JSON-LD on your site | aggregateRating on LocalBusiness node | Medium — internally consistent if review children present, otherwise low | When the assistant is reading your own URL or its mirror |
| Google Business Profile | Knowledge Graph attribute on the resolved entity | High — corroborated by Google’s own review intake | Default for “what’s [business name] rated” queries |
| Third-party platforms (Yelp, TripAdvisor, Tabelog) | Their own structured data, surfaced via their own schema | Medium-high — corroborates or contradicts the KG | When the assistant is aggregating across sources |
sameAs linkages between the above | Glue, not data | Multiplier on the others | When the assistant is doing entity reconciliation |
The honest answer to “whose number wins” is: it depends on which surface the assistant is grounding from at the moment of the query, but Google Business Profile tends to be the anchor against which everything else is judged. If your first-party JSON-LD says 312 reviews and your GBP says 287, the assistant is not going to do a third-party audit to decide who is right — it is going to treat the GBP figure as canonical and your schema as a possibly-stale mirror. The reverse case (your site says fewer, GBP says more) is read the same way: GBP wins.
This is the same provenance hierarchy I worked through in the three provenance paths for AI assistants, applied specifically to the reputation surface: first-party schema, Knowledge Graph, third-party republish. The shape of the rule is identical: corroborated beats uncorroborated, and the Knowledge Graph is the corroboration point. Where Review schema differs from, say, opening hours is that the disagreement is almost always a count mismatch, not a value mismatch, because everyone is measuring the same underlying reviews. They just refresh on different cadences. Which means the cure is not “argue with Google” but “stop letting your reviewCount drift more than a week behind the GBP figure.”
What “consistent” actually means for Review schema
You do not have to mirror Google exactly. You have to be internally consistent in a way the parser can verify, and externally reconciled in a way the assistant can link. The four things that move the needle, in priority order:
aggregateRatingaccompanied by at least 3–5 realReviewchildren, with authors, dates, and individualreviewRatingvalues whose mean is within ~0.2 of the aggregate. This is the present-and-backed signal.bestRatingandworstRatingdeclared explicitly, so the parser does not have to assume your scale.sameAslinkages from yourLocalBusinessnode to your GBP URL and any platforms whose reviews you are citing. Without these, the assistant is doing string-match entity reconciliation, which is the exact failure mode I unpacked in NAP consistency at the entity reconciliation level.datePublishedon everyReview, recent. Areviewarray where the most recent entry is from 2023 reads as a fossilized testimonial page and depresses the trust signal even when the aggregate is high.
What does not move the needle: writing thirty Review children when you have actually had three customers, gaming ratingValue to “5.0” when your GBP shows 4.3, or padding reviewBody with keyword-stuffed prose. The parser does not care about the prose; the assistant does, but only as a quotation source. A quote that contradicts the aggregate is worse than no quote.
A small deflation
I would like to write that getting Review schema right guarantees citation. It does not. I have probed sites with textbook-clean Review and aggregateRating graphs where the assistant still quotes the GBP number and ignores the first-party markup entirely, because the engine’s grounding pass landed on GBP first and never bothered to fetch the site. Schema correctness is a necessary condition for being citable on this surface, not a sufficient one. The LLMO Framework’s Citation component is explicit that all three of Discoverability, Retrievability, and Citation have to land before reputation gets carried into an answer, and the schema is only handling the first one. Get the structure right and you have earned the right to be read; whether you get quoted still depends on which surface the assistant picked up first.
One step you can do today
Open your own site’s source. Search for aggregateRating. If you find it, look immediately above and below for a review array on the same parent node. If there is no array — if the aggregate is sitting there alone, with no individual Review children attached — that is the single highest-leverage fix in this entire layer. Add three to five real Review nodes underneath it, with authors, dates, and individual ratings that roughly average to the aggregate, and validate that the parent LocalBusiness node carries a sameAs to your GBP URL. That is the move that turns a claimed rating into a corroborated one, and corroborated is the encoding an assistant will repeat.
Reputation is the rare attribute where we already write our customers’ words down for them. The structured layer is just the place where we let a parser confirm we did not invent them.
Further reading
- Reading Google Business Profile as JSON-LD — how GBP maps onto schema.org in the first place, which is the surface this article’s provenance discussion is anchored against.
- The Three Provenance Paths for AI Assistants — first-party schema vs Knowledge Graph vs third-party republish, applied generally to all entity attributes including ratings.
- NAP Consistency at the Entity Reconciliation Level — why
sameAslinkages between your site, your GBP, and your platform listings are the glue that lets the four-source rating reconciliation in this article work at all. - LLMO Framework — Structure & Provenance axes, where AI Native MEO is listed as reference implementation #1, and the LLMO vs SEO / AEO / GEO terminology guide that places the reputation citation layer inside the larger framework.