For AI agents: a documentation index is available at /llms.txt. Markdown versions of these pages are available by appending `.md` to the URL or by sending `Accept: text/markdown`.

你必须写对的 OG / Twitter meta 标签

  • open-graph
  • meta-tags
  • twitter-cards

DevTools 里 og:title、og:image 一个不缺,分享出去却还是裸链接——问题到底出在哪一行?

多数时候不是没听过协议,而是细节错了:图片写的是相对路径、og: 标签写成了 name=、主题和插件各输出一份互相打架的 title,或者干脆没有 twitter:card。

本文是最小正确集:一段可粘贴的 HTML、逐字段说明与反例、与 <title> / meta description / JSON-LD 的回退关系、框架侧点到为止,以及用稳定 规则 id 做的自检清单。看完你能回答开头那个问题,并且有一个固定的核对顺序。

更完整的工作流(预览 vs 官方 rescrape vs CI)见 Open Graph 到底在解决什么;空白卡片见 为什么你的 Open Graph 卡片一片空白。

复制即用的最小片段

ogp.me 协议要求的四件套:og:title、og:type、og:url、og:image。上线实务几乎总要补 og:description、og:site_name,再加 twitter:card,好让 X 与部分客户端选对布局。

<head>
  <title>发版说明 · Acme</title>
  <meta
    name="description"
    content="本周修了什么,以及对你意味着什么。"
  />
  <link rel="canonical" href="https://example.com/blog/ship-notes" />

  <!-- Open Graph(用 property=,不要用 name=) -->
  <meta property="og:title" content="发版说明:本周修了什么" />
  <meta property="og:type" content="article" />
  <meta property="og:url" content="https://example.com/blog/ship-notes" />
  <meta
    property="og:image"
    content="https://example.com/og/ship-notes-1200x630.jpg"
  />
  <meta
    property="og:description"
    content="本周修了什么,以及分享链接时同事会看到什么。"
  />
  <meta property="og:site_name" content="Acme" />

  <!-- Twitter / X -->
  <meta name="twitter:card" content="summary_large_image" />
  <!-- 若不需要单独覆盖 OG 回退,可省略:
  <meta name="twitter:title" content="..." />
  <meta name="twitter:description" content="..." />
  <meta name="twitter:image" content="https://example.com/og/ship-notes-1200x630.jpg" />
  -->
</head>

这段里的硬约束:

  • 图片与 URL 必须是绝对 HTTPS(协议 + 主机 + 路径)。
  • og:url 有意与 rel=canonical 一致。
  • Open Graph 用 property="og:...";Twitter Card 惯例用 name="twitter:..."。
  • 每个 key 只保留一个权威值。不要让主题、插件、框架各写一份不同的 og:title。

逐字段说明(与反例)

og:title — og-title-missing

卡片标题。优先写「信息流里人愿意点」的句子,而不是堆关键词的 SEO 串。

反例 后果
缺失 / 空 回退到 <title> 或裸 URL
永远照抄 <title> 标签页与信息流职责不同——有时可以共用;默认照抄等于放弃写分享向标题(og-title-matches-title,info)
<!-- 弱:CMS slug 当标题 -->
<meta property="og:title" content="ship-notes-q3-final-v2" />

<!-- 更好:人话标题 -->
<meta property="og:title" content="发版说明:本周修了什么" />

og:type — og-type-missing

告诉爬虫这是什么对象。落地页:website;博客:article;商品页在真正是商品时用 product。

反例 后果
缺失 部分富对象处理降级
自造值("landing"、"page") 当未知类型处理,没有收益
<meta property="og:type" content="website" />
<!-- 或 -->
<meta property="og:type" content="article" />

og:url — og-url-missing

分享的规范身份。点赞、展开会按它聚合 http/https、尾斜杠、追踪参数等变体。

反例 规则 / 影响
缺失 互动散落在多种 URL 上
相对路径(/blog/post) og-url-relative
站点已是 HTTPS 仍写 http:// og-url-not-https
与 rel=canonical 不一致 og-url-canonical-mismatch
<!-- 错误 -->
<meta property="og:url" content="/blog/ship-notes" />

<!-- 正确 -->
<meta property="og:url" content="https://example.com/blog/ship-notes" />

og:image — og-image-missing

没有可用图时,不少平台只剩文字行,甚至几乎没有卡片样式。尽量用专用分享图(约 1200×630,约 1.91:1),不要拿 logo 凑数。

反例 规则 / 影响
缺失 / 空 空白或几乎无视觉权重
相对路径 og-image-relative-url——经常被直接丢掉
非 HTTPS og-image-not-https

图片工程(体积、跳转、Content-Type、裁切风险)留给系列后文。先把绝对 URL 写对。

og:description — og-description-missing

不在协议四件套里,但实务上是 warn 级必补。没有它时,客户端会回退 meta description 或抓正文——信息流文案变成抽奖。

写一两句给「正在刷时间线的人」看(大约 70–200 字符作起点;各平台截断不同)。

<!-- CMS 空占位往往比认真省略更糟 -->
<meta property="og:description" content="" />

og:site_name — og-site-name-missing

若干平台上的发布者标签。写品牌名,不要写页面标题。

<meta property="og:site_name" content="Acme" />

twitter:card — twitter-card-missing / twitter-card-invalid

