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("masa@example.com");
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.
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.
Artigos relacionados
Workflow Obsidian para CLAUDE.md com Claude Code
Transforme notas de trabalho do Obsidian em notas operacionais CLAUDE.md para preservar contexto.
Claude Code Revenue CTA Routing: artigos para PDF, Gumroad e consultoria
Um fluxo com Claude Code para levar leitores ao PDF grátis, Gumroad ou consultoria conforme intenção.
Regras de handoff para equipes com Claude Code: evidências, permissões, rollback e receita
Formato prático para entregar trabalho do Claude Code com prova, permissões, rollback, PDF grátis, Gumroad e consultoria.