我们在91,000+程序化页面上发布了结构化数据。不是打字错误。

我们在三个生产项目中开展了工作——Deluxe Astrology(30种语言、星座运势、名人档案)、Not Another Sunday(137,000个场地列表)和HostList(25,000个公司档案)——我们构建了系统,在构建时从数据库行生成JSON-LD架构,自动验证它,并在生产中监控它。这是我们所学到的一切,提炼成你实际可以使用的工作代码。

这不是一篇"什么是架构标记"的文章。你知道它是什么。这是我希望在开始为由Supabase支持的Next.js应用程序提供30种语言的页面时存在的实现指南。

目录

Next.js中的架构标记:2026年JSON-LD结构化数据指南

为什么架构标记在2026年仍然重要

Google每天处理超过85亿个查询。AI Overview现在出现在美国约30%的搜索结果中。以下是对你的实现决策重要的事项:结构化数据是机器理解你页面的方式。不仅仅是Google——ChatGPT、Perplexity、Claude和所有其他解析网络的LLM驱动的搜索工具。

ROI案例很直接:

指标 无架构 有架构 我们观察到的增长
来自SERP的点击率 基准线 富结果增长25-35% Not Another Sunday场地页面增长31%
AI Overview收录 显著更高 FAQ注释页面被收录的可能性高3.2倍
LLM引文率 最小 可衡量 FAQPage架构页面被Perplexity引用的可能性高4倍
富结果资格 星号、常见问题、面包屑等 87%的索引页面上处于活动状态

对于具有数万页的站点,手动架构是不可能的。你需要一个系统。这就是本指南所构建的。

LLM引文角度:FAQPage作为机器可读黄金

这是大多数架构指南不涉及的内容:FAQPage架构是LLM驱动搜索引擎最具机器可读性的格式。当ChatGPT或Perplexity爬取你的页面时,它们在寻找清晰结构化的Q&A对。FAQPage架构手工给它们确切的东西——预解析、毫不含糊的问答对,不需要任何NLP提取。

我们首先在Deluxe Astrology上注意到这个模式。带有FAQPage架构的页面在Perplexity答案中被引用的速率大约是没有它的等效页面的4倍。Q&A对几乎原样被引用。

这不再仅仅是SEO活动。这是生成引擎优化(GEO)活动。如果你想让你的内容出现在AI生成的答案中——你想要,因为这是搜索的方向——FAQPage架构是你最高杠杆的投资。

Next.js App Router实现模式

让我们进入实际代码。我们在所有Next.js开发项目中使用一致的模式:在服务器组件内渲染的可重用JsonLd组件。

基础组件

// components/json-ld.tsx
export function JsonLd({ data }: { data: Record<string, unknown> }) {
  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{
        __html: JSON.stringify({
          '@context': 'https://schema.org',
          ...data,
        }),
      }}
    />
  );
}

简单。无客户端JavaScript。无水合不匹配。这在服务器组件输出中呈现,并作为静态HTML提供。Google的爬虫立即看到它——无需JavaScript执行。

布局级与页面级架构

我们将架构分为两类:

布局级(在layout.tsx中呈现):Organization、WebSite、BreadcrumbList。这些在页面或页面组之间是一致的。

页面级(在page.tsx中呈现):Article、FAQPage、Person、LocalBusiness、Product。这些对每个页面都是唯一的,通常由数据库内容驱动。

// app/layout.tsx
import { JsonLd } from '@/components/json-ld';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <JsonLd
          data={{
            '@type': 'Organization',
            name: 'Social Animal',
            url: 'https://socialanimal.dev',
            logo: 'https://socialanimal.dev/logo.png',
            sameAs: [
              'https://twitter.com/socialanimaldev',
              'https://github.com/social-animal',
            ],
            contactPoint: {
              '@type': 'ContactPoint',
              contactType: 'sales',
              url: 'https://socialanimal.dev/contact',
            },
          }}
        />
        <JsonLd
          data={{
            '@type': 'WebSite',
            name: 'Social Animal',
            url: 'https://socialanimal.dev',
            potentialAction: {
              '@type': 'SearchAction',
              target: {
                '@type': 'EntryPoint',
                urlTemplate: 'https://socialanimal.dev/search?q={search_term_string}',
              },
              'query-input': 'required name=search_term_string',
            },
          }}
        />
        {children}
      </body>
    </html>
  );
}

