Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ivanespinosa/esg-mexico-sitio-web/llms.txt

Use this file to discover all available pages before exploring further.

Esta página documenta los hallazgos de la auditoría técnica SEO realizada el 2 de julio de 2026 sobre el sitio esgmexico.net (Astro v6.4.7 + Sanity CMS + Vercel). La auditoría analizó las rutas /, /blog, /servicios-esg y un artículo de blog representativo. Los hallazgos se agrupan en tres niveles de prioridad: P0 críticos (rompen la indexación), P1 altos (degradan rendimiento y snippets), y P2 medios (oportunidades de mejora en datos estructurados y on-page). Los issues P0 deben resolverse antes de cualquier otra optimización.

Resumen ejecutivo

El sitio migró correctamente a Astro con generación estática (HTML completo servido al crawler), pero arrastra un bug crítico de generación de URLs canónicas que afecta a todo el blog, una inconsistencia de host www vs no-www que divide señales de autoridad, e imágenes servidas a tamaño original desde Sanity CDN (hasta 7,900×5,269 px) que degradan el rendimiento. Adicionalmente faltan datos estructurados JSON-LD, los meta descriptions del blog se autogeneran truncados, y hay deuda menor en Open Graph y H1 duplicados. Orden de ataque: P0 (canonicals) → P0 (host único + redirects) → P1 (imágenes Sanity) → P1 (meta descriptions) → P2 (JSON-LD, og:type, H1).

P0-1 · Canonical, og:url y og:image malformados en todo el blog

Este bug invalida los canonicals de todos los artículos del blog. Google recibe URLs del tipo https://esgmexico.nethttps://esgmexico.net/blog/... y no puede indexar el contenido correctamente. Resolver antes de cualquier otra tarea SEO.

Evidencia observada

En /blog y en cada artículo, las URLs se generan con doble concatenación del dominio:
<link rel="canonical" href="https://esgmexico.nethttps://esgmexico.net/blog">
<meta property="og:url" content="https://esgmexico.nethttps://esgmexico.net/blog/marzo2026_formula_1...">
<meta property="og:image" content="https://esgmexico.nethttps://cdn.sanity.io/images/[project]/production/[hash].jpg">
Las páginas principales (home, servicios) no tienen este bug — sus canonicals son válidos. El bug vive en el layout o componente SEO usado por las rutas del blog.

Impacto

  1. Google recibe canonicals inválidos en los ~28+ artículos → indexación degradada, riesgo de que Google elija canonicals propios o trate el contenido como duplicado.
  2. og:url roto → los crawlers de redes sociales no consolidan señales de compartido en la URL real.
  3. og:image roto → al compartir artículos en LinkedIn/WhatsApp/Facebook no aparece imagen de preview, con impacto directo en CTR.

Causa raíz

Concatenación de Astro.site (string absoluto) con una URL que ya es absoluta. Patrón típico del bug:
---
// ❌ INCORRECTO
// Astro.url ya es una URL absoluta; Astro.site también lo es.
// La concatenación produce "https://esgmexico.nethttps://esgmexico.net/..."
const canonical = `${Astro.site}${Astro.url}`;
const ogImage   = `${Astro.site}${post.mainImage.url}`;
---

Fix: usar new URL() para construir URLs seguras

---
// ✅ CORRECTO — new URL() acepta una base y nunca duplica el origen

// Canonical: toma solo el pathname de la URL actual y lo combina con el site
const canonicalURL = new URL(Astro.url.pathname, Astro.site);

// og:image: si la URL ya es absoluta (Sanity CDN o http externo), usarla tal cual.
// Solo prefijar el sitio si es una ruta relativa local (ej. "/og-default.jpg").
function absoluteImage(img: string | undefined, fallback = "/og-default.jpg") {
  const src = img ?? fallback;
  return src.startsWith("http") ? src : new URL(src, Astro.site).href;
}

const ogImage = absoluteImage(post?.mainImage?.url);
---
<link rel="canonical" href={canonicalURL} />
<meta property="og:url"   content={canonicalURL} />
<meta property="og:image" content={ogImage} />
Comandos para localizar todas las ocurrencias del bug antes de corregirlas:
# Encontrar concatenaciones de Astro.site sin new URL()
grep -rn "Astro.site" src/ | grep -v "new URL"

# Detectar usos directos de Astro.url (sin .pathname)
grep -rn 'Astro\.url[^.]' src/

Implementación actual en SEO.astro

El componente src/components/SEO.astro ya implementa el patrón correcto con new URL():
---
// src/components/SEO.astro — fragmento relevante
const siteUrl = Astro.site
  ? Astro.site.href.replace(/\/$/, "")
  : "https://www.esgmexico.net";

// Acepta canonical absoluto o relativo; fallback al pathname actual
const canonicalUrl = canonical
  ? canonical.startsWith("http")
    ? canonical
    : `${siteUrl}${canonical}`
  : `${siteUrl}${Astro.url.pathname}`;

// Acepta URL absoluta de Sanity CDN o ruta local relativa
const ogImageUrl = ogImage.startsWith("http")
  ? ogImage
  : `${siteUrl}${ogImage}`;
---
Verificar que todos los layouts del blog pasen canonical y ogImage correctos a este componente, sin hacer pre-concatenación propia antes de pasarlos.

