Volver al Blog
Angular Development11 de noviembre de 20268 min de lectura

¿Tu Sitio JavaScript Es Invisible para la Búsqueda con IA? Cómo Comprobarlo y Arreglarlo

DR

Doug Ribeiro

8 min de lectura

Una app de Angular renderizada en el cliente se ve completa en un navegador y casi vacía para cualquier bot que no ejecuta JavaScript. Antes de pasar mi portafolio a prerendering estático, medí esa línea base como lo haría un crawler así. Un post del blog de algo más de mil palabras volvía como un app-root vacío, con el mismo título genérico que compartían todas las páginas. El artículo solo existía después de que Angular arrancaba en un navegador.

Después de la migración, la misma URL devuelve unas 1.300 palabras en el HTML inicial, con su propio título. Esa cifra incluye el header y el footer, pero la diferencia es el artículo entero. El contenido en sí no cambió.

Lo Que Hacen de Verdad los Crawlers

Google es la excepción famosa, y engañó a toda una generación de nosotros. Su documentación describe tres fases: rastreo, renderizado, indexación. Las páginas esperan en una cola hasta que un Chromium headless puede ejecutar el JavaScript. Así que una app renderizada en el cliente puede posicionar en Google, y eso nos enseñó que los crawlers ejecutan JavaScript. La misma guía todavía dice que el renderizado del lado del servidor o el prerendering valen la pena, porque no todos los bots pueden ejecutar JavaScript.

La medición que sigo viendo citada para los demás es la de Vercel, de diciembre de 2024. Encontró que los crawlers de OpenAI, ClaudeBot de Anthropic y los crawlers de Meta, ByteDance y Perplexity no renderizaban JavaScript. Los crawlers de ChatGPT y de Claude sí descargaban archivos JavaScript, pero no los ejecutaban. Gemini, sobre la infraestructura de Google, y AppleBot sí renderizaban. Esos datos tienen casi dos años, y no encontré un estudio más nuevo de la misma calidad. Los crawlers cambian, así que verifica contra tu propio sitio y tus propios logs.

La Prueba de un Minuto

Elige una página real de contenido y una frase corta del medio, sin puntuación, porque las entidades HTML causan ceros falsos. Después pide la página como lo haría un crawler simple. El grep cuenta las líneas que coinciden, así que cero significa que la frase no está en el HTML que se sirvió. Una coincidencia puede venir de un blob de estado JSON en lugar del markup, así que abre la salida y mírala si el número te sorprende.

bash
# Is the content in the HTML the server sends?
curl -sL https://example.com/some-article | grep -c "a short phrase from the middle"

# Is your host or CDN treating a bot differently?
curl -sL -o /dev/null -w '%{http_code}\n' -A "GPTBot" https://example.com/some-article

# Does a page that does not exist return a real 404?
curl -sL -o /dev/null -w '%{http_code}\n' https://example.com/this-page-does-not-exist

En la línea base renderizada en el cliente, el primero devolvió 0 y el tercero devolvió 200. Ese último es un soft 404. El hosting de single-page apps suele reescribir toda URL desconocida a index.html, así que los bots reciben un status de éxito y un shell vacío por cada enlace muerto. Es la falla que la gente pasa por alto porque la página se ve bien en un navegador, donde la app renderiza una pantalla de no encontrado bien cuidada.

Distingue Cada Bot Antes de Tocar robots.txt

Bloquear bots de IA suele ser una sola decisión tomada sobre tres cosas distintas. Los proveedores las separan, y esa distinción decide qué pierdes.

  • Entrenamiento: GPTBot y ClaudeBot. Bloquearlos indica que tu contenido no debe usarse para entrenar modelos.
  • Índice de búsqueda: OAI-SearchBot y Claude-SearchBot. Si bloqueas OAI-SearchBot, OpenAI dice que tu sitio no aparecerá en las respuestas de búsqueda de ChatGPT, aunque todavía puede mostrarse como un enlace de navegación. Anthropic advierte que bloquear Claude-SearchBot puede reducir tu visibilidad en sus resultados de búsqueda.
  • Acceso iniciado por el usuario: ChatGPT-User y Claude-User. Estos piden una página porque una persona lo solicitó. Anthropic dice que bloquear Claude-User puede reducir la visibilidad en búsquedas dirigidas por el usuario. OpenAI dice que ChatGPT-User no es lo que determina si el contenido aparece en la búsqueda, y que las reglas de robots.txt pueden no aplicarse a él.

Así que puedes rechazar el entrenamiento y seguir siendo encontrable. Se ve así. Mi propio sitio permite todo, porque un portafolio quiere ser leído, pero este es el archivo del que partiría si no quisiera alimentar el entrenamiento:

text
User-agent: GPTBot
Disallow: /

User-agent: ClaudeBot
Disallow: /

User-agent: *
Allow: /

Sitemap: https://example.com/sitemap.xml

