← Voltar ao portfólio
TRACKING ATIVO

GA4 e GTM server-side, aplicados neste próprio site

Tratei o portfólio como um cliente: defini o que medir, implementei, validei e documentei. Enquanto você lê, esta página está sendo medida (se você aceitou os cookies).

5eventos personalizados
3conversões configuradas
2containers GTM (web + server)
LGPDConsent Mode v2 com banner próprio
01 · Arquitetura

Como o dado viaja

Cada clique passa por cinco camadas antes de virar dado analisável. O consentimento do visitante é checado antes de qualquer cookie ser gravado.

Site

Elementos marcados com data-track e um script que envia ao dataLayer

Consentimento

Padrão negado. Banner próprio atualiza o Consent Mode v2

GTM web

Acionadores por evento e uma tag GA4 para cada um

GTM server

Stape em São Paulo, no subdomínio próprio sv.

GA4 + BigQuery

Relatórios, conversões e exportação diária dos eventos brutos

O navegador não fala direto com o Google: as requisições vão para sv.portfoliovinicius.com.br, um servidor sob o meu domínio, que repassa os eventos ao GA4.

GTM web (client-side)

Roda no navegador do visitante. É quem enxerga o que acontece na página.

  • Captura as interações: cliques, downloads, envio de formulário. O servidor não vê a página, então essa parte só pode acontecer no navegador.
  • Respeita o consentimento na origem: lê o Consent Mode antes de gravar qualquer cookie ou enviar dados.
  • Monta o evento: transforma o dataLayer em eventos padronizados, com os parâmetros certos.

GTM server (server-side)

Roda num servidor sob o meu domínio. É quem decide o que sai e para onde.

  • Coleta first-party: o navegador envia para sv.portfoliovinicius.com.br, e não para um domínio do Google, o que reduz perdas por bloqueadores e restrições de navegador.
  • Controle do dado: é possível remover IP, dados pessoais ou parâmetros sensíveis antes de qualquer envio a terceiros.
  • Um evento, vários destinos: o mesmo evento pode ir para GA4, Meta e Google Ads sem carregar um script de cada plataforma na página, o que deixa o site mais leve.

Por que os dois juntos

Um não substitui o outro. O client-side sabe o que o visitante fez; o server-side controla como e para onde esse dado vai. Integrados, cada um cobre a limitação do outro:

Dado mais completoA interação é capturada no navegador, mas enviada para um domínio próprio, o que reduz eventos perdidos por bloqueadores e restrições de navegador.
Privacidade em duas camadasO consentimento é respeitado na origem, e o servidor ainda pode filtrar IP e dados pessoais antes de qualquer envio. Mais fácil de adequar à LGPD.
Site mais leveA página envia um único fluxo de eventos; a distribuição para cada plataforma acontece no servidor, sem um script de cada ferramenta no navegador.
Fácil de escalarNovos destinos (Meta CAPI, Google Ads, um banco próprio) entram no servidor, aproveitando os mesmos eventos, sem mexer no código do site.
02 · Plano de mensuração

O que é medido e por quê

O objetivo do site é simples: o visitante conhecer os projetos e entrar em contato. Os eventos foram escolhidos a partir disso, antes de abrir qualquer ferramenta.

EventoQuando disparaParâmetrosConversão
page_viewToda página carregadapage_location, page_titleNão
view_project_sectionClique em "Ver Mais" ou "Ver Código" nos cards da homesection_nameNão
select_projectClique em "Ver Dashboard" de um projetoproject_name, project_type (web / powerbi)Não
file_downloadDownload do currículo (3 botões)file_name, link_urlSim
contact_clickClique no LinkedIncontact_methodSim
generate_leadFormulário "Fale Comigo" enviado com sucessocontact_method = formularioSim
03 · Implementação

Passo a passo

Cada etapa gerou evidências. Clique nas imagens para ampliar.

Propriedade com fuso de São Paulo e moeda em reais, retenção de dados ampliada para 14 meses e o GA4 carregado só pelo GTM, nunca direto no HTML.

  • Medição aprimorada ajustada: cliques de saída, downloads e interações com formulário desligados, porque esses eventos são tratados pelo GTM com mais controle. Sem isso, cada download seria contado duas vezes.
  • Dimensões personalizadas para section_name, project_name, project_type e contact_method, para os parâmetros aparecerem nos relatórios.
  • Tráfego interno marcado por IP e excluído por filtro de dados, para meus próprios testes não virarem conversões falsas.
  • Eventos principais: file_download, contact_click e generate_lead, sem valor monetário (não há receita num portfólio).
Stream web com a medição aprimorada ajustada
Dimensões personalizadas de escopo Evento
Eventos principais marcados

Em vez de um acionador de clique por elemento, cada link relevante recebe atributos data-, e um único listener envia tudo para o dataLayer. Adicionar um botão novo ao tracking é só colocar um atributo no HTML.

HTML

<a href="/notebooks-dashboard/"
   data-track="select_project"
   data-project="radar-precos-notebooks"
   data-type="web">Ver Dashboard</a>

static/js/tracking.js

