Analytics que pergunta antes: construindo uma biblioteca de rastreamento só opt-in
Eu quero saber se alguém lê meus sites. Também acredito que rastreamento deveria ser opt-in, mesmo quando a lei diz que não precisa ser. O Umami autohospedado não usa cookies e é isento de banner, então eu poderia legalmente só adicionar o snippet e seguir em frente. Eu não quis. Se o visitante nunca disser sim, meu script de analytics não tem nada a fazer na página dele.
Então construí uma biblioteca pequena que torna o padrão ético o padrão fácil: astro-opt-in-analytics. O script de rastreamento não existe até você consentir. Não desativado. Não pausado. Ausente.
O tracker que nunca foi instalado
A fase de pesquisa revelou algo engraçado. Eu tinha assumido que o vdaluz.com já era rastreado, porque eu tinha feito deploy de um servidor Umami exatamente para esse fim meses atrás. O repositório do site não tinha nenhuma referência ao Umami. O HTML ao vivo confirmou: quatro tags de script, uma delas schema JSON-LD, nenhuma delas um tracker. Eu tinha feito deploy do servidor de analytics e nunca adicionado o snippet ao site. O chamado para fazer isso nem existia.
Esse acidente virou uma vantagem. Nada para migrar, nenhum usuário que já tinha feito opt-out para converter. Os dois sites recebem rastreamento opt-in a partir do primeiro visitante rastreado.
Por que eu não usei uma plataforma de consentimento
Klaro e vanilla-cookieconsent são bons gerenciadores de consentimento open-source, e eu considerei os dois a sério. Eles resolvem um problema diferente: conformidade de cookies multi-fornecedor com granularidade por serviço, enquadramento em frameworks legais, e sua própria UI de modal. Meu problema é um tracker sem cookies e uma pergunta binária. Envolver um CMP teria custado mais código de integração do que o gate inteiro custa para escrever. A biblioteca ficou com cerca de 470 linhas, incluindo os dois componentes.
O design
Dois componentes Astro e um runtime pequeno. ConsentGate lê um registro versionado do localStorage: uma concessão injeta a tag do script de rastreamento, qualquer outra coisa significa que a tag nunca existe. ConsentPrompt é um toast fixo que só aparece quando não há decisão registrada. A resposta é armazenada como { v, decision, at }; suba a versão na config quando o escopo de rastreamento mudar, e decisões antigas voltam a perguntar.
Duas decisões sobre as quais tenho convicção forte.
Global Privacy Control é uma resposta. Se navigator.globalPrivacyControl é true, o visitante já disse não através do navegador dele. O prompt nunca aparece. Pedir para alguém reconsiderar uma preferência que já configurou globalmente é, em si, um dark pattern.
As regras anti-dark-pattern são hard-coded. Botões com o mesmo peso visual, vindos de uma única regra CSS. Recusar vem primeiro na ordem do DOM. Esc significa não. Fechar significa não. Sem overlay, sem scroll lock. Nada disso é configurável. Se você quiser um prompt de consentimento em que “aceitar” brilha e “recusar” se esconde num submenu de configurações, vai ter que dar fork, e o README vai te julgar.
Testando fluxos de consentimento com nada além do Chrome headless
Sem Playwright nesta máquina, e fluxos de consentimento são exatamente o tipo de coisa que precisa de verificação em várias etapas: decidir, reiniciar o navegador, checar se a decisão permaneceu. O truque que fez funcionar: --user-data-dir persiste o localStorage entre invocações headless. Cada “usuário” de teste é um diretório de perfil. A página de teste se conduz sozinha, lendo um query param ?e2e=accept, clicando nos próprios botões, e carimbando o estado observável no DOM como JSON para o --dump-dom capturar.
Falsificar o sinal de GPC também acabou sendo fácil. Um script inline no head roda antes de qualquer módulo empacotado, então Object.defineProperty(navigator, 'globalPrivacyControl', ...) atrás de um query param resolve isso sem precisar de extensão.
Sete fluxos, todos verdes: visitante novo vê o prompt e zero execução de tracker; aceitar injeta e roda o script imediatamente sem reload; a concessão sobrevive a um restart do navegador; recusar não carrega nada, para sempre; GPC significa nenhum prompt e nenhum tracker; o link no rodapé reabre o prompt depois de uma negativa; Esc conta como não. A fixture do tracker falso define uma flag na window para que os testes verifiquem que o script realmente executou, não só que a tag existia.
Uma pegadinha para anotar: o Chrome headless imprime o DOM e depois fica pendurado, segurando o lock do perfil e derrubando a próxima execução com SingletonLock: File exists. A correção é --timeout mais matar sobras entre execuções, e se você matar por padrão a partir de um comando de shell composto, pkill -f "profile[-]a", assim o padrão não bate com a própria linha de comando dele.
Lançado
A v0.1.0 está tagueada e pública, MIT com um arquivo LICENSE de verdade desde o primeiro dia (o pacote do blog ficou meses sem um; lição aprendida). Os dois sites vão consumir ela em seguida como dependências de tarball fixadas por versão. O pitch cabe numa frase: zero requisições até o sim.
Leitura relacionada
Criando uma biblioteca compartilhada de links de afiliados para dois sites
Conformidade por construção: um plugin remark que falha o build quando um link de afiliado sai sem sua divulgação, empacotado do mesmo jeito que os componentes de blog compartilhados.
Entregando um recurso de pacote compartilhado em dois repositórios para uma única rota
Um feed RSS que se dividiu num helper puro no pacote compartilhado e numa rota local por site, além da disciplina de release que uma dependência de tarball fixada por tag exige.
Compartilhando um blog Astro entre dois sites
Você não consegue extrair um blog, mas consegue extrair seus componentes: um contrato de tokens para duas paletas, e as duas mordidas de CI que nunca acontecem num notebook.
Você também pode achar útil
RackNerd VPS
Hospedagem VPS econômica para serviços leves que funcionam continuamente.
Como afiliado da RackNerd, ganho com compras qualificadas.
Saiba maisProton Drive
Armazenamento em nuvem criptografado, da equipe por trás do Proton Mail.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
Saiba maisProton Mail
E-mail criptografado de ponta a ponta, com arquitetura de acesso zero.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
Saiba mais