← 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 />, no se requiere configuración adicional — pero vale la pena ser preciso sobre por qué, porque la explicación habitual es incorrecta.

El tracker no escucha astro:page-load ni ningún otro evento del ciclo de vida de Astro. Aplica un parche a history.pushState cuando carga. El enrutador de Astro actualiza la URL mediante esa misma llamada a la History API, así que la función parcheada se ejecuta en cada transición y envía un pageview. El hook queda por debajo de la capa de eventos de Astro en lugar de escucharla.

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.

Una advertencia importante: el hook cubre pushState, no popstate. Pulsar Atrás o Adelante en el navegador cambia la ruta sin llamar a pushState, por lo que actualmente no produce un nuevo pageview.

El tracker no expone ningún método manual de pageview. El global solo acepta eventos personalizados:

<script>
  // Solo eventos personalizados — no existe una llamada trackPageview().
  // El nombre debe coincidir con [a-z0-9_][a-z0-9_-]{0,63}.
  window.monoid('event', 'signup_started');
</script>

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.

Fuentes

Comments

Loading comments…