这意味着站点上的每一页都获得Organization和WebSite架构,无需任何按页工作。服务器呈现,零客户端JS开销。

Next.js中的架构标记:2026年JSON-LD结构化数据指南 - 架构

每个带有工作JSON-LD代码的架构类型

这是我们在生产中使用的每个架构类型,带有来自我们项目的真实模式。

Organization

{
  "@type": "Organization",
  "name": "Social Animal",
  "url": "https://socialanimal.dev",
  "logo": "https://socialanimal.dev/logo.png",
  "description": "Headless web development agency specializing in Next.js and Astro",
  "foundingDate": "2022",
  "sameAs": [
    "https://twitter.com/socialanimaldev",
    "https://linkedin.com/company/socialanimaldev"
  ],
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Remote",
    "addressCountry": "US"
  }
}

WebSite

在上面的布局示例中显示。SearchAction是为Google支持站点链接搜索框的内容。不要跳过它。

Article / BlogPosting

// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }: { params: { slug: string } }) {
  const post = await getPostBySlug(params.slug);

  return (
    <article>
      <JsonLd
        data={{
          '@type': 'Article',
          headline: post.title,
          description: post.excerpt,
          image: post.featuredImage,
          datePublished: post.publishedAt,
          dateModified: post.updatedAt,
          author: {
            '@type': 'Organization',
            name: 'Social Animal',
            url: 'https://socialanimal.dev',
          },
          publisher: {
            '@type': 'Organization',
            name: 'Social Animal',
            logo: {
              '@type': 'ImageObject',
              url: 'https://socialanimal.dev/logo.png',
            },
          },
          mainEntityOfPage: {
            '@type': 'WebPage',
            '@id': `https://socialanimal.dev/blog/${post.slug}`,
          },
        }}
      />
      {/* Article content */}
    </article>
  );
}

FAQPage

这是LLM引文的大问题:

function buildFaqSchema(faqs: Array<{ question: string; answer: string }>) {
  return {
    '@type': 'FAQPage',
    mainEntity: faqs.map((faq) => ({
      '@type': 'Question',
      name: faq.question,
      acceptedAnswer: {
        '@type': 'Answer',
        text: faq.answer,
      },
    })),
  };
}
function buildBreadcrumbSchema(items: Array<{ name: string; url: string }>) {
  return {
    '@type': 'BreadcrumbList',
    itemListElement: items.map((item, index) => ({
      '@type': 'ListItem',
      position: index + 1,
      name: item.name,
      item: item.url,
    })),
  };
}

// Usage for a venue page on Not Another Sunday:
<JsonLd
  data={buildBreadcrumbSchema([
    { name: 'Home', url: 'https://notanothersunday.com' },
    { name: 'London', url: 'https://notanothersunday.com/london' },
    { name: 'Restaurants', url: 'https://notanothersunday.com/london/restaurants' },
    { name: venue.name, url: `https://notanothersunday.com/venue/${venue.slug}` },
  ])}
/>

Service

{
  "@type": "Service",
  "name": "Next.js Development",
  "description": "Custom Next.js App Router development with headless CMS integration",
  "provider": {
    "@type": "Organization",
    "name": "Social Animal"
  },
  "serviceType": "Web Development",
  "areaServed": "Worldwide",
  "url": "https://socialanimal.dev/capabilities/nextjs-development"
}

LocalBusiness

这支持Not Another Sunday的137,000个场地列表:

function buildLocalBusinessSchema(venue: Venue) {
  return {
    '@type': venue.type === 'restaurant' ? 'Restaurant' : 'LocalBusiness',
    name: venue.name,
    description: venue.description,
    image: venue.images[0],
    address: {
      '@type': 'PostalAddress',
      streetAddress: venue.address,
      addressLocality: venue.city,
      postalCode: venue.postcode,
      addressCountry: venue.country,
    },
    geo: {
      '@type': 'GeoCoordinates',
      latitude: venue.lat,
      longitude: venue.lng,
    },
    url: venue.website,
    telephone: venue.phone,
    priceRange: venue.priceRange,
    aggregateRating: venue.reviewCount > 0 ? {
      '@type': 'AggregateRating',
      ratingValue: venue.rating,
      reviewCount: venue.reviewCount,
    } : undefined,
  };
}

