Sessionization no GA4 e BigQuery: como ler sessões de verdade

\"Sessionization

Sessão no GA4 parece objeto simples até você exportar eventos para BigQuery e descobrir que session_id, ga_session_id e lógica da UI não são a mesma coisa. Sessionization — agrupar hits em sessões com regras consistentes — é pré-requisito para funis, atribuição e análises que a interface do GA4 não entrega ou entrega com definição opaca. No warehouse, você controla timeout, exclusões e critérios — e assume responsabilidade quando divergir da UI.

Hits agrupados em sessoes no warehouse
Hits agrupados em sessoes no warehouse

Como o GA4 define sessão nativamente?

GA4 agrupa eventos em sessões com base em ga_session_id gerado client-side, com timeout de 30 minutos de inatividade (configurável via session_timeout). Nova campanha com UTM pode iniciar nova sessão dependendo de configuração. Sessões encerram à meia-noite no timezone da propriedade.

Na UI, métricas de sessão refletem essa lógica. No BigQuery export, cada evento traz ga_session_id, session_engaged e parâmetros de traffic source. Porém, export não entrega tabela de sessões pronta — você recebe eventos e reconstrói sessões via SQL.

O que muda quando você sessioniza no BigQuery?

Controle total: timeout custom (45 min para SaaS, 10 min para e-commerce flash), exclusão de eventos (internal traffic, bots), regras de atribuição de campanha à sessão, e sessões cross-device se tiver user_id. Também responsabilidade total: número não baterá com UI se lógica diferir — e isso precisa ser comunicado.

Casos que exigem sessionization custom: funil multi-step com eventos específicos, sessão definida por engagement mínimo (2+ pageviews), atribuição first-touch por sessão, análise de landing page excluindo redirects. UI do GA4 não flexibiliza essas regras.

  • ga_session_id como base, com override se necessário
  • Timeout de inatividade documentado
  • Regra de meia-noite e timezone explícitos
  • Critério de sessão engajada (session_engaged ou custom)
  • Tratamento de user_id para stitch cross-session

Qual SQL prático para sessionization no export GA4?

Abordagem comum: window functions sobre events_* particionado por user_pseudo_id (e user_id quando disponível). LAG(event_timestamp) para calcular gap; quando gap > timeout ou data muda, incrementar session_number. Gerar surrogate session_key = hash(user + session_number + date).

Alternativa: usar ga_session_id nativo quando lógica default basta — mais simples, alinha com UI. Custom sessionization só quando regra de negócio exige. Sempre compare totais com UI GA4 para mesma janela antes de confiar.

AbordagemPrósContrasQuando usar
ga_session_id nativoAlinha com UI, SQL simplesSem flexibilidade de timeoutReporting padrão
Custom timeoutControle de inatividadeDiverge da UISaaS com sessões longas
Engagement-basedFiltra bounce noiseDefinição subjetivaFunis de qualidade
user_id stitchCross-device parcialRequer loginProdutos autenticados
Campanha-forced new sessionAtribuição agressivaInfla session countTestes de atribuição

Como tratar engaged session vs sessão bruta?

GA4 define engaged session como ≥10s, ou ≥2 pageviews, ou conversion event. Parâmetro session_engaged=1 no export. Para funis de qualidade, filtre engaged sessions — sessões de 1 segundo distorcem bounce rate e pages/session.

Documente qual definição alimenta qual dashboard. Executivo pode ver sessões totais; operacional de CRO vê engaged only. Misturar definições no mesmo relatório gera confusão.

Quais armadilhas de sessionization no BigQuery?

Timezone: event_timestamp é UTC; sessão por ‘dia’ depende de conversão correta. Particionamento: queries sem filtro de _TABLE_SUFFIX escaneiam tudo — custo e timeout. Unnest de event_params sem cuidado multiplica rows. user_pseudo_id muda com consent — sessões fragmentadas pós-denial.

Cross-device sem user_id: não tente sessionizar como se tivesse identidade unificada. Dois dispositivos = duas sessões, dois usuários — a menos que login com user_id unifique.

