Estrutura de Dados Baseada em Dados: Guia Completo de JSON-LD para 2026

Entregamos estrutura de dados em mais de 91.000 páginas programáticas. Sem exagero. Em três projetos em produção — Deluxe Astrology (30 idiomas, horóscopos, perfis de celebridades), Not Another Sunday (137.000 listagens de locais) e HostList (25.000 perfis de empresas) — construímos sistemas que geram esquema JSON-LD a partir de linhas de banco de dados em tempo de construção, validam automaticamente e monitoram em produção. Isso é tudo o que aprendemos, destilado em código funcional que você pode realmente usar.

Este não é um artigo "o que é marcação de esquema". Você já sabe o que é. Este é o guia de implementação que gostaria que existisse quando começamos a integrar dados estruturados a aplicativos Next.js com suporte a Supabase servindo páginas em 30 idiomas.

Sumário

Marcação de Esquema no Next.js: Guia de Dados Estruturados JSON-LD para 2026

Por que a Marcação de Esquema Ainda Importa em 2026

O Google processa mais de 8,5 bilhões de buscas diariamente. AI Overviews agora aparecem em aproximadamente 30% dos resultados de busca nos EUA. E aqui está o que importa para suas decisões de implementação: dados estruturados é como as máquinas entendem suas páginas. Não apenas Google — ChatGPT, Perplexity, Claude e todas as outras ferramentas de busca alimentadas por LLM que analisam a web.

O caso de ROI é direto:

Métrica Sem Esquema Com Esquema Delta Observado
CTR do SERP Linha de base +25-35% com rich results +31% em páginas de locais Not Another Sunday
Inclusão em AI Overview Baixa Significativamente maior 3,2x mais provável em páginas anotadas com FAQ
Taxa de citação de LLM Mínima Mensurável Páginas com esquema FAQPage citadas 4x mais por Perplexity
Elegibilidade para rich results Nenhuma Estrelas, FAQs, breadcrumbs, etc. Ativo em 87% das páginas indexadas

Para sites com dezenas de milhares de páginas, esquema manual é impossível. Você precisa de um sistema. É isso que este guia constrói.

O Ângulo de Citação de LLM: FAQPage como Ouro Legível por Máquina

Aqui está algo que a maioria dos guias de esquema não cobre: esquema FAQPage é o formato mais legível por máquina para mecanismos de busca alimentados por LLM. Quando ChatGPT ou Perplexity rastreiam sua página, estão procurando por pares Q&A claramente estruturados. Esquema FAQPage oferece exatamente isso — pares pergunta-resposta pré-analisados e inequívocos que não exigem nenhuma extração de PNL.

Notamos esse padrão primeiro em Deluxe Astrology. Páginas com esquema FAQPage estavam sendo citadas em respostas do Perplexity em aproximadamente 4x a taxa de páginas equivalentes sem isso. Os pares Q&A estavam sendo extraídos quase literalmente.

Isso não é apenas um jogo de SEO mais. É um jogo de Generative Engine Optimization (GEO). Se você quer que seu conteúdo apareça em respostas geradas por IA — e você quer, porque é para onde a busca está indo — esquema FAQPage é seu investimento de maior alavancagem.

Padrão de Implementação Next.js App Router

Vamos entrar em código real. Usamos um padrão consistente em todos os nossos projetos de desenvolvimento Next.js: um componente JsonLd reutilizável renderizado dentro de componentes do servidor.

O Componente Base

// 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,
        }),
      }}
    />
  );
}

Simples. Sem JavaScript do lado do cliente. Sem incompatibilidades de hidratação. Isso renderiza na saída do componente do servidor e é enviado como HTML estático. O rastreador do Google vê imediatamente — nenhuma execução de JavaScript necessária.

Esquema em Nível de Layout vs Nível de Página

Dividimos o esquema em duas categorias:

Nível de layout (renderizado em layout.tsx): Organization, WebSite, BreadcrumbList. Estes são consistentes em páginas ou grupos de páginas.

Nível de página (renderizado em page.tsx): Article, FAQPage, Person, LocalBusiness, Product. Estes são únicos por página e geralmente impulsionados pelo conteúdo do banco de dados.

// 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>
  );
}

Isso significa que toda página única no site recebe esquema Organization e WebSite sem nenhum trabalho por página. Renderizado no servidor, zero sobrecarga de cliente JS.

Marcação de Esquema no Next.js: Guia de Dados Estruturados JSON-LD para 2026 - arquitetura

