Cómo Agregar Analytics Centrado en la Privacidad a una App SvelteKit
SvelteKit 2 intercepta la navegación del lado del cliente de manera diferente al resto de los frameworks. Este es el patrón correcto para rastrear cambios de ruta sin cookies ni banners de consentimiento.
SvelteKit 2 rompió silenciosamente la mayoría de las integraciones de analytics existentes. Una etiqueta <script> simple que funcionaba bien en SvelteKit 1 solo disparará eventos en recargas completas en SvelteKit 2, perdiendo toda navegación del lado del cliente. La solución habitual — engancharse a history.pushState — tampoco funciona, porque SvelteKit intercepta la navegación a nivel del router antes de que se llame a pushState. El tracker de Monoid gestiona esto correctamente sin configuración adicional.
Por qué el enfoque habitual falla
Los scripts de analytics tradicionales detectan cambios de ruta aplicando monkey-patching a history.pushState y history.replaceState. El router de SvelteKit llama a sus propias primitivas internas de navegación y solo invoca pushState como efecto secundario, después de que la transición de ruta ya está en proceso. Para cuando el pushState parcheado se ejecuta, la nueva ruta puede no haberse renderizado por completo, y en algunos tipos de navegación (llamadas programáticas a goto(), clics en <a> con precarga) el timing genera duplicados o eventos perdidos.
Esta es la causa raíz del problema ampliamente reportado en el que Google Analytics GA4 solo registra el primer pageview en la carga inicial en aplicaciones SvelteKit 2.
El enfoque correcto
Agrega el script del tracker de Monoid una vez en tu +layout.svelte raíz usando <svelte:head>:
<svelte:head>
<script
async
src="https://api.monoid.website/tracker.min.js"
data-site-id="TU_SITE_ID"
></script>
</svelte:head>
El propio listener de DOMContentLoaded del tracker se activa en la carga inicial de la página. Para las navegaciones del lado del cliente posteriores, el hook de history.pushState del tracker se ejecuta después de que la navegación interna de SvelteKit se ha resuelto — lo que significa que cada ruta, incluida la primera, se registra exactamente una vez, sin duplicados ni omisiones.
Para verificarlo, abre la pestaña de Red en DevTools y observa las solicitudes POST hacia /collect. Deberías ver una por cambio de ruta.
Separar el tráfico de staging
Los proyectos SvelteKit suelen ejecutarse en localhost durante el desarrollo. Registra un sitio separado y enlaza su site_id a una variable de entorno para que el tráfico de desarrollo nunca contamine las métricas de producción:
<script>
const siteId = import.meta.env.VITE_MONOID_SITE_ID
</script>
<svelte:head>
{#if siteId}
<script
async
src="https://api.monoid.website/tracker.min.js"
data-site-id={siteId}
></script>
{/if}
</svelte:head>
Define VITE_MONOID_SITE_ID en .env.local para desarrollo (o déjalo sin definir para suprimir el tracking) y en el entorno de deployment para producción. El bloque {#if siteId} asegura que el script del tracker nunca se inyecte cuando la variable no está configurada.
Lo que no necesitas
Sin banner de consentimiento de cookies. Sin actualización de política de cookies. Sin verificación de navigator.cookieEnabled. El endpoint de recolección deriva un hash de visitante diario a partir de la dirección IP, el User-Agent, un secreto del lado del servidor y la fecha actual:
visitor_hash = SHA-256(IP + UA + SALT_SECRET + YYYY-MM-DD)
El hash se reinicia cada 24 horas y no puede revertirse para recuperar la IP o el User-Agent. Nada se almacena en el dispositivo del visitante. Esto significa que la integración no activa los requisitos de consentimiento de ePrivacy o PECR — no hay nada sobre lo que consentir.
Verificar en el dashboard
Después de hacer el deployment, abre tu dashboard de analytics y navega entre varias rutas en tu sitio en producción. Cada navegación debería producir una nueva entrada de pageview con la ruta correcta. Si solo ves una entrada sin importar la navegación, verifica que el script esté cargado en el layout raíz y que VITE_MONOID_SITE_ID esté configurado en el entorno de producción.
El adaptador de SvelteKit que uses (Cloudflare, Vercel, Node, estático) no afecta la recolección de analytics, ya que el tracking ocurre completamente en el navegador después de la hidratación.