Un rastreador de IA pide tu HTML y lee lo que le llega
Abres una single page application de React en el navegador y ves una página completa. Esa página no está en el fichero que envió el servidor. El servidor envió un cascarón: un <div id="root">, una etiqueta de script y cuatro metaetiquetas. El navegador descarga el bundle, lo ejecuta, llama a tu API y pinta todo lo que ves.
Lo que lee un visitante, y lo que recibe un rastreador de IA
GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-SearchBot, Claude-User y PerplexityBot no hacen nada de eso. Piden la URL, leen los bytes que llegan y siguen. Sin motor de JavaScript, sin esperar a la hidratación, sin llamar a tu API por ti. Lo que no esté en el HTML crudo, para ellos no existe.
Googlebot es la excepción que despista a todo el mundo: sí renderiza JavaScript, con retraso y con presupuesto limitado. Por eso una web renderizada en cliente puede posicionar de forma aceptable en Google y ser una página en blanco en todos los asistentes a los que de verdad pregunta tu comprador. En una web de hotel bilingüe que asumimos en junio de 2026, Google tenía indexadas solo 4 de unas 30 páginas antes de que la pre-renderizáramos.
Lo que falta en el HTML crudo suele ser más de lo que la gente espera:
- El texto que se pinta tras la hidratación, incluidos tu H1 y tu primer párrafo.
- Los textos que se piden en un
useEffecta una API o a una base de datos en tiempo de ejecución. - Los paneles de pestañas y acordeones que solo se montan cuando están activos.
- El JSON-LD que inyecta un helper en cliente en lugar de escribirse en el build.
- Todo lo que quede detrás de un spinner, un aviso de cookies o un disparador de scroll.
Comprueba tu web en dos minutos
No te fíes de nadie en esto, tampoco de nosotros. Apunta curl a tu propia página con un user agent de rastreador y cuenta lo que vuelve.
Primero, descarga la página tal y como la ve GPTBot:
curl -s -A "GPTBot/1.2 (+https://openai.com/gptbot)" https://example.com/ -o crawler.html
wc -c crawler.htmlEl tamaño en bytes engaña, así que mide texto, no bytes. En una web que auditamos, el cascarón pesaba 3.559 bytes y no contenía ni un carácter legible. Esto cuenta los caracteres que un modelo podría leer de verdad:
python3 - <<'PY'
import re
h = open('crawler.html').read()
h = re.sub(r'(?is)<script.*?</script>', ' ', h)
h = re.sub(r'(?is)<style.*?</style>', ' ', h)
t = re.sub(r'(?s)<[^>]+>', ' ', h)
print(len(' '.join(t.split())), 'characters of readable text')
PYUna página real de contenido da miles. Un cascarón vacío da unos cientos, y casi todos son tu meta description. Después, comprueba que la página dice lo que es:
grep -Eio '<title>[^<]*|<h1[^>]*>[^<]*' crawler.html
grep -c 'application/ld+json' crawler.htmlLuego asegúrate de que nada en el borde está rechazando a los bots en silencio. Las reglas de firewall y la protección antibots devuelven un 403 o un reto de JavaScript que ningún rastreador de IA sabe resolver, y tu analítica no te lo va a contar:
for ua in "Mozilla/5.0" "GPTBot/1.2" "OAI-SearchBot/1.0" "ClaudeBot/1.0" "PerplexityBot/1.0"; do
printf '%-22s ' "$ua"
curl -s -o /dev/null -w '%{http_code}\n' -A "$ua" https://example.com/
doneTodas las líneas deberían dar 200. Por último, barre la web entera en vez de una URL afortunada, y ordena las peores páginas arriba:
curl -s https://example.com/sitemap.xml | grep -oE '<loc>[^<]+' | cut -c6- |
while read -r url; do
n=$(curl -s -A "OAI-SearchBot/1.0" "$url" | sed -E 's/<[^>]+>/ /g' | tr -s ' ' | wc -c)
echo "$n $url"
done | sort -n | head -20Qué aspecto tiene un cero de verdad
En el verano de 2026 reconstruimos el comercio electrónico de una marca española de mesa y hogar. Cuando medimos la web antigua igual que acabas de hacer tú, el resultado no fue "contenido pobre": en las 65 URL públicas, las páginas servían 0 caracteres de texto legible a los rastreadores de IA. Nombres de producto, precios, descripciones de serie, condiciones de envío, todo llegaba solo después de ejecutar JavaScript.
Tras la reconstrucción, el mismo barrido del 4 de agosto de 2026 devolvió 105.212 caracteres en esas mismas 65 URL. No se escribió nada para robots: es el mismo texto que lee una persona, movido de tiempo de ejecución al fichero HTML. Ese es todo el truco, y es la única medición de este artículo que hicimos nosotros mismos.
Las tres formas de arreglarlo
Generación estática, la opción por defecto
En el build renderizas cada ruta a un fichero HTML real. Con Vite y React, vite-react-ssg lo hace sin salirte de tu stack: exportas las rutas, defines getStaticPaths para los segmentos dinámicos y el build escribe dist/precios/index.html con el texto ya dentro. La web sigue siendo una SPA una vez hidratada, así que la navegación se mantiene instantánea.
Úsala cuando la lista de rutas se conoce en el build: webs de marca, páginas de servicio, blogs, documentación, catálogos. Que el contenido cambie a diario no lo impide: un deploy hook programado lo reconstruye. El catálogo de mesa y hogar funciona así, con un refresco diario.
Renderizado en servidor, cuando la página depende de la petición
Next.js, Remix o un montaje SSR con Vite generan el HTML en cada petición. Lo necesitas cuando la página no se puede conocer de antemano: stock en vivo de miles de referencias, resultados de búsqueda, cualquier cosa detrás de un login. El precio es un servidor en marcha, diseño de caché y más formas de romperse a las tres de la mañana. No adoptes SSR porque suene más moderno que la generación estática. Adóptalo cuando el contenido dependa de quién pregunta.
Pre-renderizado para rastreadores en el borde, el parche
Cuando una SPA grande no se puede reestructurar ahora, un middleware en el borde puede servir a los rastreadores un cuerpo HTML real mientras las personas siguen con la aplicación intacta. Lo usamos en una web corporativa con unas 700 noticias: el middleware detecta al bot, devuelve el H1, el cuerpo del artículo y el JSON-LD, y el resto recibe la SPA.
Dos condiciones lo hacen seguro. El texto que sirves a los bots tiene que ser el mismo que ve una persona, verificado con una prueba de paridad automática en CI; si no, es cloaking. Y trátalo como un puente, no como un destino, porque a partir de ahí mantienes dos caminos de renderizado.
Cuál eliges
- Ruta conocida en el build y contenido que cambia como mucho a diario: generación estática.
- Contenido que depende de la petición o del usuario: renderizado en servidor.
- SPA grande que no puedes reconstruir este trimestre: pre-renderizado en el borde, con prueba de paridad.
Lo que no lo arregla
- Un fichero
llms.txt. Los asistentes de consumo no lo piden y Google lo ignora. Sirve para agentes de código, no para visibilidad. - El JSON-LD por sí solo. En un estudio de Ahrefs de 2026 sobre 1.885 páginas frente a 4.000 de control, añadir schema no produjo mejora apreciable en AI Overviews, AI Mode ni ChatGPT. El texto visible es la capa principal y los datos estructurados lo reflejan.
- Escribir "para la IA": trocear páginas en fragmentos, copias en markdown solo para modelos, tipos de schema inventados. La guía de Google de 2026 dice que no ayudan, y las páginas solo para IA son un riesgo de cloaking.
- Poner
nosnippetomax-snippet:0en páginas que quieres que te citen. Eliminan justo la elegibilidad que intentas ganar.
Verifica, y sigue verificando
Repite el barrido después de desplegar y deja una versión en CI, para que ninguna refactorización vuelva a sacar el texto del HTML en silencio. Mira los registros del servidor, no tu analítica: los rastreadores no ejecutan JavaScript, así que GA4 y Plausible no los ven nunca, y los logs de Vercel o Cloudflare filtrados por user agent son el único registro honesto de si los bots han vuelto.
Si prefieres que alguien lo mida y lo arregle contigo, Polargate lo hace dentro de un Discovery Sprint de pago y precio cerrado. En cualquier caso, ejecuta antes los comandos de curl. El número que salga no es una opinión.



