SEO en Next.js: ¿cómo hago que ChatGPT cite mi sitio?

Haz que cada página se lea sin JavaScript, descríbela y deja entrar al bot de búsqueda de ChatGPT. En Next.js eso es: Server Components con el texto en el HTML, la Metadata API para título, canonical e idiomas, app/robots.ts que permite OAI-SearchBot, app/sitemap.ts y JSON-LD en la página. Nada de esto garantiza una cita; quita los motivos para que ChatGPT no use tu página.

Datos

  • OpenAI dice que los sitios que bloquean OAI-SearchBot no aparecen en las respuestas de búsqueda de ChatGPT, y que un cambio en robots.txt tarda unas 24 horas en aplicarse. (OpenAI: Overview of OpenAI crawlers)
  • OpenAI dice que bloquear GPTBot solo indica que el contenido no debe entrenar sus modelos; las visitas de ChatGPT-User las inicia el usuario y no deciden qué aparece en la búsqueda. (OpenAI: Overview of OpenAI crawlers)
  • Next.js dice que el export metadata y generateMetadata, disponibles desde la v13.2.0, solo funcionan en Server Components para que la metadata vaya en el HTML inicial. (Next.js docs: generateMetadata)
  • Next.js genera robots.txt desde app/robots.ts desde la v13.3.0, con reglas por user agent. (Next.js docs: robots.txt)
  • app/sitemap.ts acepta URLs alternativas por idioma desde Next.js v14.2.0, y el límite de Google es de 50.000 URLs por sitemap. (Next.js docs: sitemap.xml)

¿Qué bot de OpenAI tengo que permitir?

OAI-SearchBot es el que decide si la búsqueda de ChatGPT puede mostrar tu sitio. Los tres hacen cosas distintas, así que permite o bloquea cada uno por separado.

// app/robots.ts
import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      { userAgent: "*", allow: "/" },
      // ChatGPT search: must be allowed to be shown in answers
      { userAgent: "OAI-SearchBot", allow: "/" },
      // Model training: your choice, it does not decide search
      { userAgent: "GPTBot", allow: "/" },
    ],
    sitemap: "https://www.example.com/sitemap.xml",
  };
}
User agentQué haceEfecto de bloquearlo
OAI-SearchBotRastrea sitios para la búsqueda de ChatGPTTus páginas no aparecen en las respuestas de búsqueda de ChatGPT
GPTBotRastrea contenido que puede entrenar los modelos de OpenAIEl contenido no se usa para entrenar; la búsqueda no cambia
ChatGPT-UserVisita la página cuando la pregunta de un usuario lo piderobots.txt puede no aplicarse; no decide la búsqueda

¿Por qué el texto debe venir renderizado del servidor?

Porque los bots de ChatGPT leen el HTML que envía tu servidor y no ejecutan JavaScript. En el App Router las páginas son Server Components por defecto; el texto que se trae en un Client Component después de cargar no está en ese HTML. Deja la página como Server Component y pasa solo lo interactivo a archivos con "use client".

¿Qué debe tener la metadata de cada página?

Un título y una descripción únicos, la URL canónica y, en sitios multilingües, las alternativas de idioma. generateMetadata los arma por página; Next.js convierte alternates en enlaces rel="canonical" y hreflang. El JSON-LD va en la página en una etiqueta script simple, con "<" escapado como muestra la documentación de Next.js, y debe decir lo mismo que el texto visible.

// app/guides/[slug]/page.tsx (a Server Component: no "use client")
import type { Metadata } from "next";

export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
  const { slug } = await params;
  const page = await getPage(slug);
  return {
    title: page.title,
    description: page.description,
    alternates: {
      canonical: `/guides/${slug}`,
      languages: { "pt-BR": `/pt/guides/${slug}`, es: `/es/guides/${slug}` },
    },
  };
}

export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const page = await getPage(slug);
  const jsonLd = { "@context": "https://schema.org", "@type": "Article", headline: page.title };
  return (
    <article>
      <script type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, "\\u003c") }} />
      <h1>{page.title}</h1>
      <p>{page.answer}</p>
    </article>
  );
}

¿Cómo lo pruebo como lo ve un bot?

Descarga la página publicada sin navegador y busca el texto de la respuesta, el título, el canonical y el JSON-LD. Si el texto no está en el HTML crudo, ChatGPT no puede citarlo.

# 1. The text is in the raw HTML (no JavaScript run)
curl -s -A "OAI-SearchBot" https://www.example.com/guides/my-page | grep -i "a sentence from the answer"

# 2. Title, canonical and JSON-LD are there too
curl -s https://www.example.com/guides/my-page | grep -iE "<title>|rel=\"canonical\"|ld\+json"

# 3. robots.txt and sitemap answer
curl -s https://www.example.com/robots.txt
curl -s https://www.example.com/sitemap.xml | grep -c "<loc>"

¿Con todo bien configurado me van a citar?

No necesariamente. La configuración hace que tus páginas se lean y sean elegibles; ChatGPT elige fuentes por lo bien que responden. El contenido todavía tiene que ser la respuesta más clara a lo que preguntan tus clientes.

Paso a paso

  1. Revisa robots. Crea app/robots.ts que permita OAI-SearchBot y apunte al sitemap; decide GPTBot aparte.
  2. Mantén las páginas en el servidor. Asegúrate de que cada página pública sea Server Component con su texto principal en el HTML.
  3. Agrega la metadata. Usa generateMetadata para título, descripción, canonical e idiomas únicos en cada página.
  4. Agrega JSON-LD y sitemap. Renderiza el JSON-LD en la página y lista cada URL pública en app/sitemap.ts.
  5. Prueba el sitio publicado. Corre las pruebas con curl después del despliegue, no en localhost.

Errores comunes

  • Bloquear GPTBot y OAI-SearchBot juntos con una sola regla cuando solo se quería bloquear el entrenamiento.
  • Cargar el texto del artículo en useEffect, dejando vacío el HTML que recibe el bot.
  • Repetir el mismo título, descripción o canonical en todas las páginas desde el layout raíz.
  • Un JSON-LD que afirma cosas que la página visible no dice.

Cómo lo resuelve easyIndex

easyIndex encaja con un sitio en Next.js porque el trabajo queda en tu repositorio: tu agente de código escribe las páginas y easyIndex da los pasos por MCP, audita cada página al enviarla y la revisa en el sitio publicado, así que un paso se cierra con evidencia que él mismo comprueba, no con el reporte del agente.

Después el panel muestra visitantes desde asistentes de IA por página y qué páginas leyeron los bots de IA. Un plan con todo: US$ 30 por sitio al mes, 7 días gratis con un sitio.

Preguntas frecuentes

¿Debo bloquear GPTBot?

Es tu decisión. OpenAI dice que GPTBot es para entrenamiento y OAI-SearchBot para búsqueda, así que bloquear solo GPTBot no te saca de la búsqueda de ChatGPT.

¿Necesito el Pages Router o el App Router?

Los dos pueden enviar HTML renderizado en servidor. Esta guía usa el App Router, donde las páginas son Server Components por defecto y está la Metadata API.

¿llms.txt es obligatorio?

No. La búsqueda de ChatGPT lee tus páginas; un llms.txt no reemplaza el texto en el HTML.

¿Cuánto tarda en aplicarse un cambio en robots.txt?

OpenAI habla de unas 24 horas para que sus sistemas de búsqueda se ajusten.

Sigue leyendo

Verificado el .

SEO en Next.js: cómo hacer que ChatGPT cite tu sitio