Altavance Media
Abri o código-fonte que o desenvolvedor enviou e o site em produção. O GTM e a verificação de domínio são trabalho de dez minutos, ele tinha razão só na parte de que não é construtor de sites. Mas encontrei algo que ninguém tinha visto: o formulário nunca muda a URL. Configurada do jeito padrão, por página de destino, a conta registaria zero lead com tudo aparentemente instalado. Junto disso, o site leva 8,2 segundos para aparecer no celular. As três coisas já estão corrigidas, compiladas e testadas em navegador.
É uma landing page única em Next.js 16 com React 19, bilíngue inglês e português por
botão de troca, hospedada em servidor próprio com LiteSpeed. O formulário envia e-mail via
Resend. O código real cabe em oito arquivos, o resto dos 377 MB era
node_modules, .next e a pasta .git.
| Camada de medição | Estado | Consequência |
|---|---|---|
| Google Tag Manager | Não instalado | Nenhum evento sai do site |
| Google Analytics 4 | Não instalado | Sem base de comportamento |
| Meta Pixel | Não instalado | Campanha otimiza sem sinal |
| Verificação de domínio Meta | Não instalada | Sem controle das regras do domínio |
| Página de obrigado | Não existe | Detalhado no item 02 |
| Meta description | Ausente | Google escreve o resumo por conta própria |
A conta começa do zero. Isso tem um lado bom: dá para montar a estrutura certa desde o primeiro dia, sem herdar configuração errada de ninguém.
Este é o achado que muda a ordem do trabalho. Sem ele resolvido, instalar o GTM produz o pior cenário possível: tudo parece configurado, a tag aparece ativa, e o relatório mostra zero lead.
O formulário usa Server Action do Next.js. Manda os dados por baixo dos panos,
recebe a confirmação e apenas troca o texto do botão para sucesso. Não recarrega, não vai
para /obrigado, a URL fica idêntica.
Conversão configurada por URL de destino, que é o padrão, nunca dispara. O tráfego pago fica sem sinal de conversão e o algoritmo do Meta otimiza no escuro, gastando para encontrar gente que nunca é reconhecida como lead.
Em 31 de julho a Ju relatou exatamente esta dor sobre a inWindow, a página de obrigado que não contabilizava. Mesmo tipo de site, mesmo buraco. Vale virar checagem fixa antes de prometer prazo de tracking.
O evento passou a ser disparado no ponto exato em que o servidor confirma o envio, dentro do
handleSubmit, e não por mudança de URL.
setBtnStatus(btnStatuses.success);
// Conversão: dispara apenas depois que a server action confirma o envio.
track('generate_lead', {
form_id: 'contact_main',
form_language: lang,
user_data: { email: data.email, phone: data.phone },
});
O user_data vai junto de propósito. É o que permite ligar Enhanced Conversions no
Google e Advanced Matching no Meta mais adiante, sem precisar incomodar o desenvolvedor uma
segunda vez. Considerando que ele já disse estar sobrecarregado, resolver isso agora evita
uma nova fila de espera.
A task pedia conversão em dois pontos: o envio concluído e o clique no botão de pedir
orçamento. O segundo tinha o mesmo problema do primeiro: os seis CTAs de orçamento apenas
rolam a página até o formulário, não navegam, então nenhum gerava sinal. Agora todos disparam
quote_button_click carregando o texto do próprio botão e a posição dele na página,
o que permite descobrir qual CTA realmente traz o lead.
O clique no WhatsApp do rodapé também passou a disparar evento próprio
(whatsapp_click), já que é o terceiro caminho de contato do site.
Medição do PageSpeed Insights em 7 de agosto, perfil celular, rede 4G lenta.
| Métrica | Valor | Leitura |
|---|---|---|
| Largest Contentful Paint | 8,2 s | Mais de três vezes o limite de 2,5 s |
| Speed Index | 8,7 s | O conteúdo demora a aparecer |
| First Contentful Paint | 2,6 s | Aceitável |
| Total Blocking Time | 0 ms | Sem travamento de JavaScript |
| Cumulative Layout Shift | 0 | Layout estável |
O JavaScript não é o problema: o bloqueio é zero. O peso está nas imagens.
O site carrega, logo no início, seis imagens em paralelo somando cerca de 2 MB, todas em prioridade máxima. Cinco delas estão abaixo da dobra e o visitante só as veria depois de rolar a página. Em rede 4G lenta isso sozinho explica os 8,2 segundos. Somando: as fotos estão em PNG, formato pensado para gráficos e não para fotografia, e três delas passam de 400 KB cada.
| No carregamento inicial, no celular | Antes | Depois |
|---|---|---|
| Imagens baixadas | 1.962 KB | 126 KB |
| Requisições | 11 | 6 |
| Imagens em prioridade máxima | 6 | 1 |
| Peso total dos arquivos de imagem | 3.488 KB | 1.097 KB |
Os arquivos em /public são servidos sem cabeçalho Cache-Control.
Quem volta ao site baixa tudo de novo, sempre. Os arquivos do próprio Next.js já estão
corretos, só a pasta pública ficou de fora. São três linhas no .htaccess do
LiteSpeed, e o trecho pronto está dentro do pacote.
O PageSpeed aponta ainda ajustes de acessibilidade que não foram tocados porque mexem no visual e são decisão do cliente: botões sem nome acessível, contraste insuficiente em alguns textos e hierarquia de títulos fora de ordem. Ficam registados para uma segunda rodada.
O zip que o desenvolvedor mandou continha o arquivo .env.local com a
RESEND_API_KEY ativa, além da pasta .git e do
node_modules. Essa chave envia e-mail em nome de
info@vironportugal.com, ou seja, quem a tiver consegue se passar pelo
domínio do cliente.
O próprio .gitignore do projeto exclui arquivos .env. Esse
arquivo nunca deveria ter saído da máquina dele. A chave precisa ser trocada no painel
do Resend.
É também por causa do node_modules e da pasta .git que o arquivo
chegou com 377 MB, para um projeto cujo código real cabe em oito arquivos.
Em vez de devolver os 377 MB, o pacote traz só o que mudou: três arquivos substituídos, dez imagens novas, o diff linha a linha para ele conferir antes de aplicar, e um README em inglês.
app/layout.tsx, app/page.tsx,
app/Components/Gallery.tsx e os dez .webp em public/.
npm run build e subir como ele já faz hoje. Nenhuma
dependência nova foi adicionada, o GTM entrou pelo next/script que já vem
com o Next.js. Ele não precisa nem rodar npm install.
Três linhas no .htaccess. O trecho pronto está no README.
O código foi compilado a partir do fonte dele e aberto num navegador real, em viewport de celular. Confirmado com o dado na tela, não por suposição.
gtm.js, gtm.dom, gtm.load no dataLayergenerate_lead dispara no sucesso do formulário e o GTM o processaquote_button_click dispara nos cinco CTAs de orçamento renderizados, cada um com o seu próprio rótulo de posiçãowhatsapp_click dispara no cliquenpm run build passa, incluindo a checagem de tipos do TypeScriptO teste do formulário foi feito com o envio de e-mail desligado, para não disparar mensagem falsa na caixa do cliente. Depois o arquivo foi restaurado ao original e conferido byte a byte.
Com o site publicado, o resto é do nosso lado e não depende mais do desenvolvedor.
generate_lead como conversãouser_data que já vai no eventoA Meta aceita registo TXT no DNS além da meta tag. Se a Ju ou o cliente tiver acesso ao DNS do domínio, isso fica resolvido em minutos e não depende de nenhum deploy. A meta tag vai no pacote de qualquer forma: os dois caminhos funcionam e não conflitam entre si.
O desenvolvedor tem razão que precisa dele para publicar, mas o que ele chamou de sobrecarga são três arquivos e um build. O pacote está pronto, testado e verificado. Assim que subir, a estrutura de medição da Viron começa certa desde o primeiro euro investido.
Falar com o Gustavo →