Auditoria do código-fonte enviado pelo desenvolvedor e do site em produção, com as correções já aplicadas, compiladas e testadas em navegador. Inclui o pacote pronto para o dev subir.
O pedido era instalar o GTM e a verificação de domínio da Meta. Ao abrir o código apareceu um problema maior: o site não tem página de obrigado. Se a conversão fosse configurada do jeito padrão, por URL de destino, a conta registaria zero leads mesmo com tudo aparentemente instalado.
Junto disso, o site pontua 63 em performance mobile no PageSpeed, com Largest Contentful Paint de 8,2 segundos. A causa foi medida e corrigida.
As três coisas foram resolvidas no código, o projeto compila e o comportamento foi verificado num navegador real. O que falta é o dev copiar quatro pastas e fazer o build.
O desenvolvedor está certo num ponto: não é construtor de sites, é código. É 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 para viron.portugal@gmail.com.
Em medição, o estado é o seguinte:
| Item | Estado atual |
|---|---|
| Google Tag Manager | Não instalado |
| Google Analytics 4 | Não instalado |
| Meta Pixel | Não instalado |
| Verificação de domínio Meta | Não instalada |
| Página de obrigado | Não existe |
| Meta description | Ausente |
A conta começa do zero. Isso é bom em um aspecto: dá para montar a estrutura certa desde o primeiro dia, sem herdar configuração errada de ninguém.
O formulário usa Server Action do Next.js. Ele envia os dados por baixo dos panos,
recebe a confirmação e apenas troca o texto do botão para sucesso. Não navega, não
recarrega, não vai para /obrigado. Do ponto de vista do Analytics e do
Meta, nada aconteceu.
Instalar o GTM sem resolver isso produz o pior cenário possível: tudo parece configurado, o cliente vê o site com a tag ativa, mas o relatório mostra zero leads. O tráfego pago fica sem sinal de conversão e o algoritmo otimiza no escuro.
Vale registar que a Ju relatou exatamente esta dor no dia 31 de julho sobre a inWindow, a página de obrigado que não contabilizava. É o mesmo padrão de site e o mesmo buraco.
O evento passa 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 depois, sem precisar incomodar o
desenvolvedor uma segunda vez.
O clique no WhatsApp do rodapé também passou a disparar evento próprio
(whatsapp_click), já que é o segundo caminho de contato do site.
Medição do PageSpeed Insights em 7 de agosto, perfil celular:
| Métrica | Valor | Leitura |
|---|---|---|
| Largest Contentful Paint | 8,2 s | Muito acima do 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 problema é peso de imagem. O site carrega, logo no início, seis imagens em paralelo somando cerca de 2 MB, todas em prioridade máxima, incluindo cinco que estão abaixo da dobra e que o visitante só veria depois de rolar a página. Em rede 4G lenta, que é o cenário do teste, isso sozinho explica os 8,2 segundos.
Somando: as fotos do projeto estão em PNG, formato pensado para gráficos e não para fotografia. Três delas passam de 400 KB cada.
| No carregamento inicial (mobile) | 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 Next.js já estão corretos, só a pasta pública ficou de fora. Isso não
se resolve no código, precisa de três linhas no .htaccess do LiteSpeed.
As instruções estão dentro do pacote.
Fora isso, o PageSpeed aponta ajustes menores 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.
O próprio .gitignore do projeto exclui arquivos .env,
ou seja, 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 tinha 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. São três arquivos substituídos e dez imagens novas, com o diff linha a linha para ele conferir antes de aplicar, e um README em inglês.
Do lado dele o trabalho é este:
app/layout.tsx, app/page.tsx,
app/Components/Gallery.tsx e os dez .webp em public/.npm run build e publicar como já faz hoje..htaccess, o trecho pronto está no README.
Nenhuma dependência nova foi adicionada. O GTM entrou pelo next/script,
que já vem com o Next.js, então ele não precisa nem rodar npm install.
O código foi compilado a partir do fonte dele e aberto num navegador headless 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 processawhatsapp_click dispara no cliqueO 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.
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 já vai no pacote de qualquer forma, os dois caminhos funcionam e não conflitam.