document.addEventListener('click', function (e) {
  var el = e.target.closest('[data-track]');
  if (!el) return;

  var payload = {
    event: el.dataset.track,
    section_name: el.dataset.section,
    project_name: el.dataset.project,
    project_type: el.dataset.type,
    file_name: el.dataset.file,
    contact_method: el.dataset.method,
    link_url: el.href
  };

  // Remove parâmetros vazios para não mandar "undefined" ao GA4
  Object.keys(payload).forEach(function (k) {
    if (payload[k] === undefined || payload[k] === '') delete payload[k];
  });

  window.dataLayer.push(payload);
});

No container, um padrão de nomes deixa tudo legível: GA4 - Evento - contact_click, CE - contact_click (acionador de evento personalizado), DLV - project_name (variável da camada de dados), separados em pastas.

Tags, acionadores e variáveis organizados por pasta
Tag de contact_click com seus parâmetros
Histórico de versões publicadas

Um segundo container, do tipo servidor, roda na Stape em São Paulo. O container web passou a enviar os eventos para sv.portfoliovinicius.com.br (parâmetro server_container_url na tag do Google), e o servidor repassa ao GA4.

  • Domínio próprio: registro CNAME na Hostinger apontando para a Stape. A coleta passa a ser primária (first-party), o que é mais resistente a bloqueios.
  • Nome neutro de propósito: o subdomínio é sv, e não metrics ou analytics, que costumam estar nas listas de bloqueadores de anúncio.
  • No servidor: o cliente GA4 recebe a requisição, e uma tag GA4 com acionador Client Name = GA4 repassa ao Google. A regra de tráfego interno continuou funcionando depois da mudança.
DevTools: o collect indo para sv.portfoliovinicius.com.br
Preview do servidor: evento recebido e repassado ao GA4 (status 204)
Stape com o domínio próprio conectado

O GA4 exporta diariamente os eventos brutos para o BigQuery (região São Paulo). É o que permite cruzar o dado do site com outras fontes e responder perguntas que a interface do GA4 não responde.

Exemplo: cliques por projeto, direto da tabela exportada

SELECT
  (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'project_name') AS projeto,
  (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'project_type') AS tipo,
  COUNT(*) AS cliques,
  COUNT(DISTINCT user_pseudo_id) AS usuarios
FROM `analytics_556859069.events_*`
WHERE event_name = 'select_project'
GROUP BY projeto, tipo
ORDER BY cliques DESC;
Vínculo GA4 → BigQuery com exportação diária
Dataset exportado pelo GA4, com a tabela events_ e seu esquema
04 · Validação

Funciona, não só está configurado

Toda etapa foi testada no modo de visualização do GTM e no DebugView do GA4 antes de ser publicada.

Eventos e parâmetros

Os 6 eventos disparando no Tag Assistant e chegando ao DebugView com os parâmetros preenchidos.

Consentimento

Padrão negado, atualização para concedido ao aceitar e escolha respeitada ao recarregar.

Server-side

Requisições saindo para o subdomínio próprio e o servidor confirmando o envio ao GA4.

Tráfego interno

Meus acessos marcados como internos mesmo depois da passagem pelo servidor.

Tag Assistant com o evento disparado e as variáveis
DebugView do GA4 recebendo os eventos
05 · Decisões

Por que foi feito assim

Uma tag por evento, não uma genérica

O dataLayer guarda valores de pushes anteriores. Com uma tag única usando {{Event}}, um contact_click podia herdar o project_name de um clique anterior. Com uma tag por evento, cada uma só mapeia o que é dela.

Atributos data- em vez de acionadores de clique

O tracking fica declarado no próprio HTML, fácil de revisar, e não quebra quando a classe ou o texto de um botão muda.

generate_lead só no sucesso

O evento dispara na resposta positiva do envio, e não no clique em "Enviar". Um formulário com erro não vira conversão.

Banner próprio em vez de plataforma pronta

Controle total do visual e do comportamento, e a prova de que entendo o Consent Mode por dentro, e não só uma ferramenta que o configura.

Stape em vez da hospedagem do site

O GTM server é um programa Node.js (imagem Docker do Google) que precisa ficar rodando o tempo todo, e a hospedagem compartilhada só executa PHP sob demanda. Entre Stape, Google Cloud Run e uma VPS própria, a Stape resolve domínio, SSL e região em São Paulo sem manutenção e com plano gratuito.

O servidor vira uma dependência

Com server-side, o GA4 só recebe o que passa pelo servidor: se ele parar ou a cota acabar, os eventos se perdem. Por isso o uso é acompanhado, e a contingência é simples: remover o server_container_url da tag do Google faz o navegador voltar a enviar direto ao Google.

Num cliente, os próximos passos seriam:
  • Meta Conversions API e conversões otimizadas do Google Ads a partir do mesmo container server.
  • Enriquecimento de eventos no servidor (dados de CRM) e remoção de dados pessoais antes do envio.
  • Painel no Looker Studio ou Power BI sobre a exportação do BigQuery, cruzando tráfego com mídia e vendas.

Agora é a sua vez de virar um evento

Se você clicar em um destes botões, ele será registrado como conversão. Pode testar.

Falar no LinkedIn Baixar currículo

© 2026 Vinícius Rueda Lopes · Privacidade e cookies