Todos os Tipos de Esquema Com Código JSON-LD Funcional

Aqui estão todos os tipos de esquema que usamos em produção, com padrões reais de nossos projetos.

Organization

{
  "@type": "Organization",
  "name": "Social Animal",
  "url": "https://socialanimal.dev",
  "logo": "https://socialanimal.dev/logo.png",
  "description": "Agência de desenvolvimento web headless especializada em Next.js e Astro",
  "foundingDate": "2022",
  "sameAs": [
    "https://twitter.com/socialanimaldev",
    "https://linkedin.com/company/socialanimaldev"
  ],
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Remote",
    "addressCountry": "US"
  }
}

WebSite

Mostrado acima no exemplo de layout. SearchAction é o que alimenta sitelinks searchbox no Google. Não pule.

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}`,
          },
        }}
      />
      {/* Conteúdo do artigo */}
    </article>
  );
}

FAQPage

Este é o grande para citações de 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,
    })),
  };
}

// Uso para uma página de local em 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": "Desenvolvimento Next.js",
  "description": "Desenvolvimento customizado com Next.js App Router com integração de CMS headless",
  "provider": {
    "@type": "Organization",
    "name": "Social Animal"
  },
  "serviceType": "Desenvolvimento Web",
  "areaServed": "Worldwide",
  "url": "https://socialanimal.dev/capabilities/nextjs-development"
}

LocalBusiness

Alimenta as 137.000 listagens de locais de Not Another Sunday:

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": "Pacote de Desenvolvimento de CMS Headless",
  "description": "Configuração completa de CMS headless com modelagem de conteúdo e integração de API",
  "offers": {
    "@type": "Offer",
    "price": "5000",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "url": "https://socialanimal.dev/pricing"
  }
}

HowTo

{
  "@type": "HowTo",
  "name": "Como Adicionar Marcação de Esquema ao Next.js App Router",
  "description": "Guia passo a passo para implementar dados estruturados JSON-LD em componentes do servidor Next.js",
  "step": [
    {
      "@type": "HowToStep",
      "name": "Crie um componente JsonLd",
      "text": "Construa um componente do servidor reutilizável que renderiza uma tag script com tipo application/ld+json"
    },
    {
      "@type": "HowToStep",
      "name": "Adicione esquema em nível de layout",
      "text": "Coloque esquema Organization e WebSite em seu layout.tsx raiz"
    },
    {
      "@type": "HowToStep",
      "name": "Gere esquema em nível de página a partir de dados",
      "text": "Construa objetos de esquema a partir de seu conteúdo de CMS ou banco de dados em cada componente de página do servidor"
    }
  ]
}

Person

Usado nos perfis de celebridades de 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 || [],
  };
}

Esquema Dinâmico para Páginas Programáticas

É aqui que fica interessante. Quando você tem mais de 91.000 páginas apoiadas por linhas de Supabase, você precisa de um pipeline que transforme registros de banco de dados em JSON-LD válido sem intervenção humana.

Aqui está nosso padrão real:

// 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} />}
      {/* Conteúdo da página */}
    </main>
  );
}

As principais decisões arquitetônicas aqui:

  1. O esquema é gerado em tempo de construção via SSGgenerateStaticParams cria todos os 91.000+ caminhos, e o esquema de cada página é incorporado no HTML estático.
  2. Linha de Supabase = dados de esquema — O banco de dados é a única fonte de verdade. Sem desvio de conteúdo entre o que é visível e o que está no esquema.
  3. Múltiplos blocos de esquema por página — O Google explicitamente suporta múltiplas tags de script JSON-LD. Usamos blocos separados para Article, FAQPage e BreadcrumbList na mesma página.
  4. ISR para frescor — Definimos revalidate = 3600 para que as páginas se reconstruam a cada hora sem redesploques completos.

Para os 25.000 perfis de empresa HostList, o mesmo padrão se aplica mas com esquema Organization gerado a partir de cada linha de Supabase da empresa. Para os 137.000 locais de Not Another Sunday, é LocalBusiness.

Esquema Multilíngue Com inLanguage

Deluxe Astrology funciona em 30 idiomas. Cada bloco de esquema inclui inLanguage, e usamos URLs cientes de hreflang:

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',
    },
    // Informe aos mecanismos de busca sobre traduções
    workTranslation: allLanguages
      .filter((lang) => lang !== page.lang)
      .map((lang) => ({
        '@type': 'Article',
        inLanguage: lang,
        url: `https://deluxeastrology.com/${lang}/horoscope/${page.sign}/${page.period}`,
      })),
  };
}

