Claude Code Landing Pages: Angebot, Vertrauen, Tracking und Tests
Baue Claude-Code-Landingpages mit Astro/React, Formular, Events, A/B-Test und mobiler QA.
Eine Landingpage ist ein Entscheidungsweg, kein Design-Demo
Claude Code kann schnell eine Landingpage mit Hero, Feature-Karten, Preisen, FAQ und CTA erzeugen. Für Monetarisierung reicht das nicht. Eine gute Landingpage erklärt einer bestimmten Zielgruppe ein klares Angebot, baut Vertrauen auf, macht den nächsten Schritt leicht und liefert Messdaten für die nächste Iteration.
Conversion bedeutet nicht nur Kauf. Es kann auch ein Beratungstermin, ein Download, ein Template-Kauf, eine Trainingsanfrage oder ein Trial-Start sein. CTA steht für Call To Action, also die konkrete Handlungsaufforderung wie “Review buchen” oder “Checkliste erhalten”. Ein Trust-Block liefert Belege: Prozess, Erfahrung, Review-Kriterien, echte Tests und ehrliche Grenzen.
Für ClaudeCodeLab geht es nicht um falsche Garantien wie “mehr Conversion sicher”. Es geht darum, Claude-Code-Beratung, Templates und Team-Training mit einer klaren, messbaren, barrierearmen und schnellen Seite zu verbinden. Prüfe die offiziellen Quellen: Claude Code docs, Astro Pages, Tailwind CSS, React forms, GA4 events und Playwright.
Drei konkrete Use Cases
Starte mit der Situation des Lesers, nicht mit dem Layout.
| Use Case | Leserzustand | Passendes Angebot | Zu messendes Event |
|---|---|---|---|
| Template-Verkauf für Indie-Founder | Will mit Claude Code eine LP bauen, hat aber keine Copy-Struktur | Astro-LP-Template und Conversion-Copy-Prompts | Produktklick, Checkout-Start |
| SaaS- oder Agenturberatung | Hat Traffic, aber unklare Lead-Qualität | 90-Minuten-Diagnose und Implementierungsreview | Formularsubmit, Terminbuchung |
| Team-Training | Will Claude Code im Team einheitlich nutzen | Workshop mit LP-Bau, Review, Analytics und Tests | Trainingsanfrage, Unterlagen-Download |
Die Reihenfolge der Seite sollte drei Fragen beantworten: Ist das für mich? Warum soll ich vertrauen? Was passiert nach dem Klick?
flowchart TD
A["Traffic aus Suche, Artikel, Anzeige oder Social"] --> B["Erster Viewport zeigt Zielgruppe, Angebot und CTA"]
B --> C["Trust-Block erklärt Methode und Nachweise"]
C --> D["Use Cases verbinden Angebot mit Leser-Situation"]
D --> E["Preis oder Lead Magnet senkt die Hürde"]
E --> F["Formular, Produktklick oder Trainingsanfrage"]
F --> G["Events und A/B-Test steuern die nächste Verbesserung"]
Produktionsprompt für Claude Code
Ein präziser Prompt verhindert generische SaaS-Sektionen.
Implementiere eine Landingpage "Claude Code Landing Page Sprint" mit Astro, React und Tailwind CSS.
Ziel:
- Leser zu Beratungsterminen, Template-Käufen oder Trainingsanfragen führen.
- Zielgruppe: Indie-Founder, SaaS-Betreiber, Agenturen und Engineering-Leads.
- Keine garantierten Conversion-Steigerungen behaupten.
Pflichtsektionen:
- Erster Viewport: Zielgruppe, Angebot, primärer CTA, sekundärer CTA.
- Trust-Block: Masas Praxiserfahrung, Review-Prozess, Pre-Launch-Checkliste.
- Drei konkrete Use Cases.
- Preis oder Lead Magnet.
- Formular: name, email, company, goal, budget, consent.
- Events: lp_view, cta_click, lead_submit, product_click.
- A/B-Test: zwei CTA-Texte vergleichen.
- Playwright-Mobile-Checks: CTA sichtbar, Labels korrekt, kein horizontaler Scroll.
Constraints:
- Kopierbares TypeScript, kein Pseudocode.
- Labels, Focus, Tastaturbedienung und Kontrast beachten.
- Keine schweren Hero-Videos, die LCP verschlechtern.
- Keine personenbezogenen Daten in Analytics-Events senden.
Erster Viewport mit Astro
Der erste Viewport muss Zielgruppe, Angebot und nächsten Schritt erklären. Diese Komponente macht die Texte variant-fähig.
---
// 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: "Eine Claude-Code-Landingpage mit Angebot, Formular und Tracking bauen",
body: "Wir machen aus der Seite einen messbaren Funnel: erster Viewport, Trust-Blöcke, Preis, Lead-Formular, Events und mobile QA.",
primary: "Kostenloses Review buchen",
secondary: "Templates ansehen",
},
lead_magnet: {
eyebrow: "Kostenlose Checkliste inklusive",
headline: "Finde Conversion-Lücken, bevor Claude Code die UI schreibt",
body: "Prüfe Angebot, CTA, Preis, Formular, Geschwindigkeit, Barrierearmut und Event-Namen vor dem Launch.",
primary: "Checkliste erhalten",
secondary: "Training ansehen",
},
}[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">Keine Erfolgsgarantie. Das Versprechen ist klare Umsetzung und eine messbare Lernschleife.</p>
</div>
<div class="rounded-lg border border-slate-700 bg-slate-900 p-6">
<h2 class="text-lg font-semibold">Pre-Launch-Checks</h2>
<ul class="mt-4 space-y-3 text-sm leading-6 text-slate-200">
<li>Sind Zielgruppe, Angebot und nächster Schritt sofort sichtbar?</li>
<li>Erklärt der Trust-Block Prozess und Review?</li>
<li>Werden Formular, Produkt und Training separat gemessen?</li>
<li>Bleiben CTA und Formular auf dem Smartphone nutzbar?</li>
</ul>
</div>
</div>
</section>
data-cta-id ist ein Vertrag für Analytics. Wenn der Buttontext später wechselt, bleibt das Event stabil.
Vertrauen, Nachweis, Preis und Lead Magnet
Ordne die Mitte der Seite nach Einwänden.
| Block | Inhalt | Vermeiden |
|---|---|---|
| Vertrauen | Checkliste, Screenshots, Owner-Bio, QA-Prozess | Leere Badges und vage AI-Slogans |
| Nachweis | Was Masa getestet hat, was kaputtging, was geändert wurde | Erfundene Testimonials, nicht prüfbare Zahlen |
| Preis | Unterschiede zwischen Template, Review und Training | Alles hinter einem Formular verstecken |
| Lead Magnet | Checkliste, Audit-Blatt, Copy-Prompts | Dünnes PDF nur für E-Mail-Sammlung |
Für ClaudeCodeLab passt eine Leiter: products für Self-Service, training für Teams und Formular für ein gezieltes Review.
Formular-Schema und Astro API
Das Schema definiert, welche Daten akzeptiert werden. Der Endpoint braucht keine Zusatzbibliothek.
// 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" },
});
};
Sende Namen, E-Mail, Firmenname und freie Texte nicht an Analytics. Dort reichen Kategorien und CTA-IDs.
// 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(" ") ?? "Bitte Formular prüfen.");
return;
}
trackLpEvent({ eventName: "lead_submit", ctaId: "lead-form", value: "consulting" });
setMessage("Anfrage gesendet. Prüfe die E-Mail für den nächsten Schritt.");
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">Name<input name="name" required className="mt-1 w-full rounded-md border px-3 py-2" /></label>
<label className="block text-sm font-medium">E-Mail<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">Ziel der Landingpage<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">Unterstützung
<select name="budget" className="mt-1 w-full rounded-md border px-3 py-2">
<option value="template">Template</option>
<option value="consulting">Beratung</option>
<option value="training">Team-Training</option>
<option value="undecided">Noch unklar</option>
</select>
</label>
<label className="flex gap-2 text-sm"><input name="consent" type="checkbox" required />Ich bin mit Kontaktaufnahme zu dieser Anfrage einverstanden.</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 ? "Senden..." : "Anfrage senden"}</button>
<p role="status" aria-live="polite" className="text-sm">{message}</p>
</form>
);
}
Events, Performance und A/B-Test
Lege Eventnamen vor dem Launch fest.
// 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 gehören in die Review-Liste. Schwere Hero-Bilder, Drittanbieter-Skripte und Layout-Verschiebungen können Conversion direkt schaden.
// 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>
Ein häufiger Fehler ist Variant-Zuweisung nur mit localStorage. Das kann flackern und die gemessene Exposition verfälschen.
Mobile QA mit 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("Name").fill("Masa");
await page.getByLabel("E-Mail").fill("masa@example.com");
await page.getByLabel("Ziel der Landingpage").fill("Ich will eine Claude-Code-Beratungslandingpage verbessern.");
await page.getByRole("button", { name: "Anfrage senden" }).click();
await expect(page.getByLabel("Ich bin mit Kontaktaufnahme zu dieser Anfrage einverstanden.")).toBeFocused();
});
Typische Fehler
Erstens: ein unklares Angebot. “KI-Automatisierung” ist zu breit. “Wir implementieren Landingpage, Formular, Events und mobile QA für dein Claude-Code-Angebot” ist prüfbar.
Zweitens: falsche Beweise. Keine erfundenen Testimonials oder garantierten Zahlen. Zeige Prozess, Checkliste und Masas echte Tests.
Drittens: nur ein Formular als nächster Schritt. Manche wollen ein Template, andere Training, andere Review.
Viertens: Barrierearmut als Kosmetik. Fehlende Labels, schwacher Kontrast und schlechte Tastaturbedienung kosten reale Conversions.
Fünftens: Tracking nachträglich einbauen. Ohne stabile Events bleibt Optimierung Meinung.
Weiter mit ClaudeCodeLab
Für Self-Service passt products, für Teams training, und für ein Review das Formular. Weitere Details: Claude Code Analytics, A/B Testing, Playwright Testing und SEO Optimierung.
Praktisches Ergebnis
In Masas Test war der größte Gewinn kein magischer Conversion-Wert, sondern Klarheit: CTA-IDs, Formularschema und mobile Tests standen vor dem visuellen Feinschliff fest. Dadurch wurde sichtbar, welcher Button geklickt wurde, ob das mobile Formular funktioniert und welche Variante tatsächlich angezeigt wurde.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Workflow von Obsidian zu CLAUDE.md
Obsidian-Arbeitsnotizen in CLAUDE.md-Betriebsnotizen verwandeln und Kontext nicht ständig neu erklären.
Claude Code Revenue CTA Routing: Artikel zu PDF, Gumroad und Beratung führen
Ein Claude-Code-Ablauf, der Leser nach Absicht zu Gratis-PDF, Gumroad oder Beratung führt.
Claude-Code-Team-Handoff-Regeln: Belege, Berechtigungen, Rollback und Umsatzpfade
Ein praktisches Claude-Code-Handoff für Review-Belege, Berechtigungen, Rollback, Gratis-PDF, Gumroad und Beratung.