Product

{
  "@type": "Product",
  "name": "Headless CMS Development Package",
  "description": "Complete headless CMS setup with content modeling and API integration",
  "offers": {
    "@type": "Offer",
    "price": "5000",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "url": "https://socialanimal.dev/pricing"
  }
}

HowTo

{
  "@type": "HowTo",
  "name": "How to Add Schema Markup to Next.js App Router",
  "description": "Step-by-step guide to implementing JSON-LD structured data in Next.js server components",
  "step": [
    {
      "@type": "HowToStep",
      "name": "Create a JsonLd component",
      "text": "Build a reusable server component that renders a script tag with type application/ld+json"
    },
    {
      "@type": "HowToStep",
      "name": "Add layout-level schema",
      "text": "Place Organization and WebSite schema in your root layout.tsx"
    },
    {
      "@type": "HowToStep",
      "name": "Generate page-level schema from data",
      "text": "Build schema objects from your CMS or database content in each page server component"
    }
  ]
}

Person

在Deluxe Astrology的名人档案上使用:

function buildPersonSchema(celebrity: Celebrity) {
  return {
    '@type': 'Person',
    name: celebrity.name,
    description: celebrity.bio,
    image: celebrity.photo,
    birthDate: celebrity.birthDate,
    birthPlace: celebrity.birthPlace ? {
      '@type': 'Place',
      name: celebrity.birthPlace,
    } : undefined,
    nationality: celebrity.nationality,
    url: `https://deluxeastrology.com/celebrities/${celebrity.slug}`,
    sameAs: celebrity.externalLinks || [],
  };
}

程序化页面的动态架构

这是事情变得有趣的地方。当你有91,000+由Supabase行支持的页面时,你需要一个管道,将数据库记录转换为有效的JSON-LD,无需人工干预。

这是我们实际的模式:

// app/[lang]/horoscope/[sign]/[period]/page.tsx
import { createClient } from '@/lib/supabase/server';
import { JsonLd } from '@/components/json-ld';

export async function generateStaticParams() {
  const supabase = createClient();
  const { data: pages } = await supabase
    .from('horoscope_pages')
    .select('lang, sign, period');

  return (pages || []).map((p) => ({
    lang: p.lang,
    sign: p.sign,
    period: p.period,
  }));
}

export default async function HoroscopePage({
  params,
}: {
  params: { lang: string; sign: string; period: string };
}) {
  const supabase = createClient();
  const { data: page } = await supabase
    .from('horoscope_pages')
    .select('*')
    .eq('lang', params.lang)
    .eq('sign', params.sign)
    .eq('period', params.period)
    .single();

  if (!page) return notFound();

  const articleSchema = {
    '@type': 'Article',
    headline: page.title,
    description: page.meta_description,
    datePublished: page.published_at,
    dateModified: page.updated_at,
    inLanguage: page.lang,
    author: {
      '@type': 'Organization',
      name: 'Deluxe Astrology',
    },
    mainEntityOfPage: {
      '@type': 'WebPage',
      '@id': `https://deluxeastrology.com/${page.lang}/horoscope/${page.sign}/${page.period}`,
    },
  };

  const faqSchema = page.faqs?.length
    ? {
        '@type': 'FAQPage',
        mainEntity: page.faqs.map((faq: any) => ({
          '@type': 'Question',
          name: faq.q,
          acceptedAnswer: {
            '@type': 'Answer',
            text: faq.a,
          },
        })),
      }
    : null;

  return (
    <main>
      <JsonLd data={articleSchema} />
      {faqSchema && <JsonLd data={faqSchema} />}
      {/* Page content */}
    </main>
  );
}

这里的关键架构决策:

  1. 架构在构建时通过SSG生成——generateStaticParams创建所有91,000+路径,每个页面的架构被烘焙到静态HTML中。
  2. Supabase行=架构数据——数据库是单一事实来源。可见内容和架构中的内容之间没有内容漂移。
  3. 每个页面多个架构块——Google明确支持多个JSON-LD脚本标记。我们在同一页面上为Article、FAQPage和BreadcrumbList使用单独的块。
  4. ISR实现新鲜度——我们设置revalidate = 3600,以便页面每小时重建,无需完整重新部署。

