Tenten AIGEO
Voltar ao blog
AEO técnicoImplementação

Como inserir JSON-LD no Next.js App Router com Server Components

No Next.js App Router, o Server Component gera diretamente o `<script type="application/ld+json">`, incluindo os dados estruturados no HTML inicial para que crawlers de IA possam lê-los sem executar JavaScript. Veja um exemplo mínimo em page.tsx, a combinação de várias entidades com @graph e as etapas de validação com curl antes da publicação.

Equipe Tenten GEOPublicado em 2026-06-115 min de leitura
Diagrama: os dados estruturados gerados pelo servidor seguem diretamente para o HTML inicial lido pelo crawler de IA.

A forma mais confiável de inserir JSON-LD no App Router é gerar diretamente um bloco `<script type="application/ld+json">` em um Server Component. Assim, os dados estruturados já aparecem no HTML inicial retornado pelo servidor, e o crawler de IA consegue lê-los sem executar JavaScript. Para mecanismos de resposta, o JSON-LD acrescentado depois via useEffect ou Google Tag Manager praticamente não existe: na maioria dos casos, o crawler termina a coleta e vai embora antes da hidratação da página.

Por que a geração precisa acontecer no servidor?

A diferença está no momento em que o conteúdo aparece. O Server Component grava o JSON-LD na string de HTML durante a requisição. Por isso, o primeiro arquivo coletado por crawlers como GPTBot, ClaudeBot, PerplexityBot e Google-Extended já contém o schema completo. A inserção no cliente, por outro lado, depende de o navegador baixar e executar o bundle — etapa que a maioria dos crawlers de IA nem sequer realiza. Há ainda uma armadilha fácil de ignorar: o Google Rich Results Test renderiza o JavaScript, então os dados inseridos no cliente parecem normais na ferramenta e dão a impressão de que a validação foi concluída. Na prática, porém, o mecanismo de resposta pode receber apenas o HTML original, ainda não renderizado e sem nenhum schema. Nas auditorias técnicas que fazemos para clientes, esse é um dos problemas mais comuns — e também um dos mais fáceis de passar despercebido.

Exemplo mínimo viável: uma única page.tsx

A implementação é curta. Não exige pacotes adicionais nem rotas de API: tudo acontece no Server Component que renderiza o artigo. O fluxo tem apenas três partes centrais: buscar os dados, montar os objetos e gerar o script.

  1. Em `app/blog/[slug]/page.tsx` — que, por padrão, é um Server Component — use primeiro `await` para buscar os dados do artigo.
  2. Monte um objeto JavaScript puro chamado `jsonLd`. Comece com `"@context": "https://schema.org"` e `"@type": "Article"`; depois, preencha dinamicamente os demais campos — headline, datePublished, author e image — com os dados do artigo.
  3. No início do JSX retornado, inclua: `<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, "\\u003c") }} />`.
  4. Não importe bibliotecas de cliente nem adicione "use client" no início do arquivo. Ao fazer isso, o arquivo passa a ser um Client Component e todo o benefício da geração no servidor é perdido.

Como conectar várias entidades com @graph

Uma página normalmente precisa de mais de um schema: a marca é uma Organization, o artigo é um Article, o caminho de navegação é um BreadcrumbList e a seção de perguntas e respostas é uma FAQPage. Em vez de gerar quatro tags de script independentes, uma solução mais organizada é reunir tudo em um array `@graph` dentro do mesmo objeto JSON-LD e conectar as entidades por meio de `@id`. Por exemplo: o `publisher` de Article pode apontar para o `@id` de Organization, enquanto o último item de BreadcrumbList aponta para o `@id` da página atual. Assim, o mecanismo de resposta obtém todo o mapa de relações entre as entidades em uma única análise, com menos risco de encontrar nós contraditórios ou duplicados.

  • Organization e WebSite: coloque-os em `app/layout.tsx` para compartilhá-los uma única vez em todo o site. Não repita essas declarações em cada página.
  • Article ou BlogPosting: coloque-o na `page.tsx` do artigo e preencha os campos dinamicamente com os dados da página atual.
  • BreadcrumbList: organize-o de acordo com a hierarquia das rotas. Isso ajuda especialmente a IA a compreender a estrutura do site.
  • FAQPage: adicione-o somente quando a página realmente exibir uma seção de perguntas e respostas. O texto de `acceptedAnswer` deve corresponder ao conteúdo visível. Não invente uma FAQ apenas para ter o schema.
