Landing page com Claude Code: oferta, confiança, métricas e testes
Implemente landing pages com Claude Code, Astro/React, formulário, eventos, A/B test e QA móvel.
Landing page é caminho de decisão, não vitrine bonita
Claude Code consegue gerar rapidamente uma página com hero, cards, preços, FAQ e CTA. Isso é um bom começo, mas não basta para vender templates, qualificar leads ou gerar pedidos de treinamento. Uma landing page de verdade explica uma oferta para um público específico, cria confiança, facilita o próximo passo e registra dados para melhoria.
Conversão não é só pagamento. Pode ser agendar uma consultoria, baixar uma checklist, comprar um template, pedir treinamento ou iniciar um teste. CTA é Call To Action, ou chamada para ação: “Agendar revisão”, “Baixar checklist”, “Ver templates”. Um bloco de confiança mostra por que o leitor pode acreditar: processo, experiência, revisão técnica, testes reais e limites honestos.
No contexto da ClaudeCodeLab, a meta não é prometer aumento garantido de conversão. A meta é conectar consultoria em Claude Code, produtos e treinamentos a uma página clara, mensurável, acessível e rápida. Use documentação oficial como base: Claude Code docs, Astro Pages, Tailwind CSS, React forms, GA4 events e Playwright.
Três casos de uso antes do layout
Comece pelo leitor. Isso evita uma página genérica.
| Caso de uso | Estado do leitor | Oferta certa | Evento para medir |
|---|---|---|---|
| Venda de template para indie founder | Quer uma LP com Claude Code, mas falta estrutura de copy | Template Astro LP e prompts de copy de conversão | Clique no produto e início do checkout |
| Consultoria SaaS ou agência | Tem tráfego, mas leads irregulares | Diagnóstico de 90 minutos e revisão de implementação | Envio do formulário e agendamento |
| Treinamento de equipe | Quer padronizar o uso de Claude Code | Workshop com LP, revisão, analytics e testes | Pedido de treinamento e download de material |
O leitor quer saber: isso é para mim, posso confiar, o que acontece se eu clicar? A ordem da página deve responder a essas perguntas.
flowchart TD
A["Tráfego de busca, artigo, anúncio ou social"] --> B["Primeira dobra explica público, oferta e CTA"]
B --> C["Bloco de confiança mostra processo e provas"]
C --> D["Casos de uso conectam a oferta ao leitor"]
D --> E["Preço ou lead magnet reduz fricção"]
E --> F["Formulário, clique no produto ou pedido de treinamento"]
F --> G["Eventos e A/B test alimentam a próxima melhoria"]
Prompt de produção para Claude Code
Peça a implementação com objetivo, restrições e validação.
Implemente uma landing page "Claude Code Landing Page Sprint" com Astro, React e Tailwind CSS.
Objetivo:
- Converter leitores em consultorias, compras de templates ou pedidos de treinamento.
- Público: indie founders, operadores SaaS, agências e líderes de engenharia.
- Não prometer aumento garantido de conversão.
Seções obrigatórias:
- Primeira dobra: público, oferta, CTA principal e CTA secundário.
- Confiança: experiência prática de Masa, processo de review e checklist.
- Três casos de uso concretos.
- Preço ou lead magnet.
- Formulário: name, email, company, goal, budget, consent.
- Eventos: lp_view, cta_click, lead_submit, product_click.
- A/B test: comparar dois textos de CTA.
- Playwright mobile checks: CTA visível, labels corretos e sem scroll horizontal.
Restrições:
- TypeScript copiável, sem pseudocódigo.
- Labels, foco, teclado e contraste corretos.
- Evitar vídeo pesado que piore LCP.
- Não enviar dados pessoais em eventos de analytics.
Primeira dobra com Astro
A primeira dobra precisa ser direta. Este componente usa duas variantes de copy para A/B testing.
---
// src/components/LandingHero.astro
export interface Props {
variant: "control" | "lead_magnet";
}
const { variant } = Astro.props;
const copy = {
control: {
eyebrow: "Claude Code Landing Page Sprint",
headline: "Lance uma landing page Claude Code com oferta, formulário e tracking",
body: "Transformamos a página em um funil mensurável: primeira dobra, confiança, preço, formulário, eventos e QA móvel.",
primary: "Agendar revisão gratuita",
secondary: "Ver templates",
},
lead_magnet: {
eyebrow: "Checklist grátis incluída",
headline: "Encontre falhas de conversão antes de escrever a UI",
body: "Revise oferta, CTA, preço, formulário, velocidade, acessibilidade e eventos antes de publicar.",
primary: "Receber checklist",
secondary: "Ver treinamento",
},
}[variant];
---
<section class="bg-slate-950 px-4 py-16 text-white sm:py-20">
<div class="mx-auto grid max-w-6xl gap-10 lg:grid-cols-[1.05fr_0.95fr] lg:items-center">
<div>
<p class="text-sm font-semibold uppercase tracking-wide text-cyan-300">{copy.eyebrow}</p>
<h1 class="mt-4 max-w-3xl text-4xl font-bold leading-tight sm:text-5xl">{copy.headline}</h1>
<p class="mt-5 max-w-2xl text-lg leading-8 text-slate-200">{copy.body}</p>
<div class="mt-8 flex flex-col gap-3 sm:flex-row">
<a data-cta-id="hero-primary" href="#lead-form" class="inline-flex min-h-12 items-center justify-center rounded-md bg-cyan-300 px-6 font-semibold text-slate-950 hover:bg-cyan-200 focus:outline-none focus:ring-2 focus:ring-cyan-200 focus:ring-offset-2 focus:ring-offset-slate-950">{copy.primary}</a>
<a data-cta-id="hero-secondary" href="/products" class="inline-flex min-h-12 items-center justify-center rounded-md border border-slate-500 px-6 font-semibold text-white hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-cyan-200 focus:ring-offset-2 focus:ring-offset-slate-950">{copy.secondary}</a>
</div>
<p class="mt-4 text-sm text-slate-400">Sem promessa de ganho garantido. O foco é clareza, implementação e medição.</p>
</div>
<div class="rounded-lg border border-slate-700 bg-slate-900 p-6">
<h2 class="text-lg font-semibold">Checklist antes do lançamento</h2>
<ul class="mt-4 space-y-3 text-sm leading-6 text-slate-200">
<li>Público, oferta e próximo passo aparecem na primeira dobra?</li>
<li>O bloco de confiança mostra processo e experiência real?</li>
<li>Formulário, produto e treinamento são medidos separadamente?</li>
<li>No celular, CTA e formulário continuam usáveis?</li>
</ul>
</div>
</div>
</section>
data-cta-id mantém o tracking estável mesmo quando o texto do botão muda.
Confiança, prova, preço e lead magnet
O meio da página deve reduzir objeções.
| Bloco | Mostrar | Evitar |
|---|---|---|
| Confiança | Checklist, screenshots, bio, processo QA | Selos vazios e frases vagas de IA |
| Prova | O que Masa testou, o que falhou, o que mudou | Depoimentos inventados e números sem fonte |
| Preço | Diferença entre template, revisão e treinamento | Esconder todo preço atrás do formulário |
| Lead magnet | Checklist, planilha de auditoria, prompts de copy | PDF raso só para capturar email |
Na ClaudeCodeLab, o caminho natural é products para quem quer fazer sozinho, training para equipes e formulário para revisão.
Schema do formulário e API Astro
Schema é o contrato do formulário. Este endpoint roda sem dependências extras.
// src/pages/api/lead.ts
import type { APIRoute } from "astro";
type LeadInput = {
name: string;
email: string;
company: string;
goal: string;
budget: "template" | "consulting" | "training" | "undecided";
consent: boolean;
};
function validateLead(form: FormData): { ok: true; data: LeadInput } | { ok: false; errors: string[] } {
const data: LeadInput = {
name: String(form.get("name") ?? "").trim().slice(0, 80),
email: String(form.get("email") ?? "").trim().slice(0, 120),
company: String(form.get("company") ?? "").trim().slice(0, 120),
goal: String(form.get("goal") ?? "").trim().slice(0, 1000),
budget: String(form.get("budget") ?? "undecided") as LeadInput["budget"],
consent: form.get("consent") === "on",
};
const errors: string[] = [];
if (!data.name) errors.push("Name is required.");
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) errors.push("A valid email is required.");
if (data.goal.length < 20) errors.push("Please describe the goal in at least 20 characters.");
if (!["template", "consulting", "training", "undecided"].includes(data.budget)) errors.push("Budget is invalid.");
if (!data.consent) errors.push("Consent is required.");
return errors.length ? { ok: false, errors } : { ok: true, data };
}
export const POST: APIRoute = async ({ request }) => {
const result = validateLead(await request.formData());
if (!result.ok) {
return new Response(JSON.stringify({ ok: false, errors: result.errors }), {
status: 400,
headers: { "content-type": "application/json" },
});
}
console.info("new_lp_lead", {
emailDomain: result.data.email.split("@")[1],
budget: result.data.budget,
goalLength: result.data.goal.length,
});
return new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: { "content-type": "application/json" },
});
};
Não envie nome, email, empresa ou texto livre para analytics. Use apenas categoria, CTA e variante.
// src/components/LeadForm.tsx
import { useState } from "react";
import { trackLpEvent } from "../lib/lp-events";
export function LeadForm() {
const [message, setMessage] = useState("");
const [sending, setSending] = useState(false);
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setSending(true);
const response = await fetch("/api/lead", {
method: "POST",
body: new FormData(event.currentTarget),
});
setSending(false);
if (!response.ok) {
const body = await response.json();
setMessage(body.errors?.join(" ") ?? "Revise o formulário.");
return;
}
trackLpEvent({ eventName: "lead_submit", ctaId: "lead-form", value: "consulting" });
setMessage("Pedido enviado. Confira seu email para o próximo passo.");
event.currentTarget.reset();
}
return (
<form id="lead-form" onSubmit={onSubmit} className="space-y-5 rounded-lg border border-slate-200 p-6">
<label className="block text-sm font-medium">Nome<input name="name" required className="mt-1 w-full rounded-md border px-3 py-2" /></label>
<label className="block text-sm font-medium">Email<input name="email" type="email" required className="mt-1 w-full rounded-md border px-3 py-2" /></label>
<label className="block text-sm font-medium">Objetivo da landing page<textarea name="goal" required minLength={20} rows={5} className="mt-1 w-full rounded-md border px-3 py-2" /></label>
<label className="block text-sm font-medium">Tipo de apoio
<select name="budget" className="mt-1 w-full rounded-md border px-3 py-2">
<option value="template">Template</option>
<option value="consulting">Consultoria</option>
<option value="training">Treinamento de equipe</option>
<option value="undecided">Ainda não sei</option>
</select>
</label>
<label className="flex gap-2 text-sm"><input name="consent" type="checkbox" required />Aceito ser contatado sobre este pedido.</label>
<button disabled={sending} className="min-h-11 w-full rounded-md bg-slate-950 px-5 font-semibold text-white disabled:opacity-60">{sending ? "Enviando..." : "Enviar pedido"}</button>
<p role="status" aria-live="polite" className="text-sm">{message}</p>
</form>
);
}
Eventos, performance e A/B test
Defina eventos antes de publicar.
// src/lib/lp-events.ts
type LpEventName = "lp_view" | "cta_click" | "lead_submit" | "product_click";
type LpEvent = {
eventName: LpEventName;
ctaId?: string;
variant?: "control" | "lead_magnet";
value?: "template" | "consulting" | "training";
};
declare global {
interface Window {
dataLayer?: Array<Record<string, unknown>>;
gtag?: (command: "event", name: string, params: Record<string, unknown>) => void;
}
}
export function trackLpEvent(event: LpEvent) {
if (typeof window === "undefined") return;
const params = {
page_slug: "claude-code-landing-page",
cta_id: event.ctaId,
variant: event.variant,
value_type: event.value,
};
window.dataLayer?.push({ event: event.eventName, ...params });
window.gtag?.("event", event.eventName, params);
}
Core Web Vitals deve entrar no checklist. Imagens hero pesadas, scripts de terceiros e shifts de layout prejudicam a experiência e a conversão.
// src/lib/landing-ab.ts
export type LandingVariant = "control" | "lead_magnet";
export function chooseLandingVariant(visitorId: string): LandingVariant {
let hash = 2166136261;
for (let index = 0; index < visitorId.length; index += 1) {
hash ^= visitorId.charCodeAt(index);
hash = Math.imul(hash, 16777619);
}
return Math.abs(hash) % 2 === 0 ? "control" : "lead_magnet";
}
---
// src/pages/lp.astro
import LandingHero from "../components/LandingHero.astro";
import { chooseLandingVariant } from "../lib/landing-ab";
const visitorId = Astro.cookies.get("lp_visitor")?.value ?? crypto.randomUUID();
Astro.cookies.set("lp_visitor", visitorId, {
path: "/",
sameSite: "lax",
secure: import.meta.env.PROD,
maxAge: 60 * 60 * 24 * 30,
});
const variant = chooseLandingVariant(visitorId);
---
<LandingHero variant={variant} />
<script define:vars={{ variant }}>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ event: "lp_view", page_slug: "claude-code-landing-page", variant });
</script>
A/B test não é garantia. Com pouco tráfego, trate o resultado como sinal. Evite localStorage como única fonte de variante porque ele pode causar flicker e inconsistência de exposição.
QA móvel com Playwright
// tests/landing-page.spec.ts
import { test, expect, devices } from "@playwright/test";
test.use({ ...devices["iPhone 13"] });
test("mobile LP keeps CTA visible and avoids horizontal overflow", async ({ page }) => {
await page.goto("/lp");
await expect(page.getByRole("heading", { level: 1 })).toBeVisible();
await expect(page.locator('[data-cta-id="hero-primary"]')).toBeVisible();
const scrollWidth = await page.evaluate(() => document.documentElement.scrollWidth);
const viewportWidth = page.viewportSize()?.width ?? 390;
expect(scrollWidth).toBeLessThanOrEqual(viewportWidth + 1);
});
test("lead form requires consent", async ({ page }) => {
await page.goto("/lp");
await page.getByLabel("Nome").fill("Masa");
await page.getByLabel("Email").fill("[email protected]");
await page.getByLabel("Objetivo da landing page").fill("Quero melhorar uma landing de consultoria Claude Code.");
await page.getByRole("button", { name: "Enviar pedido" }).click();
await expect(page.getByLabel("Aceito ser contatado sobre este pedido.")).toBeFocused();
});
Erros comuns
Primeiro, oferta vaga. “Automação com IA” é amplo demais. “Implementamos landing, formulário, eventos e QA móvel para sua oferta Claude Code” é claro.
Segundo, prova falsa. Não invente depoimentos ou números. Mostre processo, checklist e o que Masa testou de verdade.
Terceiro, esconder todos os caminhos atrás de um formulário. Alguns querem template, outros treinamento, outros revisão.
Quarto, tratar acessibilidade como detalhe visual. Labels, contraste e teclado afetam conversões reais.
Quinto, medir tarde. Sem eventos estáveis, otimização vira opinião.
Próximo passo com ClaudeCodeLab
Para seguir sozinho, veja products. Para equipes, veja training. Para revisão, use o formulário. Leia também analytics com Claude Code, A/B testing com Claude Code, Playwright com Claude Code e SEO com Claude Code.
Resultado prático
No teste de Masa, o ganho principal não foi um número mágico. Foi ter CTA ids, schema do formulário e testes móveis definidos antes do acabamento visual. Assim ficou claro qual botão foi clicado, se o formulário móvel era usável e qual variante foi exibida.
Artigos relacionados
shadcn/ui com Claude Code: guia prático para React
Use Claude Code com shadcn/ui: instalação, Button/Card/Form/Dialog/Table, tokens e testes visuais com Playwright.
Melhore a página de primeira visita com Claude Code: sintomas e CTA único
Organize sintomas, preço, fluxo, FAQ, formulário e CTA de uma página de primeira visita usando Claude Code.
Dicas de Tailwind CSS com Claude Code: guia prático para UI estável
Tailwind CSS com Claude Code: tokens, responsividade, dark mode, componentes, safelist e checagens visuais em React.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.