Product Schema 评论数与页面可见评论对不上

JSON-LD 声明 1,247 条评论、4.8 星,页面上只有 32 条。Google 判定为评论不一致,SERP 里的星级片段直接消失。修法:让 reviewCount 等于可见评论数,且取自同一份来源。

一句话先看: Google 要求你放进 aggregateRating 的评分必须在同一个页面上可见,而且数字要对得上。如果 JSON-LD 写 reviewCount: 1247,页面上却只有 32 条,Google 就会记一个评论问题、撤掉你的星级片段。最快的修法:让 reviewCountratingValue 取自渲染可见评论的那同一份来源,把 bestRating / worstRating 设成跟可见量纲一致,在 Rich Results Test 里重测,然后请求重新索引。星级片段通常 2-4 周内回归(截至 2026 年 6 月)。

你的商品页之前在 SERP 上一直挂着五星片段。上周片段消失了,页面看起来什么都没改。Search Console 在受影响 URL 上安静地报了个问题,落在 Merchant listings(带 offers 的页面)或 Product snippets(纯评论页)里 —— 这是 Google 把商品数据拆成的两份增强报告。view-source 一看就明白:aggregateRating 声明 1,247 条评论、4.8 星,而页面”评论”区只有数据库里的 32 条。

Google 在这里规则很硬,文档里写得也很直白:“Don’t aggregate reviews or ratings from other websites”(不要汇总来自其他网站的评论或评分),而且你标记的汇总评分必须在同一个页面上对用户可见。跨站评论数、还没渲染出来的第三方插件、“全球”汇总,全都违反这条规则。星级片段是被静默压制的;很少有硬报错,只是富结果不再出现而已。

你属于哪一类?

先做一个检查:打开页面,用 View Source 看原始 HTML(不是 DevTools 里渲染后的 Elements 面板),找到 reviewCount,再跟页面完全渲染后的可见评论数对比。差距落在哪一行,就去看对应的原因。

你观察到的现象最可能的原因
许多互不相关的商品 reviewCount 是同一个数全站汇总被声明在每个页面上(原因 1)
关掉 JavaScript 后可见评论消失,JSON-LD 数字仍很高插件渲染评论、服务端渲染 schema(原因 2)
数字里含 Amazon / Google Shopping / 合作伙伴的评论站外评论被算进汇总(原因 3)
reviewCount 跟昨天一样,可见数已经降了schema 缓存过期(原因 4)
每个尺寸 / 颜色规格共用一个数母商品评分被声明在每个规格上(原因 5)
可见是 “4.8 / 5”,但 bestRating 写成 "10"评分量纲写错(原因 6)

常见原因

按真实团队踩坑频率排序。

1. 全站汇总的评分被声明在单页上

你的平台把全部门店、市场、地区的评分汇成一个全球数字,模板再把这个全球数字声明在每一个商品页上 —— 而每个页面其实只显示自己那部分评论。

怎么判断:几十个互不相关的商品页 reviewCount 都是同一个数。可见评论只是这个数的一小部分。

2. 评论靠第三方插件展示,JSON-LD 来自另一份数据

可见评论由 Yotpo / Trustpilot / Bazaarvoice 之类的插件加载。页面上的 JSON-LD 是服务端从你自己的数据库生成的。两边永远对不上。

怎么判断:禁掉 JavaScript 刷新一次。可见评论数掉到 0,但 JSON-LD 还在报几百条 —— 说明插件是可见评论的唯一来源。

3. 站外评论被算进了 aggregateRating

Amazon、Google Shopping、合作伙伴站点的评论被合并进了汇总。它们不在 Google 抓取的这个页面上,所以 Google 拒绝这个评分。这违反 Google 明文写出的规则:“Don’t aggregate reviews or ratings from other websites”

怎么判断:评论系统有”包含外部来源”开关并且开着。关掉,重算,跟 JSON-LD 输出比对。

4. 缓存过期:可见评论已更新,JSON-LD 还是旧的

评论被审核删除,可见数下降。JSON-LD 生成器把 reviewCount 缓存了 24 小时,依然报删除前的数字。

怎么判断reviewCount 跟昨天一模一样。可见数已经降了。缓存 TTL 刚好对得上时间差。

5. 多规格商品,每个 SKU 都声明同一个汇总评分

母商品有 6 个尺寸 / 颜色规格。每个规格页都声明母商品的汇总评分(1,247 条),但页面上只显示自己那一份(比如 18 条)。

