0

Minha landing tinha 386 KB de SPA e comia 2 de cada 3 cliques pagos. Achei hoje de madrugada

Contexto: construi o Dosy, um app Android que organiza a medicacao de uma FAMILIA inteira numa conta so. Nao e mais um lembrete de remedio individual sao varios pacientes (mae idosa, filho em tratamento, voce, e ate o pet), cada um com a lista dele, e o dia de todos numa tela. Alarme nativo em tela cheia que toca no silencioso, historico de adesao, relatorio PDF pro medico, e um segundo cuidador que acompanha e marca dose junto.

Ontem subi 4 anuncios no Meta pra achar testadores. Resultado do dia:

  • 8.720 pessoas alcancadas
    • 458 cliques, CTR de 5,4% (umas 2x a media da categoria)
    • CPC de R$ 0,21
    • 218 visualizacoes de pagina
    • zero cadastros

Gastei um tempo achando que era copy. Nao era.

O que os numeros do GA4 diziam, e que eu demorei pra ler direito: 263 usuarios dispararam page_view e so 86 dispararam o evento proprio da landing. Os dois eventos estao no mesmo arquivo. A diferenca e QUANDO cada um roda: o page_view sai assim que o gtag inicializa, e o outro so quando o componente React da pagina monta.

Ou seja: 177 pessoas carregaram o suficiente pro Analytics existir, e foram embora antes da pagina existir.

Fui medir o que a landing realmente pedia pro navegador antes do primeiro pixel:

index .............. 121,4 KB
react-vendor ....... 101,9 KB
dosy ...............  78,3 KB
supabase ...........  51,0 KB
tanstack ...........  20,2 KB
css ................   6,5 KB
+ runtime e outros
TOTAL .............. 386,6 KB comprimidos (~1,5 MB descomprimidos), 10 arquivos

Mais um chunk lazy da propria pagina. Mais um @import de Google Fonts DENTRO do CSS que e a pior forma possivel de carregar fonte, porque o navegador so descobre o pedido depois de baixar o CSS e ai serializa mais duas idas ao servidor.

E o <body> do HTML servido era literalmente isso:

<body><div id="root"></div></body>

2 KB de HTML sem uma palavra dentro.

O erro de raiz nao foi performance. Foi arquitetural, e obvio depois: eu tratei uma pagina de captura como se fosse uma rota da aplicacao. Ela morava dentro do SPA porque era comodo reaproveitar componente e estilo. So que trafego pago do Feed do Facebook abre no WEBVIEW do app, num Android de entrada, em 4G. Nesse ambiente, 386 KB e varios segundos de tela branca e ninguem espera tela branca de um link de anuncio.

O tempo de engajamento somado confirmava, e eu tinha esse dado na mao o tempo todo:

/quemdeu  48 sessoes -> 70 segundos NO TOTAL
/juntos   32 sessoes ->  0 segundos
/lembrete 31 sessoes ->  1 segundo
/descanso 23 sessoes ->  0 segundos

Refiz as landings como HTML estatico gerado do mesmo arquivo de conteudo que alimentava as versoes React (uma fonte da verdade so). CSS inline, fonte do sistema, e JavaScript apenas pra medir e enviar o formulario nunca pra desenhar.

386,6 KB -> 6,0 KB na rede. TTFB de ~240 ms.

Tres coisas que aprendi e que valem mais que o numero:

  1. Pagina que recebe trafego pago nao e rota de aplicacao, e documento. Se o conteudo depende de download pra existir, voce esta pagando por clique de gente que nunca vai ver o conteudo.

  2. Instrumente dois eventos em momentos diferentes do boot. Foi so o vao entre page_view e o evento do componente que revelou o problema. Um evento so teria mostrado "chegou pouca gente" e eu ia culpar o anuncio pelo resto da semana.

  3. Cuidado com o que o build assume do ambiente. Na primeira geracao das paginas estaticas, o formulario saiu apontando pro Supabase de LOOPBACK, porque o .env.local da minha maquina aponta o VITE_SUPABASE_URL pro banco local do npm run dev. Ia subir bonita, aceitar o e-mail e o POST morreria em 127.0.0.1 no celular de quem clicou. Zero erro no build, zero cadastro, zero pista. Coloquei um guard que quebra o build se a URL escolhida for loopback.

No mesmo dia achei tambem um honeypot que devolvia {ok:true} e ia embora sem gravar nada. Pra bot, perfeito. Pra uma pessoa cujo gerenciador de senha preencheu o campo escondido, a tela dizia "Pronto" e o cadastro simplesmente nao existia. Agora grava marcado, e so o e-mail e pulado.


A parte do pedido, e vou ser direto porque acho que voces preferem assim: o app esta em teste fechado no Google Play e eu preciso de 12 pessoas usando por 14 dias e a exigencia e de 14 dias CONTINUOS, entao quem sai no meio rebobina o relogio.

Se voce cuida do remedio de alguem em casa (pai, mae, filho, ou voce mesmo com contnuo), e o publico exato pra quem isso foi feito, e eu quero MUITO a reclamacao de voces inclusive "essa tela ta feia" e "nao entendi esse botao".

Stack, pra quem tiver curiosidade: React 19 + Vite + Capacitor, Supabase atras, e o alarme em Java nativo porque WebView nao da conta de alarme confiavel em Doze mode.

Critica de arquitetura e de UX e bem-vinda. Se tiver furo, prefiro descobrir agora.

Carregando publicação patrocinada...
1
1

Juro que nao fui eu !!! Eu nao uso acentos, mas eh uma escolha estilistica minha com mais de 30 anos (por conta das BBS/usenet), mas por exemplo uso "eh" para referenciar "é" e o autor nem isso fez.