Infográfico: o Server Component inclui o JSON-LD no HTML inicial, enquanto a inserção no cliente é ignorada pelo crawler de IA.
O JSON-LD gerado pelo servidor entra no HTML inicial; o conteúdo inserido no cliente pode não estar disponível a tempo para o crawler.

Como manter o JSON-LD sustentável

Se os objetos de schema ficarem espalhados pelas páginas, depois de três meses ninguém vai querer mexer neles. Nossa abordagem é centralizá-los em `lib/schema.ts` e usar os tipos de `schema-dts` (`import type { Article, WithContext } from "schema-dts"`) para limitar o valor retornado por cada função geradora. Se o nome ou o tipo de um campo estiver incorreto, o TypeScript apontará o erro durante a compilação. A página apenas chama `buildArticleSchema(post)`, recebe um objeto com segurança de tipos e o gera. Qualquer alteração passa a valer em todo o site. As URLs devem sempre ser absolutas e ficar centralizadas em uma constante `SITE_URL`, evitando divergências de `@id` entre o site oficial e o domínio de preview.

Erros comuns e validação antes da publicação

  • Os valores de `url`, `image` e `datePublished` no JSON-LD não correspondem ao conteúdo real da página. O mecanismo de resposta identifica essa divergência, o que reduz a confiança na página inteira.
  • Usar caminhos relativos em `@id` ou `url` pode apontar para o endereço errado ao alternar para o domínio de preview.
  • Esquecer de escapar `<` ou adicionar `"use client"` por engano no início da página faz com que o script passe a ser gerado no cliente.
  • Antes da publicação, use o Google Rich Results Test para verificar a sintaxe. Depois, execute `curl` para capturar diretamente o HTML original da página e confirmar que o script realmente faz parte da resposta inicial — e não aparece apenas no DevTools do navegador. Essa é a etapa mais importante, pois reproduz exatamente o que o crawler de IA enxerga.
Nos sites que auditamos, a maioria dos problemas de JSON-LD não vem de um schema mal escrito, mas do fato de ele existir apenas no cliente. Se os dados não estão no HTML retornado pelo servidor, para a IA é como se não existissem.Tenten GEO Technical Audit

Da implementação à citação

Levar o JSON-LD para o Server Component é o requisito mínimo para tornar o conteúdo legível por máquinas. O próximo passo é alinhar a nomenclatura das entidades, os links internos e a consistência entre páginas, para que a IA possa citar sua marca de forma recorrente como uma fonte confiável. Se você não sabe se os dados estruturados do seu site chegaram ao HTML que o crawler realmente vê, agende um diagnóstico GEO de 30 minutos. Vamos analisar o código-fonte efetivamente capturado para mapear as lacunas, em vez de olhar apenas para a página já renderizada.

Perguntas frequentes

Como adicionar JSON-LD ao Next.js App Router?
Monte um objeto de schema no Server Component, em page.tsx ou layout.tsx, e gere-o com `<script type="application/ld+json">` e `dangerouslySetInnerHTML`. Também é preciso escapar o `<` da string para `<`. Dessa forma, os dados estruturados entram no HTML inicial e podem ser lidos pelo crawler de IA sem a execução de JavaScript.
Posso inserir JSON-LD usando next/head ou a Metadata API?
O App Router não usa mais next/head, e a Metadata API não permite gerar tags de script arbitrárias. A recomendação oficial do Next.js é renderizar `<script type="application/ld+json">` diretamente no JSX do Server Component. Atualmente, essa é a forma mais estável de inserir JSON-LD e também a mais fácil de ser lida pelos crawlers.
Por que não é recomendável inserir dados estruturados com GTM ou useEffect?
As duas opções são executadas no cliente, portanto o JSON-LD só aparece depois da hidratação no navegador. A maioria dos crawlers de IA coleta apenas o HTML inicial e não executa JavaScript, o que os impede de enxergar o schema. Para garantir que os dados estruturados sejam realmente lidos e usados como referência pelo mecanismo de resposta, a geração precisa acontecer no servidor.

PRÓXIMO PASSO

Qual é a visibilidade da sua marca nas respostas de IA?

Em um diagnóstico GEO de 30 minutos, identificamos lacunas de visibilidade e as ações que merecem prioridade.

Agendar diagnóstico