A propriedade inLanguage usa tags de idioma BCP 47 (en, fr, de, ja, etc.). Isso é crítico para sites multilíngues — sem isso, o Google pode identificar incorretamente o idioma de seus dados estruturados e servi-los ao público errado.

Ferramentas de Validação e Monitoramento

Enviar esquema sem validação é como fazer deploy sem testes. Aqui está nosso kit de ferramentas:

Ferramenta Propósito Custo Quando Usar
Teste de Rich Results do Google Valida elegibilidade para rich results Gratuita Antes do deploy, verificações pontuais
Validador de Marcação de Esquema Validação completa da especificação schema.org Gratuita Detecta erros de propriedade que a ferramenta do Google ignora
Screaming Frog Custom Extraction Rastreia site, extrai JSON-LD de cada página £199/ano (licença paga) Validação em massa em 91K+ páginas
Google Search Console Monitora esquema indexado, apresenta erros Gratuita Monitoramento contínuo em produção
Relatórios de Status de Rich Results Mostra quais páginas têm esquema válido/inválido Gratuita Revisão semanal

Screaming Frog Custom Extraction para Esquema em Escala

É assim que você valida 91.000 páginas sem verificar cada uma manualmente. No Screaming Frog:

  1. Vá para Configuration → Custom → Extraction
  2. Adicione uma extração customizada com CSSPath: script[type="application/ld+json"]
  3. Defina extração para "Extract Inner HTML"
  4. Rastreie seu site
  5. Exporte e analise o JSON para validar programaticamente

Canalizamos a exportação através de um script Node que verifica propriedades obrigatórias por tipo de esquema e sinaliza qualquer página com dados faltando ou malformados antes do Google fazer isso.

Erros Comuns Que Destruirão Seus Rich Results

Cometemos a maioria desses. Aprenda com nossa dor.

1. Conteúdo do esquema não corresponde ao conteúdo visível. Se seu esquema Article diz que o título é "Melhores Restaurantes em Londres" mas o <h1> real diz algo diferente, o Google ignorará ou penalizará o esquema. Os dados devem refletir o que está na página.

2. Usar tipos de esquema para páginas que não se qualificam. Não coloque esquema FAQPage em uma página que não exibe conteúdo de FAQ. O time de ações manuais do Google pega isso, e a penalidade remove TODOS os seus rich results, não apenas as páginas ofensoras.

3. Propriedades obrigatórias faltando. Article precisa de headline e image. LocalBusiness precisa de name e address. Verifique a documentação de dados estruturados do Google para requisitos por tipo.

4. Renderizar esquema em componentes do cliente. No Next.js App Router, se você renderizar JSON-LD dentro de um componente 'use client', não estará no HTML inicial. Googlebot geralmente executará JS, mas outros rastreadores (incluindo alguns rastreadores de LLM) não. Sempre use componentes do servidor.

5. Esquema duplicado em layouts aninhados. Se seu layout.tsx raiz e um layout.tsx aninhado ambos renderizam esquema Organization, você terá duplicatas. Deduplicar colocando cada tipo de esquema apenas no nível mais específico apropriado.

6. Não escapar caracteres especiais em JSON. Se seu título de artigo ou resposta de FAQ contém aspas ou colchetes não escapados, o JSON quebra silenciosamente. JSON.stringify() lida com a maioria dos casos, mas observe conteúdo extraído de dados gerados por usuários.

7. Usar tipos de esquema deprecados ou não suportados. Veja a próxima seção.

Depreciações e Mudanças do Google 2025-2026

O Google tem sido rigoroso em relação a quais tipos de esquema acionam rich results:

  • Rich results FAQPage removidos para a maioria dos sites (agosto de 2023, ainda em vigor): Apenas sites de autoridades governamentais e de saúde recebem rich results de FAQ no SERP agora. MAS — e isso é crucial — o Google ainda lê e processa esquema FAQPage. Apenas não mostra a FAQ expansível em resultados de busca para a maioria dos sites. Para fins de citação de LLM, o esquema ainda é ouro.
  • Rich results HowTo removidos do mobile (setembro de 2023, ainda em vigor): Desktop ainda os mostra ocasionalmente, mas o Google depriorizou significativamente rich results HowTo.
  • Depreciação de Sitelinks Searchbox (novembro de 2024): O SearchAction do esquema WebSite não garante mais uma caixa de pesquisa de sitelinks, mas o Google ainda pode usá-lo internamente.
  • AI Overviews priorizam dados estruturados (2025-2026): Os AI Overviews do Google cada vez mais extraem de páginas com dados estruturados. O esquema não garante inclusão, mas páginas sem ele são mensuravelmente menos prováveis de serem citadas.

