Como Adicionar Analytics Focado em Privacidade a uma App SvelteKit
O SvelteKit 2 intercepta a navegação client-side de forma diferente dos outros frameworks. Este é o padrão correto para rastrear mudanças de rota sem cookies ou banners de consentimento.
O SvelteKit 2 quebrou silenciosamente a maioria das integrações de analytics existentes. Uma tag <script> simples que funcionava bem no SvelteKit 1 só dispara eventos em recarregamentos completos no SvelteKit 2, perdendo toda navegação client-side. A solução habitual — interceptar history.pushState — também não funciona, porque o SvelteKit intercepta a navegação no nível do router antes de chamar pushState. O tracker do Monoid lida com isso corretamente sem nenhuma configuração adicional.
Por que a abordagem habitual falha
Scripts de analytics tradicionais detectam mudanças de rota aplicando monkey-patching em history.pushState e history.replaceState. O router do SvelteKit chama suas próprias primitivas internas de navegação e só invoca pushState como efeito colateral, depois que a transição de rota já está em andamento. No momento em que o pushState modificado é executado, a nova rota pode não ter sido renderizada por completo, e em alguns tipos de navegação (chamadas programáticas a goto(), cliques em <a> com prefetch) o timing gera duplicatas ou eventos perdidos.
Esta é a causa raiz do problema amplamente relatado em que o Google Analytics GA4 registra apenas o primeiro pageview no carregamento inicial em aplicações SvelteKit 2.
A abordagem correta
Adicione o script do tracker do Monoid uma vez no seu +layout.svelte raiz usando <svelte:head>:
<svelte:head>
<script
async
src="https://api.monoid.website/tracker.min.js"
data-site-id="SEU_SITE_ID"
></script>
</svelte:head>
O próprio listener de DOMContentLoaded do tracker é disparado no carregamento inicial da página. Para navegações client-side subsequentes, o hook de history.pushState do tracker é executado após a navegação interna do SvelteKit ter resolvido — o que significa que cada rota, incluindo a primeira, é registrada exatamente uma vez, sem duplicatas ou omissões.
Para verificar, abra a aba de Rede no DevTools e observe as requisições POST para /collect. Você deve ver uma por mudança de rota.
Separar o tráfego de staging
Projetos SvelteKit geralmente rodam em localhost durante o desenvolvimento. Registre um site separado e vincule seu site_id a uma variável de ambiente para que o tráfego de desenvolvimento nunca contamine as métricas de produção:
<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>
Defina VITE_MONOID_SITE_ID no .env.local para desenvolvimento (ou deixe sem definir para suprimir o tracking) e no ambiente de deploy para produção. O bloco {#if siteId} garante que o script do tracker nunca seja injetado quando a variável não estiver definida.
O que você não precisa
Sem banner de consentimento de cookies. Sem atualização de política de cookies. Sem verificação de navigator.cookieEnabled. O endpoint de coleta deriva um hash de visitante diário a partir do endereço IP, do User-Agent, de um segredo do lado do servidor e da data atual:
visitor_hash = SHA-256(IP + UA + SALT_SECRET + YYYY-MM-DD)
O hash é redefinido a cada 24 horas e não pode ser revertido para recuperar o IP ou o User-Agent. Nada é armazenado no dispositivo do visitante. Isso significa que a integração não aciona os requisitos de consentimento da ePrivacy ou da PECR — não há nada sobre o que consentir.
Verificando no dashboard
Após o deploy, abra seu dashboard de analytics e navegue entre várias rotas no seu site em produção. Cada navegação deve produzir uma nova entrada de pageview com o caminho correto. Se você ver apenas uma entrada independentemente da navegação, verifique se o script está carregado no layout raiz e se VITE_MONOID_SITE_ID está configurado no ambiente de produção.
O adaptador SvelteKit que você usa (Cloudflare, Vercel, Node, estático) não afeta a coleta de analytics, já que o tracking ocorre inteiramente no navegador após a hidratação.