{
  "id": "ai-ignores-seo-metadata",
  "type": "failures",
  "category": "failures",
  "locale": "pt",
  "url": "/pt/failures/ai-ignores-seo-metadata",
  "title": "Como Corrigir a IA Que Ignora Metadados SEO",
  "description": "Agentes de IA geram páginas Next.js e Astro sem tags de título, metadados Open Graph ou URLs canônicas, resultando em páginas invisíveis para motores de busca e rastreadores sociais.",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "Next.js",
    "Astro",
    "TypeScript"
  ],
  "tags": [
    "seo",
    "nextjs",
    "astro"
  ],
  "difficulty": null,
  "updated": "2026-06-08",
  "markdown": "O agente gera componentes de página sem exportação `Metadata`, sem tag `title`\ne sem tags Open Graph, produzindo páginas que ranqueiam mal e são mal compartilhadas nas\nredes sociais.\n\n## O sintoma\n\nUma página do Next.js App Router é gerada sem nenhuma exportação de metadados, deixando o\ntítulo da aba vazio e o `head` vazio além dos padrões do Next.js.\n\n```tsx\n// app/blog/[slug]/page.tsx — WRONG\nexport default async function BlogPost({ params }: { params: { slug: string } }) {\n  const post = await getPost(params.slug);\n  return (\n    <article>\n      <h1>{post.title}</h1>\n      <div dangerouslySetInnerHTML={{ __html: post.html }} />\n    </article>\n  );\n  // No <title>, no meta description, no og:image, no canonical URL\n}\n```\n\nO Google vê: `Untitled document`. Twitter/LinkedIn mostram um card em branco.\n\n## Por que isso acontece\n\nO agente foca na UI visível — busca e renderização de dados — e trata\nos metadados do `head` como algo secundário. O SEO é invisível durante o desenvolvimento local\ne não produz um erro em tempo de execução, então o agente nunca recebe feedback de que está\nfaltando.\n\n## Como identificar\n\n- Nenhum `export const metadata` ou `export async function generateMetadata` nos arquivos\n  de página do App Router.\n- Nenhum `Astro.props` ou `title` / `description` orientados por frontmatter nos layouts\n  do Astro.\n- Pontuação de SEO do Lighthouse abaixo de 90 em uma nova página.\n- `curl -s http://localhost:3000/blog/my-post | grep \"<title>\"` retorna nada\n  ou um título de site genérico.\n- `og:image` ausente do `head` (a prévia social mostra um card em branco).\n\n## Como corrigir\n\nExporte `generateMetadata` para páginas dinâmicas e adicione todas as tags necessárias.\n\n```tsx\n// app/blog/[slug]/page.tsx — CORRECT\nimport type { Metadata } from \"next\";\n\nexport async function generateMetadata({\n  params,\n}: {\n  params: { slug: string };\n}): Promise<Metadata> {\n  const post = await getPost(params.slug);\n  return {\n    title: post.title,\n    description: post.excerpt,\n    alternates: { canonical: `https://example.com/blog/${params.slug}` },\n    openGraph: {\n      title: post.title,\n      description: post.excerpt,\n      url: `https://example.com/blog/${params.slug}`,\n      images: [{ url: post.ogImage, width: 1200, height: 630, alt: post.title }],\n      type: \"article\",\n      publishedTime: post.publishedAt,\n    },\n    twitter: {\n      card: \"summary_large_image\",\n      title: post.title,\n      description: post.excerpt,\n      images: [post.ogImage],\n    },\n  };\n}\n\nexport default async function BlogPost({ params }: { params: { slug: string } }) {\n  const post = await getPost(params.slug);\n  return (\n    <article>\n      <h1>{post.title}</h1>\n      <div dangerouslySetInnerHTML={{ __html: post.html }} />\n    </article>\n  );\n}\n```\n\nPara Astro, passe metadados através do layout:\n\n```astro\n---\n// src/pages/blog/[slug].astro\nconst { post } = Astro.props;\n---\n<Layout\n  title={post.title}\n  description={post.excerpt}\n  ogImage={post.ogImage}\n  canonical={`https://example.com/blog/${post.slug}`}\n>\n  <article>\n    <h1>{post.title}</h1>\n    <post.Content />\n  </article>\n</Layout>\n```\n\n```txt\n[ ] Every page exports generateMetadata (Next.js) or passes title+description to layout (Astro)\n[ ] title is unique per page — not just the site name\n[ ] description is 120-160 characters and describes the page content\n[ ] og:title, og:description, og:image (1200x630), og:url are all set\n[ ] twitter:card is \"summary_large_image\" for pages with images\n[ ] canonical URL is set to the preferred URL (no trailing slash ambiguity)\n[ ] robots meta is not accidentally set to \"noindex\"\n[ ] Verify with: curl -s <url> | grep -E \"<title>|og:title|description\"\n```\n\n## Prompt de Correção\n\n```txt title=\"Fix Prompt\"\nThis page component is missing all SEO metadata. Add an async generateMetadata\nexport (Next.js App Router) that returns title, description, canonical URL, full\nopenGraph object (title, description, url, images with 1200x630 dimensions, type),\nand twitter card metadata. Derive values from the page's data fetch — do not use\nplaceholder strings. Also confirm that no parent layout accidentally sets\nrobots: noindex.\n```\n\n## Teste\n\n```bash\n# Check that <title> and og:title appear in the server-rendered HTML\ncurl -s http://localhost:3000/blog/my-post \\\n  | grep -E '<title>|og:title|og:description|og:image|canonical' \\\n  | grep -v \"node_modules\" \\\n  && echo \"Metadata present\" || echo \"FAIL: metadata missing\"\n```"
}