Nossa recomendação: continue implementando FAQPage, HowTo e todos os tipos de esquema mesmo que os recursos SERP do Google tenham sido reduzidos. Os dados são consumidos por múltiplos sistemas agora — AI do Google, modo browse do ChatGPT, Perplexity, Bing Copilot. O valor se estende muito além dos rich results tradicionais.

Se você está construindo um site headless e quer ajuda para implementar isso em escala, veja nossas capacidades de desenvolvimento de CMS headless ou entre em contato.

Perguntas Frequentes

Esquema FAQPage ainda funciona para SEO em 2026? Sim, mas de forma diferente que antes. O Google removeu rich results de FAQ para a maioria dos sites em 2023, então você não verá snippets de FAQ expansíveis em resultados de busca. No entanto, o Google ainda processa o esquema internamente, e ferramentas de busca alimentadas por LLM como ChatGPT, Perplexity e AI Overviews do Google extraem ativamente pares Q&A da marcação FAQPage. Medimos um aumento de 4x em citações de LLM em páginas com esquema FAQPage versus aquelas sem.

Como adicionar marcação de esquema JSON-LD no Next.js App Router? Crie um componente do servidor que renderiza uma tag <script type="application/ld+json"> usando dangerouslySetInnerHTML com JSON.stringify() no seu objeto de esquema. Coloque-o dentro do componente do servidor de sua página — nunca em um componente do cliente. Para esquema em todo o site como Organization, coloque em layout.tsx. Para esquema específico da página como Article ou FAQPage, gere-o a partir de seus dados em cada page.tsx.

Você pode ter múltiplas tags de script JSON-LD em uma página? Absolutamente. O Google explicitamente suporta múltiplos blocos JSON-LD em uma única página. Regularmente renderizamos blocos separados para Article, FAQPage, BreadcrumbList e Organization na mesma página. Cada um recebe sua própria tag <script type="application/ld+json"> com seu próprio @context.

Como gerar marcação de esquema para milhares de páginas programáticas? Construa objetos de esquema a partir de suas linhas de banco de dados em componentes do servidor. Usamos generateStaticParams no Next.js para criar caminhos para todas as páginas, então o componente do servidor de cada página busca seus dados do Supabase e constrói o JSON-LD dinamicamente. O esquema é incorporado em HTML estático em tempo de construção. Para 91.000 páginas, isso funciona durante o processo de construção com ISR tratando atualizações.

Qual é a diferença entre esquema Article e BlogPosting? BlogPosting é um subtipo de Article. Use BlogPosting para posts de blog com data de publicação clara e autor. Use Article para conteúdo editorial mais geral como artigos de notícias ou guias. Na prática, o Google os trata de forma quase idêntica. Usamos Article para a maioria do conteúdo e BlogPosting apenas para posts com formato de blog explícito.

Marcação de esquema ajuda com AI Overviews do Google? Sim. Páginas com dados estruturados são mensuravelmente mais prováveis de serem citadas em AI Overviews. O esquema ajuda a IA do Google a entender relacionamentos de entidades, tipo de conteúdo e precisão de dados. Esquema FAQPage é particularmente eficaz porque fornece pares Q&A pré-estruturados que a IA pode extrair diretamente. Não é garantia de inclusão, mas melhora significativamente suas chances.

Quais ferramentas devo usar para validar marcação de esquema em escala? Para páginas individuais, use o Teste de Rich Results do Google e o Validador de Marcação de Esquema em validator.schema.org. Para validação em massa em milhares de páginas, use o recurso de extração customizada do Screaming Frog para rastrear seu site e extrair todo JSON-LD, então execute a saída através de um script de validação. Monitore problemas contínuos nos relatórios de dados estruturados do Google Search Console.

Devo implementar tipos de esquema para os quais o Google não mostra mais rich results? Sim. Os recursos SERP do Google são apenas um consumidor de seus dados estruturados. ChatGPT, Perplexity, Bing Copilot e outros sistemas de IA leem marcação de esquema. Mesmo se o Google parasse de mostrar rich results HowTo no mobile, o esquema ainda ajudaria LLMs a entender seu conteúdo. Pense em dados estruturados como uma camada legível por máquina universal, não apenas um recurso do Google.