X 仍靠 twitter:card 选布局。合法值:summary、summary_large_image、app、player。未知值等同缺失。

营销页与博客多半用 summary_large_image。

<meta name="twitter:card" content="summary_large_image" />

回退现实: 很多客户端在缺少对应 twitter:* 时会用 og:title / og:description / og:image。这很省事——但不能因此省略 twitter:card。卡片类型并不能完全由 OG 推断出来。

若只想在 X 上用不同图或标题,再单独写 twitter:title、twitter:description、twitter:image。否则让 OG 承载文案,仍声明 card 类型。

属性名与重复值陷阱

两类 bug 每周都在上线:

  1. name vs property —— OG 必须用 property="og:..."。写成 name="og:title" 是常见粘贴错误;主流解析器会直接忽略(meta-attribute-wrong)。
  2. 冲突的重复 —— 主题 + 插件 + 应用各输出一份不同的 og:title;爬虫取 first 还是 last 不可预期(meta-tag-conflicting-duplicates)。
<!-- 错:属性名不对 -->
<meta name="og:title" content="View Source 里看起来对,实际无效" />

<!-- 错:两个赢家 -->
<meta property="og:title" content="来自 CMS" />
<meta property="og:title" content="来自主题默认值" />

与 title / description / JSON-LD 的关系(回退链)

把它想成回退链,而不是单一真相源:

卡片字段 优先 常见回退
标题 og:title <title>,再是 URL
正文 og:description meta name="description",再是抓取正文
图 og:image 经常没有——别赌平台会找 logo
X 布局 twitter:card 无合法类型则降级 / 跳过
X 标题 / 图 twitter:title / twitter:image 有 OG 时通常回退到 og:*

JSON-LD(Article、Product 等)服务搜索与富结果,不能可靠替代 Open Graph 的分享卡片。若某平台 unfurl 根本不读你的 JSON-LD,schema 写得再漂亮,Slack 仍可能没图。

实务分工:

  • <title> + meta description → 标签页与搜索摘要
  • og:*(+ twitter:card)→ 分享表面
  • JSON-LD → 读它的引擎的结构化数据

事实对齐(产品名、日期、URL),但不要假设一层会填满另外两层。

框架侧(点到为止)

Next.js Metadata

Next 的 metadata / generateMetadata 在同时填 openGraph 与 twitter 时映射清晰:

import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "发版说明 · Acme",
  description: "本周修了什么,以及对你意味着什么。",
  alternates: { canonical: "https://example.com/blog/ship-notes" },
  openGraph: {
    title: "发版说明:本周修了什么",
    description: "本周修了什么,以及分享链接时同事会看到什么。",
    url: "https://example.com/blog/ship-notes",
    siteName: "Acme",
    type: "article",
    images: [
      {
        url: "https://example.com/og/ship-notes-1200x630.jpg",
        width: 1200,
        height: 630,
      },
    ],
  },
  twitter: {
    card: "summary_large_image",
    // 省略 title / description / images 时通常回退到 openGraph
  },
};

注意图片绝对 URL(或配置好的 metadataBase),并在 layout 合并后检查渲染出的 HTML里每个 property 仍只有一个值。

CMS 字段映射

编辑常填的字段 应输出为
SEO 标题 / 浏览器标题 <title>
SEO 描述 meta name="description"
分享标题 / 社交标题 og:title(可选再写 twitter:title)
分享描述 og:description
分享图 / 社交图 绝对 URL 的 og:image
站点 / 品牌名(全局) og:site_name
规范 URL rel=canonical 与 og:url

若 CMS 只有「SEO 标题」没有分享标题,标签页与信息流会完全一样。可作默认,但不是每篇发布文的最优解。

用规则 id 自检

对爬虫会看到的原始 HTML逐项核对(或放进 CI):

检查 规则
有 og:title og-title-missing
有 og:type og-type-missing
有绝对 HTTPS 的 og:url og-url-missing、og-url-relative、og-url-not-https
og:url ≡ canonical og-url-canonical-mismatch
有绝对 HTTPS 的 og:image og-image-missing、og-image-relative-url、og-image-not-https
有 og:description og-description-missing
有 og:site_name og-site-name-missing
有合法的 twitter:card twitter-card-missing、twitter-card-invalid
OG 用 property= 而非 name= meta-attribute-wrong
无冲突重复 meta-tag-conflicting-duplicates

完整目录:规则索引。各平台裁切与截断:平台档案。

上线前清单

  • 协议四件套 + description + site_name + twitter:card 出现在原始 HTML
  • og:url 与 og:image 为绝对 HTTPS;图片 200 可抓、无登录墙
  • og:url 与 rel=canonical 一致
  • 每个 og:* / twitter:* 只有一个权威值
  • OG 用 property=;Twitter card 用 name=
  • description 是刻意写的文案,不是空字段

用公网 URL 扫一次

开头的那个问题——标签齐全为什么还是裸链接——用工具验证一遍最快。把线上页面贴进首页扫描。报告会按上面同一套规则 id 拆开——缺必填、相对路径图、错误属性、非法 Twitter card——而不是一张「看起来还行」的模拟卡。

第三方预览仍是近似。权威的抓取与缓存行为仍在各平台官方 debugger。先写对标签,再预览;若第一次抓取缓存了坏卡,再 rescrape。

OGKit
你必须写对的 OG / Twitter meta 标签 · OGKit