A JSON-LD aggregateRating block that shows 4.5 stars while the page displays 4.3 stars is an active schema-org policy violation — Google's Rich Results guidelines prohibit structured data that misrepresents visible content. Discovery of the discrepancy triggers manual review and can result in a site-wide rich-result penalty. Beyond compliance, rating mismatch is a data-integrity failure: users who click a listing based on an inflated SERP star count and see a lower on-page rating experience an immediate trust collapse. The ratingValue and reviewCount in schema-org AggregateRating must be computed from the same database query that drives the visible UI.
High because mismatched structured-data ratings violate Google's explicit rich-results content policies, risking manual review penalties that suppress all rich results site-wide.
Derive the JSON-LD aggregateRating from the same source as the rendered rating — never hardcode or cache independently. Compute both from a single database read per listing.
// In your listing data fetcher
const listing = await db.listing.findUnique({
where: { id },
select: {
name: true,
averageRating: true,
reviewCount: true,
// ...
},
});
const jsonLd = {
"@type": "LocalBusiness",
...(listing.reviewCount > 0 && {
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": listing.averageRating,
"reviewCount": listing.reviewCount,
},
}),
};
The guard listing.reviewCount > 0 prevents an empty aggregateRating block, which is separately flagged as invalid by Google's structured data validator.
ID: directory-listing-schema.structured-data.rating-accuracy
Severity: high
What to look for: Count all listings with ratings. For each, find the aggregateRating object in JSON-LD. Compare its ratingValue and reviewCount against the ratings/review counts displayed on the page. Verify they match.
Pass criteria: The JSON-LD aggregateRating values match the displayed rating and review count on the page — 100% of displayed ratings must match the computed average of individual reviews, with no more than 0.1 point deviation. Report: "X rated listings found, all Y display accurate aggregate ratings."
Fail criteria: The JSON-LD shows one rating/count while the page displays different values, or aggregateRating is present but empty.
Skip (N/A) when: The listing has no ratings or reviews.
Detail on fail: Quote the actual rating values showing the discrepancy. Example: "JSON-LD shows 4.5 rating and 120 reviews, but page displays 4.3 stars and 95 reviews" or "aggregateRating block present but empty"
Remediation: Populate aggregateRating from the same source as the displayed ratings:
const jsonLd = {
"@type": "LocalBusiness",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": listing.averageRating,
"reviewCount": listing.reviewCount
}
}