SEO para Astro
Audita y mejora la configuración SEO de un sitio Astro frente a la pila completa descrita en Astro SEO: la guía definitiva. La skill cubre nueve áreas — fundamentos técnicos, datos estructurados, contenido, estructura del sitio, rendimiento, mapas del sitio e indexación, descubrimiento de agentes, redirecciones y analítica — y produce código listo para usar para cualquier elemento faltante o débil.
La columna vertebral opinada de esta skill es @jdevalk/astro-seo-graph. La mayoría de las correcciones pasan a través de él. Si el proyecto aún no lo usa, instalarlo es la primera recomendación.
Las recetas de código están en AGENTS.md — léelo cuando necesites implementar una corrección específica. Este archivo tiene el flujo de trabajo y la lista de verificación de auditoría.
Flujo de trabajo
- Detectar el proyecto — confirma que es un sitio Astro y comprende su estructura.
- Auditar — puntúa nueve categorías y produce hallazgos accionables.
- Mejorar — genera o modifica archivos para cerrar las brechas. Las recetas están en
AGENTS.md. - Paso de metadatos — invoca
metadata-checken cada cadena corta que la skill generó (títulos, descripciones, camposdescriptionde schema, respuestas de FAQ, extractos de frontmatter). - Verificar — ejecuta la compilación, comprueba que las validaciones pasan, recuerda al usuario sobre tareas que no son de archivo (Search Console, Bing Webmaster Tools, verificación de clave IndexNow).
Fase 0: Detectar el proyecto
Confirma los conceptos básicos antes de auditar:
astro.config.mjs/astro.config.tsexiste.package.jsontieneastrocomo dependencia.site:está configurado enastro.config— las URL canónicas, mapas del sitio y URL de imágenes OG se derivan de esto. Si falta, está vacío o eshttp://localhost, márcalo como un problema bloqueante antes que cualquier otra cosa. Esta es la mala configuración más común.- Colecciones de contenido en
src/content/(osrc/pages/markdown heredado). - Destino de despliegue — lee
package.json,vercel.json,netlify.toml,wrangler.tomlopublic/_headerspara determinar el host. Esto impulsa la sintaxis de redirecciones y cabeceras en la Fase 2. - ¿Ya está instalado
@jdevalk/astro-seo-graph? Si es así, registra la versión y qué características están conectadas (busca<Seo,seoGraph(,createSchemaEndpoint,createSchemaMap,FuzzyRedirect,createIndexNowKeyRoute,createMarkdownEndpoint,createApiCatalog,gitLastmod). Comprueba la versión instalada frente a la última en npm connpm view @jdevalk/astro-seo-graph version. Si el proyecto está desactualizado, recomienda una actualización en la Fase 2 antes de auditar las brechas de funcionalidad — el paquete publica nuevos valores predeterminados y correcciones con regularidad, y una versión desactualizada es una causa plausible de cualquier hallazgo de auditoría. La Fase 2 se bifurca en esto. - ¿El sitio es multilingüe? Comprueba si hay
i18nenastro.configo múltiples directorios de locale bajosrc/content/. Si es así, el hreflang importa; si no, omítelo.
Pregunta solo lo que no puedas detectar. No le preguntes al usuario de qué trata el sitio — lee astro.config.mjs y el contenido de la página de inicio.
Fase 1: Auditoría
Puntúa cada categoría sobre 10. Para cada una, da de 2 a 4 hallazgos específicos que citen el código o la configuración real. Dentro de cada categoría, las comprobaciones están por niveles:
- Debe — bloqueadores de publicación. Un fallo aquí causa una regresión SEO visible.
- Debería — práctica estándar. Omitirlo cuesta alcance.
- Opcional — con visión de futuro o situacional. Útil pero no es la base para cada sitio.
Omite las comprobaciones Opcional para pequeños blogs personales a menos que el usuario solicite el tratamiento completo.
1. Componente <Seo> y metadatos de cabecera (/10)
- Debe — componente único para todos los metadatos de cabecera (no disperso en varios layouts).
- Debe —
site:enastro.configestá configurado al origen de producción. - Debe — URL canónicas derivadas de la configuración
sitecon parámetros de seguimiento eliminados. - Debe — se omite la canónica cuando
noindexes verdadero (según la recomendación de Google). - Debe — cadena de respaldo para campos SEO faltantes:
seo.title → title → siteName;seo.description → excerpt → first paragraph. Las páginas con títulos o descripciones en blanco son el síntoma más común de una cadena de respaldo rota. - Debería — el meta
robotsincluyemax-snippet:-1,max-image-preview:large,max-video-preview:-1. - Debería — etiquetas de Twitter suprimidas cuando duplican Open Graph (Twitter recurre automáticamente).
- Debería — alternativas
hreflangpresentes en sitios multilingües. Omitir si es monolingüe. - Opcional — usa el componente
<Seo>de@jdevalk/astro-seo-graphen lugar de uno hecho a mano. (Uno hecho a mano que cubra todo lo anterior está bien; esta skill empuja hacia el paquete porque maneja la cadena de respaldo y las reglas de robots de forma predeterminada.)
2. Datos estructurados / gráfico JSON-LD (/10)
- ¿Un solo objeto
Articleplano, o un@graphenlazado con múltiples entidades? - ¿Entidades conectadas con referencias
@id? - ¿
WebSite,Blog/WebPage,Person/Organization,BlogPosting/Article,BreadcrumbList,ImageObjecttodos presentes donde sea relevante? - ¿Señales de confianza:
publishingPrinciples,copyrightHolder,copyrightYear,knowsAbout,SearchAction? - ¿Valida en Prueba de resultados enriquecidos y ClassySchema?
3. Colecciones de contenido y esquema SEO (/10)
- ¿Colecciones de contenido definidas con esquemas Zod?
- ¿
seoSchemade@jdevalk/astro-seo-graphaplicando longitudes de título (5–120) y descripción (15–160)? - ¿Campos obligatorios (
publishDate,title,excerpt) aplicados en tiempo de compilación? - ¿
articleBodysin markdown expuesto en endpoints de esquema (hasta 10K caracteres)?
4. Imágenes Open Graph (/10)
- ¿Cada página tiene una imagen OG, o faltan muchas?
- ¿1200×675 (Google Discover mínimo 1200px de ancho, relación 16:9)?
- ¿Generada en tiempo de compilación mediante satori + sharp, o manual?
- ¿JPEG (las plataformas sociales no admiten de forma fiable WebP/AVIF)?
- ¿La ruta deriva la URL OG del slug automáticamente?
- ¿Cada
<img>en el HTML renderizado tiene un atributoalt(oalt=""/role="presentation"para imágenes decorativas)?validateImageAltenseoGraph()lo detecta en tiempo de compilación en ≥ 1.1.0.
5. Mapas del sitio e indexación (/10)
- Debe —
@astrojs/sitemapinstalado, índice del mapa del sitio accesible. - Debe —
robots.txtreferencia el índice del mapa del sitio. - Debe — existe feed RSS (
@astrojs/rss), anunciado mediante<link rel="alternate" type="application/rss+xml">, contiene el contenido completo de la publicación (no extractos truncados). - Debería — dividido por colección mediante la opción
chunks(sitemap-posts-0.xml, etc.) — mucho más fácil de depurar la indexación en GSC. - Debería —
lastmodpoblado a partir de marcas de tiempo de commits de git, no de fechas de frontmatter o marcas de tiempo de archivos de CI.@jdevalk/astro-seo-graph≥ 1.4.0 exportagitLastmod(filePath, { excludeCommits, depth })para esto — devuelve la fecha del committer del commit no excluido más reciente que tocó el archivo, onullsi git no está disponible. Conéctalo en la devolución de llamadaserializedel mapa del sitio. Si el código base tiene un helperexecSync('git log ...')hecho a mano, reemplázalo con la exportación del paquete — la exportación maneja la exclusión de commits masivos (importaciones, reformateos) que una búsqueda ingenua con-1no puede. - Debería — IndexNow integrado y enviando en cada compilación, con ruta de verificación de clave en
/[key].txt. ≥ 1.0.1 excluye/404de los envíos de forma predeterminada. Limita el envío al host de producción (por ejemplo,process.env.CF_PAGES === '1' && CF_PAGES_BRANCH === 'main',VERCEL_ENV === 'production',CONTEXT === 'production'). El envío incondicional hace ping al endpoint en cadanpm run buildlocal y despliegue de vista previa con URL que el host de producción aún no ha servido, lo que marca la clave como no válida (403) y fuerza la rotación.
6. Descubrimiento de agentes (/10)
- Debería — endpoints de esquema (
/schema/*.json) que exponen JSON-LD de todo el corpus. - Debería — mapa de esquema (
/schemamap.xml) que enumera todos los endpoints, con directivaSchemamap:enrobots.txt. - Debería —
llms.txten la raíz del sitio que enumera páginas (título + descripción) para consumidores LLM.@jdevalk/astro-seo-graph≥ 0.9.0 genera esto mediante la opción de integraciónllmsTxt. - Debería — URL alternativas en markdown (
/blog/post.mdjunto a/blog/post/) que sirven markdown limpio con frontmatter YAML para que los agentes de IA lo consuman sin análisis HTML.@jdevalk/astro-seo-graph≥ 1.2.0 incluyecreateMarkdownEndpointpara la ruta y una opción de integraciónmarkdownAlternate: trueque emite<link rel="alternate" type="text/markdown">en cada página. ≥ 1.3.0 agrega verificación posterior a la compilación: la integración recorre la salida de la compilación y elimina cualquier enlace cuyo destino.mdno esté en el disco (con unwarnpor ocurrencia) — por lo que un endpoint mal configurado aparece como una advertencia de compilación en lugar de un 404 enviado. Combínalo con una regla de transformación de Cloudflare (reescritura de URL mediantewildcard_replace, sin cabeceraVary: Accept— CF elimina valores Vary personalizados) para la negociación de contenido enAccept: text/markdownsin necesidad de SSR. - Debería — catálogo de API en
/.well-known/api-catalogsegún RFC 9727.@jdevalk/astro-seo-graph≥ 1.4.0 incluyecreateApiCatalog, que asigna automáticamente tipo a los endpoints de esquema a sus URLhttps://schema.org/<Tipo>y absolutiza las rutas contrasiteUrl. Enumera los endpoints de esquema, el mapa de esquema y cualquier API específica del sitio (/ask,/feed.xml, etc.). La RFC está finalizada, por lo que el formato es estable; la adopción es temprana pero el costo es un archivo de ruta. - Debería — directiva Content Signals en
robots.txt(por ejemplo,Content-Signal: ai-train=yes, search=yes, ai-input=yes). Declara preferencias para el entrenamiento de IA, la base de búsqueda y el uso de entrada de IA independientemente del acceso de rastreo. La especificación es un borrador de IETF y la adopción es temprana, pero es una línea en un archivo que todo sitio ya tiene. - Debería — cabecera
Linken/*que apunta a archivos de descubrimiento (mapa del sitio, llms.txt, api-catalog, schemamap y cualquier tarjeta MCP/A2A que el sitio publique). Los agentes que leen las cabeceras de respuesta los encuentran sin analizar HTML. En Cloudflare Pages / Netlify esto espublic/_headers; en Vercel esvercel.json. - Opcional — tarjeta de servidor MCP en
/.well-known/mcp/server-card.json(SEP-1649) y/o tarjeta de agente A2A en/.well-known/agent-card.json(protocolo A2A). Solo relevante cuando el sitio realmente expone un servidor MCP o un agente A2A. Ambos son archivos JSON estáticos que declaran el endpoint, las capacidades y las habilidades. Omitir en caso contrario. - Opcional —
<link rel="nlweb">que apunta a un endpoint conversacional. NLWeb es temprano; la etiqueta es una línea y vale la pena tenerla, pero no es un bloqueador de puntuación en 2026. - Opcional — catálogo ARD (Agentic Resource Discovery) en
/.well-known/ai-catalog.json, que enumera lo que ofrece el dominio (servidor MCP, agente A2A, paquete OKF, API específicas del sitio). Borrador v0.9, por lo tanto opcional — pero es la capa de descubrimiento a través de la cual las tarjetas MCP/A2A y el paquete OKF dan sus frutos. Dos trampas: la especificación base (Agent-Card/ai-catalog) nombra el campo de tipo de mediomediaTypemientras que la capa ARD (ards-project/ard-spec) lo nombratype— emite ambas claves con el mismo valor para que la entrada se valide bajo cualquier lectura (ambas especificaciones requieren que los consumidores ignoren las claves desconocidas). ARD también agrega una matriz opcionalrepresentativeQueriesde prompts de muestra por entrada. - Opcional — paquete OKF (Open Knowledge Format): un árbol de archivos Markdown de concepto con tipo (uno por página, rutas que reflejan URL canónicas) empaquetado como un solo
.tar.gz, con archivos de índice entre ellos. Servir y descubrir son objetivos no explícitos de OKF — para eso sirve la entrada del catálogo ARD. Borrador v0.9, opcional. Aún no hay un tipo de medio registrado, por lo que la cadena provisional esapplication/okf-bundle+gzip(seguimiento en knowledge-catalog#111 y ard-spec#27); márcalo como provisional, puede cambiar. Es mejor generarlo como una salida más de un canal de contenido existente en lugar de una copia mantenida manualmente.
7. Rendimiento (/10)
- ¿Salida estática de forma predeterminada (sin SSR en páginas que no lo necesitan)?
- ¿Cero JS del lado del cliente a menos que una isla lo requiera?
- ¿Componente
<Image>de Astro usado para todas las imágenes de contenido (srcset responsivo, WebP, lazy, async)? - ¿Fuente web principal precargada en woff2?
- ¿
<ClientRouter />condefaultStrategy: 'viewport'para precarga? - ¿Activos con hash bajo
/_astro/sirvenCache-Control: public, max-age=31536000, immutable? - ¿Cabecera de respuesta
No-Vary-Searchque elimina los parámetros UTM de la clave de caché?
8. Redirecciones y manejo de errores (/10)
- ¿
public/_redirects(o equivalente) mantenido para cada URL que alguna vez existió y se movió? - ¿301 no 302 para movimientos permanentes?
- ¿Componente
FuzzyRedirectde@jdevalk/astro-seo-graphconectado en la página 404? - ¿La propia página 404 devuelve un estado 404, no 200?
9. Validación en tiempo de compilación y calidad del contenido (/10)
- Debe — integración
seoGraph()ejecutándose en cada compilación convalidateH1yvalidateUniqueMetadatahabilitados. Para la validación JSON-LD, pasawarnOnDanglingReferences: trueaassembleGraph()enseo-graph-core— esa es la comprobación en tiempo de ensamblaje, no una opción de integración. - Debería —
validateImageAlt,validateMetadataLengthyvalidateInternalLinkshabilitados enseoGraph()(todos predeterminadostrueen ≥ 1.1.0). Detectan texto alternativo faltante, títulos o descripciones fuera de los límites de SERP (predeterminados: título 30–65, descripción 70–200), y enlaces internos que dan 404 o encuentran una discrepancia de barra inclinada final. Actualiza a ≥ 1.1.1 si el proyecto está en 1.1.0 — esa versión de parche corrige dos errores de validador:validateInternalLinksahora reconoce los activos depublic/como destinos válidos (no más falsos positivos en/images/*o/fonts/*), yvalidateMetadataLengthya no trunca las descripciones que contienen …
[truncado para la traducción]