Ve a leer tu robots.txt actual ahora. Si alguien agregó un bloqueo general de IA hace unos años, revisa si también atrapa a los bots de búsqueda. Revisa también cualquier configuración de protección contra bots en tu CDN, que puede bloquear crawlers que robots.txt permite. El segundo curl de arriba puede detectar un bloqueo basado en el user agent, aunque no uno basado en IP.

No Usé llms.txt, y la Evidencia Me Respalda

llms.txt es una propuesta de septiembre de 2024 de Jeremy Howard para un archivo Markdown que les indica a los modelos de lenguaje tu contenido clave. No es un estándar ratificado. Es barato, así que la gente lo agrega con la esperanza de conseguir citas en IA. La evidencia no está de su lado.

  • Ahrefs revisó logs de servidor de 137.000 dominios, todos clientes de su propia analítica, así que trata el 28% que publica el archivo como un límite superior. El 97% de esos archivos recibió cero solicitudes en mayo de 2026.
  • SE Ranking estudió unos 300.000 dominios y no encontró ninguna relación medible entre tener el archivo y ser citado.
  • La guía de Google dice que no necesitas nuevos archivos legibles por máquina ni archivos de texto para IA para aparecer en AI Overviews o AI Mode. John Mueller también ha dicho que los sistemas LLM no pueden confiar en el archivo como forma de distinguir un sitio web de otro.

Un contrapunto honesto. Ahrefs encontró a GPTBot y Claude Code cerca del tope de los agentes de IA que piden estos archivos, aunque GPTBot fue solo alrededor del 4,5% de los accesos, y Chrome agregó una verificación de llms.txt a las auditorías agénticas experimentales de Lighthouse. Si tienes un sitio de documentación que leen agentes de programación, el archivo puede valer sus pocos minutos de trabajo. Para un sitio de marketing, un blog o un portafolio, yo gastaría esos minutos en el HTML. Mi sitio no tiene uno.

Lo Que Llevó el Arreglo en un Hosting Estático

No necesitas un servidor Node para esto. Mi sitio vive en un hosting estático, y el prerendering cuesta tiempo de build más una restricción real: cambiar contenido ahora implica un rebuild y un deploy. Angular lo trae incorporado: agrega @angular/ssr, configura outputMode en static en angular.json y dale a cada ruta pública un modo Prerender. Las rutas con parámetros tienen que declarar sus valores en tiempo de build, que es la parte que requiere pensar:

typescript
// app.routes.server.ts (simplified)
export const serverRoutes: ServerRoute[] = [
  {
    path: 'blog/:slug',
    renderMode: RenderMode.Prerender,
    getPrerenderParams: async () => postSlugs().map(slug => ({ slug })),
  },
  { path: '**', renderMode: RenderMode.Client }, // the shell I publish as 404.html
];

En React, la misma decisión recae en un framework: Astro, Next.js o React Router en modo framework. El static export de Next.js pierde el renderizado por request, así que verifícalo antes de elegirlo. La herramienta no importa. Decide por ruta: el contenido que cualquiera puede leer recibe HTML en tiempo de build, el contenido que cambia por request recibe renderizado en el servidor, y todo lo que está detrás de un login puede quedarse renderizado en el cliente, porque de todos modos ningún crawler llega ahí.

El build produce unas 300 páginas en cuatro idiomas. El render fue la mitad fácil. Esto es el resto:

  • Un title propio de cada página y una description y un canonical únicos en cada página, en el HTML inicial.
  • Hreflang solo entre traducciones reales. Una página que cae de vuelta al inglés recibe un canonical a la URL en inglés y ningún alternate.
  • Un sitemap generado en tiempo de build a partir de los datos de los posts, y un build que falla si los conteos de posts no coinciden.
  • Una URL por página. Elige con barra final o sin barra final y redirige la otra. Apache agrega su propio redirect de directorio, así que lo desactivé con DirectorySlash Off, agregué un rewrite al index.html de cada carpeta y mantuve desactivados los listados de directorio.
  • Un status 404 real. Un 404.html mediante ErrorDocument, no un rewrite a index.html.
  • Una hidratación que no pelee con el HTML estático. En Angular, mira provideClientHydration y su transfer cache. Todo lo que depende de la página terminada, como hacer scroll a un ancla, tiene que esperar a ApplicationRef.whenStable. El síntoma típico es un enlace que hace scroll antes de que la sección haya cargado.

Lo Que el Prerendering No Promete

Un HTML legible hace que te tengan en cuenta. Eso es todo lo que te da. Nada de esto garantiza que una respuesta de IA te cite. Lo que sí puedo decir es que la falla es binaria: el contenido que un bot no puede leer no puede citarse a partir de ese fetch. Arregla eso primero, porque es la única parte de la discusión sobre búsqueda con IA que controlas por completo.

Después del deploy, lee tus access logs en lugar de adivinar. Un grep de GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-SearchBot, Claude-User y PerplexityBot muestra quién visita y qué status recibe. Los user agents se pueden falsificar, así que tómalo como una señal aproximada.

Abre tu sitio con JavaScript desactivado, o hazle curl. Lo que veas es lo que ve una gran parte de los bots que te importan.

Referencias

SEOAngularPrerenderingAIWeb Performance