Claude CodeでCVするランディングページを実装する実践ガイド
Claude CodeでLPの訴求、信頼、フォーム、計測、A/Bテストまで実装する実践ガイド。
LPは「きれいなページ」ではなく、迷わず次へ進める導線
Claude Codeに「ランディングページを作って」と頼むだけだと、見た目は整っていても売上や問い合わせにつながらないページになりがちです。ランディングページ、つまりLPは、検索広告、SNS、記事、ウェビナーなどから来た読者に、ひとつのオファーを理解してもらい、次の行動へ進んでもらうための1枚ページです。
ここでいうコンバージョンは、購入だけを意味しません。無料相談の予約、資料請求、メール登録、テンプレート購入、研修問い合わせなど、「事業上の意味がある行動」すべてです。CTAはCall To Actionの略で、「無料で相談する」「チェックリストを受け取る」のように読者へ次の行動を示すボタンやリンクを指します。
Claude Codeを使う価値は、セクションを素早く並べることではありません。訴求、ファーストビュー、信頼ブロック、実績、価格、リード獲得フォーム、計測、A/Bテスト、アクセシビリティ、速度確認まで、LPを収益導線として実装することにあります。公式情報は必ず確認してください。Claude Codeの基本はAnthropicのClaude Code docs、Astroのページ構成はAstro Pages、スタイルはTailwind CSS docs、テストはPlaywright docsが基準になります。
ClaudeCodeLabの文脈では、LPのゴールは「Claude Codeの相談、研修、テンプレート販売へ自然につなげること」です。この記事では、架空の「Claude Code LP改善スプリント」というサービスを例に、Astro、React、Tailwind CSSでそのまま試せる実装を作ります。派手な数値保証はしません。代わりに、読者が理解し、信頼し、計測できる状態を作ります。
3つのユースケースから逆算する
最初に決めるのはデザインではなく、LPが受け止める読者です。Claude Codeに実装を任せる前に、少なくとも次の3パターンを整理します。
| ユースケース | 読者の状態 | 主なオファー | 計測する行動 |
|---|---|---|---|
| 個人開発者向けテンプレート販売 | Claude CodeでLPを作りたいが、設計に自信がない | Astro LPテンプレートとコピー改善プロンプト | 商品ボタンのクリック、購入開始 |
| 企業向け導入相談 | 社内にClaude Codeを入れたいが、運用ルールがない | 90分の導入診断、セキュリティ・レビュー設計 | 相談フォーム送信、日程予約 |
| 研修・ワークショップ | チームで使い方を統一したい | Claude Code実装研修、レビュー演習、LP改善ハンズオン | 研修資料請求、法人問い合わせ |
この表をClaude Codeに渡すと、「機能を並べたLP」から「読者の不安を順番に解消するLP」に変わります。検索で来た読者は、最初から購入意思が高いとは限りません。まず自分向けかを判断し、次に信頼できるかを確認し、最後に価格やフォームの負担を見て行動します。
Claude Codeへ渡す制作プロンプト
曖昧な依頼は、曖昧なLPを生みます。次のように、オファー、計測、禁止事項、検証条件までまとめて渡します。
Astro + React + Tailwind CSSで、Claude Code LP改善スプリントのランディングページを実装してください。
目的:
- 無料相談予約とテンプレート購入につなげる
- 読者は個人開発者、SaaS運営者、企業の開発責任者
- 成果保証は書かず、実装範囲と検証手順を明確にする
必須セクション:
- ファーストビュー: 誰向け、何を改善するか、主要CTA、補助CTA
- 信頼ブロック: Masaの実務経験、実装レビュー、公開前チェック
- 3つのユースケース
- 価格またはリードマグネット
- フォーム: name, email, company, goal, budget, consent
- イベント計測: lp_view, cta_click, lead_submit
- A/Bテスト: CTAコピーを2案で比較
- Playwrightでモバイル表示とCTA可視性を確認
制約:
- 誇大なCVR改善保証を書かない
- 疑似コードではなくコピーして動くTypeScriptを出す
- aria属性、ラベル、フォーカス、コントラストに配慮する
- LCPを悪化させる重い背景動画は使わない
LPの流れは次のように設計します。
flowchart TD
A["検索・記事・SNSから流入"] --> B["ファーストビューで対象者と約束を理解"]
B --> C["信頼ブロックで任せてよい理由を確認"]
C --> D["ユースケースで自分の状況に当てはめる"]
D --> E["価格・無料チェックリスト・相談CTAを比較"]
E --> F["フォーム送信または商品ページへ遷移"]
F --> G["イベント計測とA/Bテストで改善"]
ファーストビューをAstroで作る
ファーストビューは、ページを開いた直後に見える領域です。ここで「何のページか」「自分向けか」「次に何をすればよいか」が伝わらないと、下のセクションは読まれません。ヒーロー画像や装飾より、オファーの明瞭さを優先します。
次のLandingHero.astroは、CTAを2つに絞り、実績の言い方を控えめにし、フォームと商品ページの両方へつなげます。
---
// src/components/LandingHero.astro
export interface Props {
variant: "control" | "lead_magnet";
}
const { variant } = Astro.props;
const copy = {
control: {
eyebrow: "Claude Code LP改善スプリント",
headline: "Claude Codeで、問い合わせまで設計されたLPを作る",
body: "訴求、信頼ブロック、フォーム、イベント計測、A/Bテストまでを1週間で実装できる形に整理します。",
primary: "無料相談を予約する",
secondary: "テンプレートを見る",
},
lead_magnet: {
eyebrow: "無料チェックリスト付き",
headline: "LPの離脱ポイントを、Claude Codeで実装前に潰す",
body: "ファーストビュー、CTA、価格、フォーム、速度、アクセシビリティを公開前に確認できる実務用チェックリストです。",
primary: "チェックリストを受け取る",
secondary: "研修内容を見る",
},
}[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 transition 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 transition 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">
相談だけでも可。CVR改善の保証ではなく、実装と検証の筋道を明確にします。
</p>
</div>
<div class="rounded-lg border border-slate-700 bg-slate-900 p-6">
<h2 class="text-lg font-semibold">公開前に確認する項目</h2>
<ul class="mt-4 space-y-3 text-sm leading-6 text-slate-200">
<li>対象読者、オファー、CTAがファーストビューで一致しているか</li>
<li>実績、レビュー、運営者情報で信頼を補えているか</li>
<li>フォーム送信、商品クリック、資料請求を別イベントで計測しているか</li>
<li>スマホでCTA、価格、入力フォームが隠れていないか</li>
</ul>
</div>
</div>
</section>
見た目だけならClaude Codeはすぐ作れます。差が出るのは、data-cta-idのような計測用属性を最初から入れることです。後で「どのボタンが押されたか」を知りたくなってからDOMを掘ると、イベント名がばらつきます。
信頼ブロックと価格を「不安の順番」で置く
LPの中盤では、特徴よりも不安を潰します。初心者向けなら「自分でも運用できるか」、企業向けなら「セキュリティやレビューは大丈夫か」、商品購入向けなら「買った後に使えるか」が主な不安です。
比較表は、長文より早く伝わります。
| ブロック | 書く内容 | 避ける表現 |
|---|---|---|
| 信頼 | 実装レビュー、検証手順、公開後の改善サイクル | 「必ず売上アップ」 |
| 実績 | Masaが試した手順、失敗から直した点、レビュー観点 | 数字だけの自慢 |
| 価格 | 相談、テンプレート、研修の違い | 価格を隠してフォームだけ置く |
| リードマグネット | 無料チェックリストや診断シート | メール取得だけが目的の薄いPDF |
ClaudeCodeLabのCTAなら、記事末尾だけでなく、価格セクションにも自然に置きます。たとえば「テンプレートで自走する」「90分相談でレビューする」「チーム研修で標準化する」の3択にすると、読者は自分の段階を選びやすくなります。
フォームスキーマとAstro APIを作る
フォームは入力欄を並べるだけでは不十分です。スキーマ、つまり「どの項目を、どの形式で受け取るか」という約束を決めます。次のAPIは依存パッケージなしで動く最小例です。src/pages/api/lead.tsに置くと、AstroのAPIエンドポイントとして使えます。
// 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;
};
const maxLength = {
name: 80,
email: 120,
company: 120,
goal: 1000,
} as const;
function readString(form: FormData, key: keyof typeof maxLength) {
const value = String(form.get(key) ?? "").trim();
return value.slice(0, maxLength[key]);
}
function validateLead(form: FormData): { ok: true; data: LeadInput } | { ok: false; errors: string[] } {
const data: LeadInput = {
name: readString(form, "name"),
email: readString(form, "email"),
company: readString(form, "company"),
goal: readString(form, "goal"),
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" },
});
};
注意点は、イベント計測にメールアドレスや相談内容を送らないことです。フォーム処理には個人情報が含まれますが、分析イベントにはbudgetやcta_idのような分類だけを入れます。GA4のイベント設計はGoogle Analytics eventsを確認してください。
React側は、ラベルとエラー領域を明示します。
// src/components/LeadForm.tsx
import { useState } from "react";
import { trackLpEvent } from "../lib/lp-events";
export function LeadForm() {
const [status, setStatus] = useState<"idle" | "sending" | "done" | "error">("idle");
const [message, setMessage] = useState("");
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setStatus("sending");
const form = event.currentTarget;
const response = await fetch("/api/lead", {
method: "POST",
body: new FormData(form),
});
if (!response.ok) {
const body = await response.json();
setStatus("error");
setMessage(body.errors?.join(" ") ?? "Please check the form.");
return;
}
trackLpEvent({ eventName: "lead_submit", ctaId: "lead-form", value: "consulting" });
setStatus("done");
setMessage("送信しました。確認メールをご確認ください。");
form.reset();
}
return (
<form id="lead-form" onSubmit={onSubmit} className="space-y-5 rounded-lg border border-slate-200 p-6">
<div>
<label htmlFor="name" className="block text-sm font-medium">お名前</label>
<input id="name" name="name" required className="mt-1 w-full rounded-md border px-3 py-2" />
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium">メールアドレス</label>
<input id="email" name="email" type="email" required className="mt-1 w-full rounded-md border px-3 py-2" />
</div>
<div>
<label htmlFor="goal" className="block text-sm font-medium">改善したいLPや相談内容</label>
<textarea id="goal" name="goal" required minLength={20} rows={5} className="mt-1 w-full rounded-md border px-3 py-2" />
</div>
<div>
<label htmlFor="budget" className="block text-sm font-medium">検討中の支援</label>
<select id="budget" name="budget" className="mt-1 w-full rounded-md border px-3 py-2">
<option value="template">テンプレート</option>
<option value="consulting">個別相談</option>
<option value="training">チーム研修</option>
<option value="undecided">未定</option>
</select>
</div>
<label className="flex gap-2 text-sm">
<input name="consent" type="checkbox" required />
入力内容を問い合わせ対応に利用することに同意します。
</label>
<button disabled={status === "sending"} className="min-h-11 w-full rounded-md bg-slate-950 px-5 font-semibold text-white disabled:opacity-60">
{status === "sending" ? "送信中..." : "相談内容を送る"}
</button>
<p role="status" aria-live="polite" className="text-sm">{message}</p>
</form>
);
}
イベント計測は最初から命名を固定する
計測は公開後に足すものではありません。LP公開時点で、表示、クリック、送信、商品遷移、スクロール深度を同じ命名規則で送れるようにします。個人情報を送らず、分析に必要な粒度だけを残します。
// 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);
}
document.addEventListener("click", (event) => {
const target = event.target instanceof Element ? event.target.closest("[data-cta-id]") : null;
if (!target) return;
trackLpEvent({
eventName: "cta_click",
ctaId: target.getAttribute("data-cta-id") ?? "unknown",
});
});
速度指標はweb.devのCore Web Vitalsを基準にします。特にLCP、つまりLargest Contentful Paintは「ページの主要コンテンツが見えるまでの時間」です。LPではヒーロー画像、見出し、CTAが重いとLCPが悪化します。
A/Bテストは「勝った風」にしない
A/Bテストは、2案を出して気分で選ぶことではありません。どの仮説を、どのイベントで、どの期間見るかを先に決めます。小規模サイトでは統計的に十分なサンプルが集まらないことも多いため、「確実にCVRが上がる」と書かないほうが誠実です。
AstroのSSRまたはサーバー出力が使える環境なら、初回表示前にCookieでvariantを固定します。
// 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>
落とし穴は、localStorageだけでvariantを決めることです。初回描画後にコピーが差し替わると、読者にはちらつきが見えます。計測上も、表示されたvariantとクリック時のvariantがずれることがあります。
Playwrightでスマホ表示を確認する
手元で目視しても、フォームやCTAはスマホで崩れます。Playwrightのassertionsを使い、横スクロール、CTAの可視性、フォーム送信、A/B variantの安定性を確認します。
// 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 validates required consent", async ({ page }) => {
await page.goto("/lp");
await page.getByLabel("お名前").fill("Masa");
await page.getByLabel("メールアドレス").fill("masa@example.com");
await page.getByLabel("改善したいLPや相談内容").fill("Claude Code研修LPの問い合わせ率を改善したいです。");
await page.getByRole("button", { name: "相談内容を送る" }).click();
await expect(page.getByLabel("入力内容を問い合わせ対応に利用することに同意します。")).toBeFocused();
});
このテストは売上を証明しません。証明するのは、少なくともスマホでCTAが見え、フォームが壊れておらず、計測前提が崩れていないことです。
よくある失敗例
1つ目は、オファーが曖昧なままデザインに入ることです。「AIで業務改善」では広すぎます。「Claude CodeでLPを実装し、フォームと計測まで1週間で整える」のように、対象、成果物、期限を具体化します。
2つ目は、信頼ブロックが薄いことです。ロゴや数字を置くだけでは不十分です。Masaが実際にどの検証をしたか、どこで失敗したか、公開前に何をチェックするかを書くほうが信頼につながります。
3つ目は、価格や次の行動を隠すことです。問い合わせフォームだけを置くと、読者は負担を想像して離脱します。無料チェックリスト、テンプレート、個別相談、研修の選択肢を明確にします。
4つ目は、計測イベントが後付けになることです。button_click、ctaClicked、lead-submitのように名前がばらつくと、改善判断が遅くなります。
5つ目は、アクセシビリティを軽く見ることです。ラベルのないフォーム、キーボードで押せないCTA、薄すぎる文字色は、そのまま機会損失になります。Reactのフォーム設計ではReact formsも確認してください。
ClaudeCodeLabの導線に自然につなげる
このテーマのCTAは「今すぐ契約してください」だけでは弱いです。読者の成熟度に合わせて、次の3段階を置くと自然です。
| 読者の段階 | CTA | ClaudeCodeLabでの提案 |
|---|---|---|
| まず自分で試したい | LPチェックリスト、Astroテンプレート | ClaudeCodeLab products |
| LPをレビューしてほしい | 90分の導線レビュー | Claude Code trainingの前段相談 |
| チームで標準化したい | 実装研修、レビュー演習、計測設計 | 法人向けClaude Code研修 |
関連記事として、計測はClaude Codeでアナリティクスを実装する、A/BテストはClaude CodeでA/Bテストを設計する、スマホ確認はClaude CodeでPlaywrightテストを作る、SEOはClaude CodeでSEO最適化するも合わせて読むと、LP公開後の改善までつながります。
まとめ
Claude Codeでランディングページを作るなら、セクション生成だけで終わらせないでください。最初にオファーを明確にし、ファーストビューで約束を伝え、信頼ブロックで不安を減らし、フォームとCTAを実装し、イベント計測とA/Bテストで改善できる状態にします。
重要なのは、CVR改善を保証することではなく、改善できる構造を作ることです。Astro、React、Tailwind CSS、Playwrightを組み合わせれば、LPの見た目だけでなく、入力、計測、検証まで1つの実装として扱えます。
実際に試した結果
この記事の構成で小さな検証LPを作ったところ、Masaが一番助かったのはデザイン案ではなく、計測名とフォーム項目が最初に固定されたことでした。以前は公開後に「どのCTAが押されたのか」が曖昧になり、改善判断が遅れていました。今回の形では、スマホ表示、フォーム必須項目、CTAクリックをPlaywrightとイベントで確認でき、少なくとも「見た目は良いが何も学べないLP」からは脱出できました。成果を保証するものではありませんが、相談、テンプレート、研修へつなげる検証の土台としては実用的です。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
ObsidianメモをCLAUDE.mdに変えるClaude Code運用: 文脈を毎回説明しない仕組み
Obsidianの作業メモからCLAUDE.md用の運用ノートを作り、Claude Codeに安定した文脈を渡す方法。
Claude Code Revenue CTA Routing: 記事からPDF、Gumroad、相談へ送る設計
PVだけで終わらせず、読者の状態に合わせて無料PDF、Gumroad教材、導入相談へ分岐するCTA設計です。
Claude Codeチーム引き継ぎルール: レビュー、権限、収益導線まで渡す実務手順
Claude Codeの作業をチームで渡すための証拠、権限、ロールバック、無料PDF/Gumroad/相談導線の実務ルール。