Product标记全绿,购物代理却下不了单
导语:Product + Offer 的 JSON-LD 通过 Rich Results Test 只证明"代理能读懂这件商品",不证明"代理能买";卡住的是快照式结构化数据撑不起实时交易,差别在有没有可调用的端点。
背景:绿勾通过之后,链路还是断的
商品页的常规做法是:用生成器跑一份 Product JSON-LD,粘进模板,name、image、description、sku、brand、offers(含 price、availability)都齐,Rich Results Test 全绿,收工。
这套流程在"搜索富结果"时代是完整的,但购物代理(agentic commerce)要的不是页面描述,而是三个实时答案:这一刻这个 SKU 还有没有货、发到我的地址含税运费多少、能不能不经人确认直接下单。结构化数据里没有任何字段能回答这三个问题——因为它是爬虫回访时刷新的页面内快照,不是可查询的接口。
最典型的一段"完全合法但不可交易"的标记:
{
"@type": "Offer",
"price": "49.00",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock"
}字段没错,验证器也不会报错。问题在于 InStock 是页面渲染并缓存那一刻为真,代理在结算前需要的是提交时刻的库存,不是抓取时刻的库存。静态文档答不了实时问题。
落地清单
1. 选用的 @type 与字段(按 Schema.org 30.1)
- @type:
Product+Offer,子结构补OfferShippingDetails、ShippingDeliveryTime、MerchantReturnPolicy、Brand。 - 必填/核心字段:
name、image、description、sku(或gtin13)、brand、offers;Offer 侧price、priceCurrency、availability、url、priceValidUntil、itemCondition。 - 推荐字段:
shippingDetails、hasMerchantReturnPolicy——这两块直接影响代理能不能算出"到手价",缺了它,代理只能拿商品价做比较,跨店比价就会失真。 - 版本:Schema.org 30.1(2026-09-16 发布),查询于 2026-11-04。30.1 里与电商强相关的新增包括:
Product上的consumerNotice、isOftenBoughtWith、specification;Offer上的itemPopularity;ShippingRateSettings上的minimumOrderValue;枚举PriceTypeEnumeration新增MaximumRetailPrice;以及DigitalProductPassport类与hasDigitalProductPassport(可用于Product/Offer)。这些字段的可用范围请以官网对应属性页为准再上生产——新字段先小流量试,别一次铺全站。
2. 完整 JSON-LD 片段(可复制,脱敏)
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "XX 无线降噪耳机",
"image": ["https://example.com/img/xx-1.jpg", "https://example.com/img/xx-2.jpg"],
"description": "主动降噪,单次续航 8 小时,支持双设备连接。",
"sku": "XX-BLK-M",
"gtin13": "6900000000001",
"brand": { "@type": "Brand", "name": "XX" },
"offers": {
"@type": "Offer",
"url": "https://example.com/p/xx",
"price": "499.00",
"priceCurrency": "CNY",
"priceValidUntil": "2026-12-31",
"itemCondition": "https://schema.org/NewCondition",
"availability": "https://schema.org/InStock",
"shippingDetails": {
"@type": "OfferShippingDetails",
"shippingRate": { "@type": "MonetaryAmount", "value": "0", "currency": "CNY" },
"shippingDestination": { "@type": "DefinedRegion", "addressCountry": "CN" },
"deliveryTime": {
"@type": "ShippingDeliveryTime",
"handlingTime": { "@type": "QuantitativeValue", "minValue": 0, "maxValue": 1, "unitCode": "DAY" },
"transitTime": { "@type": "QuantitativeValue", "minValue": 1, "maxValue": 3, "unitCode": "DAY" }
}
},
"hasMerchantReturnPolicy": {
"@type": "MerchantReturnPolicy",
"applicableCountry": "CN",
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
"merchantReturnDays": 7,
"returnMethod": "https://schema.org/ReturnByMail",
"returnFees": "https://schema.org/FreeReturn"
}
}
}
</script>注意这里没有 aggregateRating。评分字段是结构化数据里造假成本最低、被判定为操纵也最狠的一类,没有真实评价体系就别填(见文末红线)。
3. 插在哪个模板节点、SSR 还是静态注入
- 位置:商品详情模板的
<head>内,或</body>前的静态片段;一份页面只输出一个Product主实体,Offer作为子节点嵌套,不要平铺成两个并列的@type。 - 必须服务端输出:GPTBot、ClaudeBot、PerplexityBot 默认不执行 JavaScript,客户端水合后才注入的 JSON-LD 对它们等于不存在。Next.js 用
metadata/ 服务端组件直接渲染,Nuxt 用useHead在 SSR 阶段输出;如果只能在客户端插,等于自费武功。 - 多变体商品:
ProductGroup+hasVariant的结构可以表达变体,但代理侧真正需要的是"能被放进购物车并解析的稳定标识",这部分结构化数据给不了,得靠商品目录接口。
4. 验证:先验标记,再验入口
# 1) 标记合法性:提交 URL 到 Google Rich Results Test / validator.schema.org
# 期望:Product 无错误、无警告(shippingDetails、returnPolicy 有值)
# 2) 交易入口是否存在(UCP 示例)
curl -sS -o /dev/null -w "%{http_code}\n" https://example.com/.well-known/ucp
# 3) 若入口存在,看它声明了哪些能力
curl -sS https://example.com/.well-known/ucp | jq '.services, .capabilities'
# 4) 核对两层价格是否一致(JSON-LD vs 目录端点)
curl -sS "https://example.com/api/catalog/xx-blk-m" | jq '.price, .currency, .availability'第 2 步返回 404,说明后面所有优化都白做——代理连门都没有。第 4 步是很多站点翻车的地方:JSON-LD 里写 499,目录端点返回 479,代理按哪个报价都会出错,最后只会把你从候选里剔除。
结果:四个断点,和一条别抱错期待的数据
能通过验证器的部分:Product 标记在 Rich Results Test 中为绿;shippingDetails + hasMerchantReturnPolicy 补齐后,"到手价"可被计算,商品在比较列表里不再因信息缺失被直接跳过。
代理侧仍然断在四个点(UCPtools 的复盘归纳):
| 断点 | 结构化数据为什么接不住 |
|---|---|
| 实时库存 | availability 是抓取时刻的布尔快照,不是提交时刻的库存 |
| 变体身份 | Schema.org 能表达变体,但没有字段把标识符绑定到购物车操作 |
| 履约协商 | 运费是"商品 × 目的地 × 方式 × 同单其他商品"的函数,shippingDetails 答不了"这个购物车能否拆两个地址" |
| 结算闭环 | 富结果把人送到店铺落地页;代理没有"人"可以接手,交易不能程序化完成,前面全是装饰 |
平台差异(同一复盘给出的观察):BigCommerce 与 WooCommerce 默认就会输出质量尚可的 Product 标记,但默认不带 UCP profile——标记越好,这个缺口越隐形;Shopify 因为参与共建 UCP,交易层支持更可能由平台直接给到;自建/headless 的情况正好相反,端点通常不难,难的是没人记得发那份发现文档。
别把结构化数据当引用开关:2026 年 5 月 Ahrefs 公布过一组对照实验,1,885 个新增 JSON-LD 的页面对比约 4,000 个对照页面,追踪期内 Google AI Overviews 引用变化约 -4.6%、AI Mode +2.4%、ChatGPT +2.2%,后两者与零没有统计显著差异。口径:第三方工具方自述数据、非本站复现,样本与平台口径以其原文为准。它和本文结论一致——结构化数据解决"被正确理解",不解决"被优先引用",更不解决"能成交"。
本站未做量化:没有可公开的前后对照数据(流量、成交、代理调用量),因此这里只给定性结论,不编数字。
复盘
三条配置动作
- 先补
shippingDetails+hasMerchantReturnPolicy,再加任何"高级字段"。这两个块决定代理能不能算出到手价,是比aggregateRating更实用的 ROI 项。 - JSON-LD 必须服务端渲染输出,并在模板层做"价格/库存唯一来源"校验:商品价、
Offer.price、目录端点三者任一不一致就拦发布。 - 把
/.well-known/ucp的存在性做成上线检查项(一行curl -o /dev/null -w "%{http_code}"),和站点地图、robots 放在同一张 checklist 上。
两条红线
- 别填没有的
aggregateRating/review。虚假评分是结构化数据里执法最明确的违规类型,代价远大于收益;没有评价体系就空着。 - 别把 30.1 的新字段当装饰批量铺。
itemPopularity、consumerNotice、DigitalProductPassport这类字段语义强、约束细,字段名或取值范围写错,比不写更糟——新字段先在单个品类试点,验证器过、目录端点对得上,再扩。
标注
- Schema.org 版本:30.1,发布日期 2026-09-16;字段核对查询于 2026-11-04(依据 schema.org Releases 页 30.1 条目)。
- 验证工具与时间:Google Rich Results Test、Schema.org Validator、UCP 校验器(检查 profile / 能力声明 / 端点);文中命令为 2026-11-04 编写,未对示例域名执行。
- 来源:UCPtools「Your Product Schema Is Valid. An AI Shopping Agent Still Cannot Buy From You.」;Schema.org 30.1 Release Notes;Ahrefs 2026-05 的 1,885 页 JSON-LD 对照实验(第三方转述,非复现)。
- 数据口径:文中无本站量化数据;第三方数据均标注来源与"非第三方复现"。
标签:Schema.org、结构化数据、JSON-LD、AI可见度、GEO、电商