Como validar sessões modeladas vs GA4 UI?

Compare sessions, engaged_sessions e average_session_duration por date para últimos 7 dias. Divergência <5% é aceitável (processing delay, definição). >10% exige investigação: timezone, filtros, internal traffic exclusion na UI mas não no SQL.

Automatize reconciliação diária como dbt test. Quando divergir, marketing precisa saber qual número é ‘oficial’ — documente que warehouse usa definição X, UI usa definição Y.

  • Reconciliar sessions by date por 7 dias
  • Verificar timezone conversion
  • Confirmar filtros (internal, bots) consistentes
  • Testar impacto de consent na contagem
  • Documentar divergência aceitável e causa

Como evoluir de sessão para jornada e funil?

Com sessões modeladas, construa funil: within session (step1 → step2 → step3) ou cross-session (sessão 1 view → sessão 2 signup). Window functions PARTITION BY session_key ORDER BY event_timestamp. Para cross-session, PARTITION BY user_pseudo_id com janela de atribuição (7d, 30d).

Materialize tabela fct_sessions com session_key, start/end timestamp, landing page, campaign, engaged flag, conversion flag. Funis e atribuição consomem essa fato — não re-sessionizam a cada query.

Checklist prático

  • Definição de sessão documentada (timeout, engaged, timezone)
  • Abordagem escolhida: ga_session_id nativo vs custom
  • SQL de sessionization versionado em dbt model
  • Reconciliação diária sessions vs GA4 UI
  • Tabela fct_sessions materializada com grain claro
  • Tratamento de user_id para produtos autenticados
  • Particionamento e filtro de data em toda query
  • Comunicação ao time sobre divergência vs UI

Erros comuns

  • Assumir session_id do export = sessão da UI sem validar
  • Query full-scan em events_* sem filtro de partição
  • Sessionizar cross-device sem user_id
  • Ignorar timezone na agregação diária
  • Unnest event_params gerando duplicatas na sessão
  • Mudar regra de sessionization sem versionar dashboards

Sessão no GA4 não bate com sua lógica?

A DataScroll modela sessões no BigQuery com critérios claros para análises que a UI do GA4 não resolve.

Modelar sessões no BQ Falar com a DataScroll

Perguntas frequentes

▸ga_session_id basta para a maioria dos casos?

Sim — se você aceita a definição de sessão do GA4 (30min timeout, meia-noite, campanha pode reiniciar). Alinha com UI, SQL mínimo. Custom sessionization só quando regra de negócio exige divergir.

▸Por que sessões no BQ diferem da UI?

Processing delay (24-48h), filtros de internal traffic na UI, timezone, sampling em relatórios UI (não no export), ou lógica custom no SQL. Compare após 48h de lag; divergência >10% investigue.

▸Como sessionizar app + web?

GA4 property unificada gera ga_session_id por stream. No BQ, stream_id identifica origem. Cross-platform session (web → app) exige user_id comum — sem isso, são sessões independentes.

▸Session timeout custom recomendado?

Depende do produto: e-commerce 30min default; SaaS com demos longas 60-120min; media 15min. Justifique com distribuição de gap entre eventos no seu dado — não copie default sem analisar.

▸events_* vs events_intraday_*?

intraday atualiza ao longo do dia (incompleto); events_* é final (24-48h delay). Use intraday para monitoramento; events_* para reporting oficial e reconciliação.

▸Como excluir bots na sessionization?

Filtre traffic_source.medium=’bot’ ou lista de user_agent conhecidos antes de agrupar. GA4 tem filtro de bot na UI — replique no SQL se quer paridade.

▸Materialized view ou dbt model?

dbt model incremental com partition por date é padrão mid-market — controle, tests, lineage. Materialized view nativa BQ funciona mas menos flexível para lógica complexa.

▸A DataScroll modela sessões no BigQuery?

Sim — sessionization com critérios documentados, reconciliação com GA4 UI e tabela fct_sessions pronta para funis e atribuição custom.