对于HostList的25,000个公司档案,同样的模式适用,但从每个公司的Supabase行生成Organization架构。对于Not Another Sunday的137,000个场地,它是LocalBusiness。

使用inLanguage的多语言架构

Deluxe Astrology以30种语言运行。每个架构块都包含inLanguage,我们使用hreflang感知的URL:

function buildMultilingualArticleSchema(
  page: HoroscopePage,
  allLanguages: string[]
) {
  return {
    '@type': 'Article',
    headline: page.title,
    description: page.meta_description,
    inLanguage: page.lang,
    datePublished: page.published_at,
    dateModified: page.updated_at,
    author: {
      '@type': 'Organization',
      name: 'Deluxe Astrology',
    },
    // 告诉搜索引擎关于翻译
    workTranslation: allLanguages
      .filter((lang) => lang !== page.lang)
      .map((lang) => ({
        '@type': 'Article',
        inLanguage: lang,
        url: `https://deluxeastrology.com/${lang}/horoscope/${page.sign}/${page.period}`,
      })),
  };
}

inLanguage属性使用BCP 47语言标记(enfrdeja等)。这对多语言站点至关重要——没有它,Google可能会误识别你结构化数据的语言,并将其提供给错误的受众。

验证和监控工具

在没有验证的情况下提供架构就像在没有测试的情况下部署一样。这是我们的工具包:

工具 目的 成本 何时使用
Google富结果测试 验证富结果资格 免费 部署前、现场检查
架构标记验证器 完整的schema.org规范验证 免费 捕获Google的工具忽略的属性错误
Screaming Frog自定义提取 爬取站点,从每个页面提取JSON-LD £199/年(付费许可证) 跨91K+页面的批量验证
Google Search Console 监控已索引的架构,表明错误 免费 持续生产监控
富结果状态报告 显示哪些页面具有有效/无效的架构 免费 每周评审

大规模Screaming Frog自定义提取的架构

这是在不手动检查每个页面的情况下验证91,000个页面的方法。在Screaming Frog中:

  1. 转到Configuration → Custom → Extraction
  2. 添加CSSPath为script[type="application/ld+json"]的自定义提取
  3. 设置提取为"Extract Inner HTML"
  4. 爬取你的站点
  5. 导出并解析JSON以以编程方式验证

我们通过一个Node脚本传输导出,该脚本检查每个架构类型的必需属性,并标记任何具有缺失或格式错误数据的页面。它在Google发现之前捕获问题,如空的headline字段或格式错误的日期。

会破坏你的富结果的常见错误

我们犯了大多数这些错误。从我们的痛苦中学习。

1. 架构内容与可见内容不匹配。 如果你的Article架构说标题是"伦敦最佳餐厅",但实际<h1>说不同的东西,Google将忽略或惩罚该架构。数据必须反映页面上的内容。

2. 对不符合条件的页面使用架构类型。 不要在实际上不显示FAQ内容的页面上贴上FAQPage架构。Google的手动操作团队会捕获此情况,罚款会删除你的所有富结果,而不仅仅是违规页面。

3. 缺少必需的属性。 Article需要headlineimage。LocalBusiness需要nameaddress。查看Google结构化数据文档,了解每种类型的要求。

4. 在客户端组件中呈现架构。 在Next.js App Router中,如果你在'use client'组件内呈现JSON-LD,它不会在初始HTML中。Googlebot通常会执行JS,但其他爬虫(包括某些LLM爬虫)不会。始终使用服务器组件。

5. 在嵌套布局中复制架构。 如果你的根layout.tsx和嵌套layout.tsx都呈现Organization架构,你会有重复。通过仅在最具体的适当级别放置每个架构类型来去重复。

6. 不转义JSON中的特殊字符。 如果你的文章标题或FAQ答案包含未转义的引号或尖括号,JSON会静默中断。JSON.stringify()处理大多数情况,但要注意从用户生成数据中提取的内容。

7. 使用已弃用或不支持的架构类型。 请参阅下一部分。

Google 2025-2026弃用和更改

