Skip to content

Verificar analytics da landing com Google Analytics (GA4/gtag) + receita de origins na doc #456

@milkway

Description

@milkway

Objetivo

Verificar, ponta a ponta com uma propriedade GA4 real, se o recurso de
analytics da landing (#57) funciona com o Google Analytics (gtag.js), além
do Plausible/Matomo que motivaram a feature. O foco é a CSP — se os beacons do
GA chegam ao destino ou são bloqueados silenciosamente.

Como o recurso funciona hoje (levantado no código)

  • Injeção: templates/landing.html (L12-13) emite analytics-html verbatim
    (|safe) no <head> da landing. Um <script> colado ali sobrevive. ✓
  • CSP base (lib.rs::content_security_policy):
    • script-src 'self' 'unsafe-inline' 'unsafe-eval'{extra} → o inline gtag(...)
      já é permitido pelo 'unsafe-inline'. ✓
    • connect-src 'self'{extra} e img-src 'self' data:{extra}.
  • Widening: routes/landing.rs (L286-294) injeta a CSP da landing com
    analytics-origins adicionado a script-src, connect-src e img-src
    (security_headers respeita o valor setado pelo handler via or_insert).
  • Sanitização (sanitize_csp_origins/is_safe_csp_source): aceita
    [scheme://][*.]host[:port][/path]curinga de subdomínio *. é aceito
    (ex.: https://*.analytics.google.com); só o * solto é rejeitado. ✓

Conclusão preliminar (a confirmar no teste real)

Tecnicamente GA4 deve funcionar, MAS só se o operador listar todos os
domínios certos em analytics-origins. O risco concreto:

  • GA4 carrega o script de https://www.googletagmanager.com (→ script-src).
  • O inline gtag('config', ...) roda ('unsafe-inline'). ✓
  • Os beacons de coleta vão para https://www.google-analytics.com /
    https://*.google-analytics.com / https://*.analytics.google.com
    (→ connect-src). Se o operador listar só o googletagmanager.com, os
    beacons são bloqueados pela CSP e o GA falha em silêncio.

Ou seja: provavelmente não é bug de código, e sim uma lacuna de
documentação/UX (a string de origins do GA é não-óbvia e multi-domínio).

Tarefas

  • Teste real: criar uma propriedade GA4, colar o snippet gtag em
    analytics-html, listar os origins e abrir a landing em um navegador;
    confirmar no DevTools (Network/Console) que (a) o gtag/js carrega,
    (b) não há violação de CSP, (c) o collect chega ao GA (e aparece no
    Realtime do GA).
  • Descobrir a lista mínima de origins necessária na prática (GA4 às vezes
    usa endpoints regionais region1.google-analytics.com, daí o curinga).
  • Documentar uma receita copy-paste de GA4 em docs/YAML_SCHEMA.md
    (hoje o exemplo só cobre Plausible), incluindo o analytics-origins
    completo, por ex.:
    analytics-origins: "https://www.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com"
  • (Opcional) Validação/UX no admin: se analytics-html parece um snippet GA
    (contém googletagmanager.com/gtag) mas analytics-origins não inclui um
    domínio google-analytics.com, mostrar um aviso "faltam origins de coleta".
  • (Opcional) Adicionar um teste cobrindo o cenário GA (origins curinga
    sobrevivem ao sanitize_csp_origins e caem em connect-src/script-src/img-src).

Arquivos relevantes

  • crates/ruscker-admin/templates/landing.html (L12-13)
  • crates/ruscker-admin/src/lib.rs (content_security_policy, sanitize_csp_origins, is_safe_csp_source)
  • crates/ruscker-admin/src/routes/landing.rs (L286-294 widening)
  • crates/ruscker-config/src/schema.rs (analytics-html, analytics-origins)
  • docs/YAML_SCHEMA.md (exemplo de analytics — só Plausible hoje)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:adminruscker-admin cratekind:docsDocs changepriority:lowBacklog — nice-to-have, not blockingquestionFurther information is requested

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions