Volver al blog

Cómo Agregar Analíticas Respetuosas de la Privacidad a un Sitio Astro

Las View Transitions de Astro rompen los scripts de analíticas estándar en silencio. Aquí está el patrón correcto para rastrear cada cambio de ruta sin cookies ni banners de consentimiento.

Las View Transitions de Astro intercambian el contenido de la página sin una recarga completa del navegador — lo que significa que cualquier script de analíticas que dependa de DOMContentLoaded o load solo se ejecutará una vez, en la visita inicial. Cada navegación posterior del lado del cliente es invisible. Esto no es un error de configuración de tu parte; es una consecuencia fundamental de cómo funciona el ClientRouter.

El mismo problema de rastreo silencioso existe en SvelteKit 2 y Remix, pero la solución en cada framework es diferente. En Astro, la respuesta es el evento de ciclo de vida astro:page-load.

Por qué falla el tag de script habitual

Cuando <ClientRouter /> está activo (opt-in mediante astro:transitions en Astro 4, habilitado por defecto en Astro 5), las navegaciones no descargan la página. Astro obtiene la siguiente página en segundo plano, intercambia el DOM y actualiza la URL — todo sin destruir el contexto JavaScript actual.

Un script de rastreo cargado mediante un tag <script> simple es tratado como un script de módulo empaquetado por el pipeline de build de Astro. Los scripts de módulo empaquetados se ejecutan exactamente una vez por sesión de página. El tracker se inicializa, registra una visita para la página de aterrizaje y luego nunca vuelve a ejecutarse mientras el usuario navega.

Para ejecutarse en cada navegación, la lógica de inicialización debe conectarse al ciclo de vida de navegación de Astro. El hook correcto es astro:page-load, que se dispara después de que la nueva página es visible y todos los scripts de bloqueo están cargados — tanto en la carga inicial como en cada transición posterior.

La integración correcta

Agrega el script de rastreo una sola vez en tu layout raíz (src/layouts/Layout.astro o equivalente), luego adjunta un listener para astro:page-load:

---
// Layout.astro
---
<html lang="es">
  <head>
    <!-- contenido del head -->
  </head>
  <body>
    <slot />

    <script
      is:inline
      src="https://api.monoid.website/tracker.min.js"
      data-site-id="TU_SITE_ID"
      async
    ></script>
  </body>
</html>

La directiva is:inline le indica al bundler de Astro que deje este script exactamente como está. Sin ella, Astro procesaría el script como módulo, lo deduplicaría y suprimiría su re-ejecución. Con is:inline, el tag de script se emite verbatim en el HTML de cada página.

Para sitios que no usan View Transitions, esto es todo lo que necesitas. El tracker se dispara una vez al cargar y listo.

Manejo de la navegación con View Transitions

Si tu sitio usa <ClientRouter />, el hook history.pushState incorporado del tracker se dispara correctamente después de cada transición — el tracker escucha los eventos de navegación de Astro internamente. No se requiere configuración adicional.

Para verificarlo, abre la pestaña Red de DevTools y filtra por collect. Navega entre dos páginas. Deberías ver una solicitud POST por navegación, incluida la carga inicial.

Si inyectas el tracker condicionalmente y necesitas que se reinicialice después de cada intercambio (por ejemplo, después de que una isla dinámica se monta), puedes activar manualmente una re-ejecución:

<script data-astro-rerun>
  // Este bloque se re-ejecuta después de cada View Transition.
  // Úsalo con moderación — la mayor parte de la lógica del tracker no debería ir aquí.
  if (window.__monoid) {
    window.__monoid.trackPageview();
  }
</script>

El atributo data-astro-rerun fuerza a los scripts inline a re-ejecutarse después de cada transición. Ten en cuenta que implica is:inline, por lo que solo aplica a scripts no empaquetados.

Separación de entornos

Los proyectos Astro típicamente tienen entornos de desarrollo local, preview y producción. Usa una variable de entorno para almacenar el site_id y suprimir el rastreo en desarrollo:

---
const siteId = import.meta.env.PUBLIC_MONOID_SITE_ID
---

{siteId && (
  <script
    is:inline
    src="https://api.monoid.website/tracker.min.js"
    data-site-id={siteId}
    async
  ></script>
)}

Configura PUBLIC_MONOID_SITE_ID en .env para producción y déjalo sin definir en local. Astro expone las variables con prefijo PUBLIC_ al cliente; las variables solo del servidor (sin el prefijo) no son visibles en el código ejecutado en el navegador.

Lo que no necesitas

Sin banner de consentimiento de cookies. Sin integración con CMP. El endpoint de recolección calcula un hash diario del visitante a partir de la dirección IP, el User-Agent, un secreto del servidor y la fecha actual:

visitor_hash = SHA-256(IP + UA + SALT_SECRET + YYYY-MM-DD)

El hash se restablece cada 24 horas. Nada se almacena en el dispositivo del visitante. La familia de navegador y el tipo de dispositivo se derivan del lado del servidor desde el User-Agent de la solicitud para los reportes agregados — los strings completos de User-Agent, versiones de navegador e identificadores persistentes nunca se almacenan.

Los sitios Astro suelen ser totalmente estáticos o renderizados en el edge con JavaScript mínimo. Agregar un script de analíticas de menos de 2 KB sin cookies ni requisito de consentimiento encaja naturalmente en esa filosofía. No hay ningún paquete npm que mantener, ningún SDK que actualizar y ninguna base legal del RGPD que documentar para el procesamiento de analíticas.