Criterios de aceptación

  • curl -s https://www.esgmexico.net/blog | grep canonical devuelve una sola URL válida sin duplicación.
  • Todos los artículos tienen canonical, og:url y og:image válidos.
  • Validar 2–3 artículos en opengraph.xyz o el Post Inspector de LinkedIn: el preview muestra imagen.
  • El sitemap.xml no contiene URLs con doble dominio (comprobar con grep "nethttps" dist/sitemap.xml).

P0-2 · Inconsistencia de host www vs no-www + trailing slash

Los canonicals de home y servicios apuntan a https://esgmexico.net (sin www) mientras el sitio sirve en https://www.esgmexico.net. Google puede indexar ambos hosts, dividir la autoridad de enlace y desperdiciar crawl budget en redirects o contenido duplicado.

Evidencia observada

  • El sitio sirve en https://www.esgmexico.net.
  • Los canonicals de home y servicios apuntan a https://esgmexico.net (sin www).
  • El canonical de /servicios-esg incluye trailing slash (/servicios-esg/) mientras los enlaces internos usan /servicios-esg (sin slash).

Fix

1. Alinear astro.config.mjs con el host canónico elegido (www):
// astro.config.mjs
export default defineConfig({
  site: "https://www.esgmexico.net", // ✅ con www, sin trailing slash
  trailingSlash: "never",            // ✅ política uniforme de slash
  adapter: vercel(),
  // ...
});
2. Redirect 301 en vercel.json — ya implementado correctamente:
{
  "redirects": [
    {
      "source": "/:path*",
      "has": [{ "type": "host", "value": "esgmexico.net" }],
      "destination": "https://www.esgmexico.net/:path*",
      "permanent": true
    }
  ]
}
3. Verificar en el dashboard de Vercel que esgmexico.net esté configurado como redirect al dominio principal, no como alias que sirve contenido duplicado.4. Regenerar el sitemap tras el fix para que use el host canónico con www.

Criterios de aceptación

  • curl -sI https://esgmexico.net/ devuelve 301 con Location: https://www.esgmexico.net/.
  • curl -sI https://esgmexico.net/blog → 301 a la ruta equivalente en www.
  • Todos los canonicals usan el mismo host y la misma política de slash que los enlaces internos.
  • grep -r "esgmexico.net" dist/ | grep -v "www.esgmexico" no arroja resultados.

Robots.txt y Sitemap

El archivo public/robots.txt permite el crawl general y referencia el sitemap:
public/robots.txt
User-agent: *
Allow: /

Sitemap: https://www.esgmexico.net/sitemap.xml
El sitemap se genera dinámicamente en src/pages/sitemap.xml.ts, que combina páginas estáticas y artículos del blog obtenidos vía getCollection("blog"). Tras resolver P0-1 y P0-2, verificar que el sitemap resultante no contenga URLs con doble dominio:
# Verificar que el sitemap generado no tiene el bug de doble dominio
grep "nethttps" dist/sitemap.xml && echo "BUG ENCONTRADO" || echo "OK"

# Verificar que todos los URLs usan www
grep -c "www.esgmexico.net" dist/sitemap.xml
El sitemap cubre 10 páginas estáticas (home, nosotros, servicios, cumplimiento y sus sub-rutas, blog) más todos los artículos del blog con lastmod calculado desde el campo date de cada post. Enviar el sitemap en Google Search Console tras desplegar los fixes P0.

Plan de ejecución

1

Sesión 1 — P0 (urgente, hoy)

  1. Localizar y corregir la concatenación de canonical/og:url/og:image con grep -rn "Astro.site" src/ | grep -v "new URL".
  2. Verificar que astro.config.mjs tenga site: "https://www.esgmexico.net" y trailingSlash: "never".
  3. Confirmar el redirect 301 no-www → www en vercel.json.
  4. Build local + grep sobre dist/ para validar que no queda ninguna URL con doble dominio.
  5. Deploy + validar con curl y LinkedIn Post Inspector.
2

Sesión 2 — P1 (rendimiento)

  1. Usar sanityImg() y sanitySrcset() en todas las tarjetas del blog y heroes de artículos.
  2. Agregar campo excerpt en Sanity + usar metaDescription() de src/lib/seo.ts en todos los layouts del blog.
  3. Correr PageSpeed Insights antes/después y documentar el delta de LCP.
3

Sesión 3 — P2 (datos estructurados y on-page)

  1. Verificar que el JSON-LD de SEO.astro se renderiza en todas las páginas y agregar Article + BreadcrumbList en los layouts de post.
  2. Pasar ogType="article", articlePublishedTime y articleAuthor desde los layouts de blog.
  3. Reemplazar alt texts de logos de clientes por nombres reales.
  4. Activar validación de slug kebab-case en el schema de Sanity para posts nuevos.
  5. Limpiar H1 duplicado (editorial o defensivo en código).
4

Sesión 4 — P3 (verificaciones y menores)

  1. Enviar el sitemap en Google Search Console y solicitar reindexación de páginas principales.
  2. Auditar headers de seguridad en securityheaders.com — ya implementados en vercel.json.
  3. Newsletter footer: agregar <label> y referencia al aviso de privacidad.
  4. Ofuscar email buzon@esgmexico.net del footer contra harvesting de spam.
  5. Verificar aria-hidden="true" en la navegación duplicada (desktop/móvil).

Build docs developers (and LLMs) love