怎么判断:所有规格 reviewCount 都一样。可见数每个规格不同。

6. bestRating / worstRating 把量纲写错了

JSON-LD 写的是 10 分制("bestRating": "10"),可见评论却是 5 分制。Google 把 4.8 解读成 4.8/10,星级片段直接掉到很低。

怎么判断:可见 UI 写 “4.8 / 5”,JSON-LD 却是 "bestRating": "10"。注意 Google 的默认值:省略 bestRating 时它默认按 5 算,省略 worstRating 时默认按 1 算。所以这个 bug 只会在你显式写错量纲时出现 —— 5 分制拿不准时,干脆两个都省略,让默认值生效。

不是原因:“self-serving reviews” 限制对 Product 不适用

一个常见的误判方向:“self-serving reviews”(自我评价:实体在自己站点上给自己打分)这条限制只会让 LocalBusinessOrganization schema 失去星级片段资格。它适用于 Product —— 你自己托管的第一方商品评论是有资格的,前提是评论在页面上可见、数字对得上。如果是商品页上的星级片段消失了,原因是数字不一致,不是 self-serving 那条规则。

开始前

  • 改动之前先截一张 SERP 富结果的基线截图。修完之后用来对比。
  • 打开 Search Console,左侧导航里 Merchant listingsProduct snippets 两份都看(Google 把商品报告拆成了这两份;带 offers 的页面落在 Merchant listings)。看清这个 URL 是被标成 error / invalid item 还是 warning —— warning 状态下片段还会出,error 通常就不出了。
  • 列出页面上所有可能产出评论数据的组件:服务端 JSON-LD、第三方插件、microdata、RDFa。
  • 确定真相来源 —— 通常跟可见插件用同一份。

需要收集的信息

  • 原始 HTML 里的 reviewCount(或 ratingCount)、ratingValuebestRatingworstRating 具体值。
  • JavaScript 完全渲染之后页面上的可见评论数。
  • 可见评论的来源系统(Yotpo、Trustpilot、自研数据库等)。
  • 多规格页面是共用一段 schema 还是每个规格一段。
  • Search Console 上问题名称原文的截图(留作邮件 / 上报的凭证)。

一步步修

按性价比排序。

第 1 步:用直接对比确认存在不一致

curl -s https://example.com/products/widget | \
  grep -oE '"(reviewCount|ratingCount)":\s*"?[0-9]+"?' | head -2

curl 拿到的是服务端原始 HTML —— Googlebot 在跑 JavaScript 之前抓到的就是这些字节。把这个数和页面在浏览器里完全渲染之后能看到的数对比。差距超过四舍五入,就是这个 bug。(不要用 DevTools 的 Elements 面板去看 schema 里的值;它显示的是跑完 JavaScript 的 DOM,会把服务端 / 插件之间的分歧藏起来。)

想看 Google 自己抽出来的是什么,把 URL 粘进 Rich Results Test,读它解析回来的 reviewCount

第 2 步:确定唯一真相来源

下决定:你是想让 JSON-LD 镜像用户在页面上看到的内容,还是想露出你的全球汇总?Google 要求前者。挑驱动可见插件的那个来源,让 JSON-LD 走同一个调用。

第 3 步:把跨源汇总从 schema 里去掉

// before — 把所有平台都汇进来
const reviewCount = totalReviewsAcrossPlatforms(productId);

// after — 只算这一页上真的渲染出来的评论
const reviewCount = visibleReviewsOnPage(productId, locale, variant);

可见插件显示 32 条,reviewCount 就必须是 32。

第 4 步:让规格页各自归位

规格页把 schema 限定到这个规格:

{
  "@type": "Product",
  "name": "Widget — Red, Large",
  "sku": "WID-RED-L",
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.7",
    "reviewCount": "18",
    "bestRating": "5",
    "worstRating": "1"
  }
}

每个规格 URL 只挂自己的汇总。如果某个规格一条评论都没有,整段 aggregateRating 去掉,不要 fallback 到母商品。

第 5 步:把评分量纲锁死

bestRatingworstRating 设成跟可见 UI 一致,或者在标准 5 分制下两个都省略(Google 在它们缺失时默认 bestRating: 5worstRating: 1)。危险的是写了错误的量纲,而不是不写:

"aggregateRating": {
  "@type": "AggregateRating",
  "ratingValue": "4.8",
  "reviewCount": "32",
  "bestRating": "5",
  "worstRating": "1"
}