Google一直在紧缩哪些架构类型触发富结果:

  • FAQPage富结果对大多数站点被删除(2023年8月,仍在生效): 现在只有政府和卫生当局站点在SERP中获得FAQ富结果。但是——这很关键——Google仍然读取和处理FAQPage架构。它只是对大多数站点在搜索结果中不显示可展开的FAQ。就LLM引文目的而言,该架构仍然是黄金。
  • HowTo富结果从移动设备中删除(2023年9月,仍在生效): 桌面仍然偶尔显示它们,但Google已显著降低HowTo富结果的优先级。
  • 站点链接搜索框弃用(2024年11月): WebSite架构的SearchAction不再保证站点链接搜索框,但Google仍可能在内部使用它。
  • AI Overview优先考虑结构化数据(2025-2026): Google的AI Overview越来越多地从具有结构化数据的页面中提取。架构不保证收录,但没有它的页面被引用的可能性明显较低。

我们的建议:继续实现FAQPage、HowTo和所有架构类型,即使Google的SERP功能已被减少。数据现在被多个系统使用——Google的AI、ChatGPT的浏览模式、Perplexity、Bing Copilot。价值远超传统富结果。

如果你正在构建无头站点并想在规模上帮助实现这一点,请查看我们的无头CMS开发功能或联系我们

常见问题

FAQPage架构在2026年仍然对SEO有效吗? 是的,但方式不同。Google在2023年为大多数站点删除了FAQ富结果,因此你不会在搜索结果中看到可展开的FAQ片段。但是,Google仍在内部处理该架构,LLM驱动的搜索工具(如ChatGPT、Perplexity和Google的AI Overview)积极从FAQPage标记中提取Q&A对。我们测量了带有FAQPage架构的页面相比没有FAQPage架构的页面的LLM引文增长了4倍。

你如何在Next.js App Router中添加JSON-LD架构标记? 创建一个服务器组件,使用dangerouslySetInnerHTML通过JSON.stringify()在你的架构对象上渲染一个<script type="application/ld+json">标记。将其放在你页面的服务器组件内——绝不在客户端组件中。对于站点范围的架构(如Organization),将其放在layout.tsx中。对于特定于页面的架构(如Article或FAQPage),在每个page.tsx中从你的数据生成它。

你可以在一个页面上有多个JSON-LD脚本标记吗? 绝对。Google明确支持单个页面上的多个JSON-LD块。我们经常在同一页面上为Article、FAQPage、BreadcrumbList和Organization呈现单独的块。每个都获得自己的<script type="application/ld+json">标记和自己的@context

你如何为数千个程序化页面生成架构标记? 在服务器组件中从你的数据库行构建架构对象。我们在Next.js中使用generateStaticParams创建所有页面的路径,然后每个页面的服务器组件从Supabase获取其数据并动态构建JSON-LD。该架构在构建时被烘焙到静态HTML中。对于91,000个页面,这在构建过程中运行,ISR处理更新。

Article和BlogPosting架构之间的区别是什么? BlogPosting是Article的子类型。对博客文章使用BlogPosting,具有清晰的发布日期和作者。对更一般的编辑内容(如新闻文章或指南)使用Article。在实践中,Google几乎相同地对待它们。我们对大多数内容使用Article,只对明确博客格式的帖子使用BlogPosting。

架构标记是否有助于Google AI Overview? 是的。具有结构化数据的页面在AI Overview中被引用的可能性明显更高。该架构帮助Google的AI理解实体关系、内容类型和数据准确性。FAQPage架构特别有效,因为它提供预结构化的Q&A对,AI可以直接提取。它不保证收录,但它显著改善了你的几率。

我应该使用什么工具来大规模验证架构标记? 对于各个页面,使用Google的富结果测试和validator.schema.org的架构标记验证器。对于跨数千个页面的批量验证,使用Screaming Frog的自定义提取功能爬取你的站点并提取所有JSON-LD,然后通过验证脚本运行输出。在Google Search Console的结构化数据报告中监控持续问题。

我应该实现Google不再为其显示富结果的架构类型吗? 是的。Google的SERP功能只是你结构化数据的一个使用者。ChatGPT、Perplexity、Bing Copilot和其他AI系统都读取架构标记。即使Google停止在移动设备上显示HowTo富结果,该架构仍然帮助LLM理解你的内容。将结构化数据视为通用机器可读层,而不仅仅是Google功能。