# Como Corrigir a IA Que Ignora Metadados SEO

> 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.

**Type:** Failure  
**Tools:** Cursor, Claude Code, Codex, Windsurf  
**Stack:** Next.js, Astro, TypeScript  
**Updated:** 2026-06-08

---

O agente gera componentes de página sem exportação `Metadata`, sem tag `title`
e sem tags Open Graph, produzindo páginas que ranqueiam mal e são mal compartilhadas nas
redes sociais.

## O sintoma

Uma página do Next.js App Router é gerada sem nenhuma exportação de metadados, deixando o
título da aba vazio e o `head` vazio além dos padrões do Next.js.

```tsx
// app/blog/[slug]/page.tsx — WRONG
export default async function BlogPost({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug);
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.html }} />
    </article>
  );
  // No <title>, no meta description, no og:image, no canonical URL
}
```

O Google vê: `Untitled document`. Twitter/LinkedIn mostram um card em branco.

## Por que isso acontece

O agente foca na UI visível — busca e renderização de dados — e trata
os metadados do `head` como algo secundário. O SEO é invisível durante o desenvolvimento local
e não produz um erro em tempo de execução, então o agente nunca recebe feedback de que está
faltando.

## Como identificar

- Nenhum `export const metadata` ou `export async function generateMetadata` nos arquivos
  de página do App Router.
- Nenhum `Astro.props` ou `title` / `description` orientados por frontmatter nos layouts
  do Astro.
- Pontuação de SEO do Lighthouse abaixo de 90 em uma nova página.
- `curl -s http://localhost:3000/blog/my-post | grep "<title>"` retorna nada
  ou um título de site genérico.
- `og:image` ausente do `head` (a prévia social mostra um card em branco).

## Como corrigir

Exporte `generateMetadata` para páginas dinâmicas e adicione todas as tags necessárias.

```tsx
// app/blog/[slug]/page.tsx — CORRECT
import type { Metadata } from "next";

export async function generateMetadata({
  params,
}: {
  params: { slug: string };
}): Promise<Metadata> {
  const post = await getPost(params.slug);
  return {
    title: post.title,
    description: post.excerpt,
    alternates: { canonical: `https://example.com/blog/${params.slug}` },
    openGraph: {
      title: post.title,
      description: post.excerpt,
      url: `https://example.com/blog/${params.slug}`,
      images: [{ url: post.ogImage, width: 1200, height: 630, alt: post.title }],
      type: "article",
      publishedTime: post.publishedAt,
    },
    twitter: {
      card: "summary_large_image",
      title: post.title,
      description: post.excerpt,
      images: [post.ogImage],
    },
  };
}

export default async function BlogPost({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug);
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.html }} />
    </article>
  );
}
```

Para Astro, passe metadados através do layout:

```astro
---
// src/pages/blog/[slug].astro
const { post } = Astro.props;
---
<Layout
  title={post.title}
  description={post.excerpt}
  ogImage={post.ogImage}
  canonical={`https://example.com/blog/${post.slug}`}
>
  <article>
    <h1>{post.title}</h1>
    <post.Content />
  </article>
</Layout>
```

```txt
[ ] Every page exports generateMetadata (Next.js) or passes title+description to layout (Astro)
[ ] title is unique per page — not just the site name
[ ] description is 120-160 characters and describes the page content
[ ] og:title, og:description, og:image (1200x630), og:url are all set
[ ] twitter:card is "summary_large_image" for pages with images
[ ] canonical URL is set to the preferred URL (no trailing slash ambiguity)
[ ] robots meta is not accidentally set to "noindex"
[ ] Verify with: curl -s <url> | grep -E "<title>|og:title|description"
```

## Prompt de Correção

```txt title="Fix Prompt"
This page component is missing all SEO metadata. Add an async generateMetadata
export (Next.js App Router) that returns title, description, canonical URL, full
openGraph object (title, description, url, images with 1200x630 dimensions, type),
and twitter card metadata. Derive values from the page's data fetch — do not use
placeholder strings. Also confirm that no parent layout accidentally sets
robots: noindex.
```

## Teste

```bash
# Check that <title> and og:title appear in the server-rendered HTML
curl -s http://localhost:3000/blog/my-post \
  | grep -E '<title>|og:title|og:description|og:image|canonical' \
  | grep -v "node_modules" \
  && echo "Metadata present" || echo "FAIL: metadata missing"
```