如果统计的是没有文字的纯星级评分,就用 ratingCount 代替 reviewCount,或者两个一起用;Google 要求两者至少有一个。别在只有 8 条带评论文本、其余都是裸星级的情况下报 32 条 reviewCount:这种分歧正是一致性检查会盯的点。

第 6 步:评论变化时让缓存失效

把 JSON-LD 缓存 key 绑到一个内容版本号,审核或新增评论时这个版本号翻动。光靠短 TTL 不够 —— 24 小时 TTL 就意味着最多一天的过期富结果。

第 7 步:重新验证并请求再次索引

  • 在修好的 URL 上跑 Rich Results Test;确认它解析出的 reviewCount 已经等于可见数,且没有评论相关的 warning。
  • 用 URL Inspection → Test Live URL 确认修好了,再对 5-10 个核心商品 URL 走 Request Indexing
  • 盯 Search Console 的 Merchant listingsProduct snippets 增强报告;随着 Google 重抓,2-4 周内 warning 会逐步退出。

验证

  • Rich Results Test 报告 “Valid”,aggregateRating 上没有 warning。
  • 页面可见评论数与 JSON-LD 里的 reviewCount 完全一致。
  • 2-4 周内星级片段重新出现在 SERP 上(在 Search Console 跟踪展示数)。
  • 规格页各自挂自己的汇总,不再被母商品的数字带跑。

长期预防

  • 在团队范围明确写下规则:“JSON-LD 里出现的每一个数字都必须在同一个页面上可见。”
  • schema 里的评论字段要从驱动可见插件的同一个 API 拉 —— 永远不从单独的”全球”来源拉。
  • 加一个 CI 断言:抽样爬一批商品页,比较 JSON-LD 的 reviewCount 与可见数。
  • 有站外评论的站点不要把跨域评分汇成一个页面级 schema;要么单独引用,要么干脆不挂。
  • schema 生成器内建规格意识,永远不让母商品评分泄漏到子 URL 上。

常见坑

  • 把热门规格的评论”借”给长尾规格,让它看起来有口碑 —— Google 能识别重复,整个产品线都会被标。
  • ratingValue 写两位小数,但可见 UI 只显示一位(“4.85” vs “4.9”)。精度要跟可见的一模一样。
  • 评论全部被审核删掉之后还留着 aggregateRatingreviewCount 是 0 就整段拿掉。
  • 把站内”点赞 / 点踩”控件算作评论。Google 要求是真实的评论文本。
  • 写虚构的 bestRating / worstRating,例如 10 或 100,而可见量纲是 5。Google 会重新解释评分,显示一个很低的分。

FAQ

Q:我能把全球评论数放在别的地方展示吗,比如”全店超 1,200 条评论”?

可以 —— 作为页面正文的散文写出来就行,不要进 aggregateRating。Schema 必须镜像同一个页面上的内容。文案里吹总数,schema 保持诚实。

Q:修完之后星级片段多久回归?

通常 2-4 周。Google 在抓取时重新评估结构化数据;高流量商品 URL 重抓最快。在收入最高的页面上申请索引可以加速。

Q:我们每个页面只有寥寥几条评论。还要不要挂 aggregateRating

技术上 aggregateRating 只要求数量非零,哪怕一条也算合格。但只有两三条评分撑起来的片段很难有说服力,看着也单薄;数量很小时,通常宁可先不挂 schema,让页面在没星级片段的情况下竞争,等样本更有意义了再说。永远不要为了凑一个想象出来的门槛去注水。

Q:我能不能用 iframe 内嵌 Trustpilot 的评论片段?

不行。评论必须在同一页面上、用可抓取的 HTML。iframe 里的内容不属于父页面,所以 Google 不会把它算进这个页面的评论标记。要么把评论文本服务端渲染进页面,要么不要在 schema 里声明这些评论。

Q:数字对上了,片段却还没回来,怎么办?

先确认页面确实被重抓了:在 URL Inspection 里看这个 URL 的 last-crawl 日期。如果它在你修复之后被抓过、Rich Results Test 也干净,那片段就是有资格但不保证一定出 —— 是否展示评论片段由 Google 决定。再确认页面有必需的 Product name,以及 offersreview 块,因为残缺的 Product 即便评分本身有效,也可能把整个富结果压掉。

外部参考:

标签: #SEO #排查 #结构化数据 #product-schema #aggregaterating