netlify-forms について
netlify-forms は、Netlify のフォーム設定とトラブルシューティングを支援する開発者向けスキルです。ビルド時のフォーム検出、静的なスケルトンファイル、AJAX 送信、スパム対策、送信データの取得方法を扱います。
主な機能
- 01HTML 属性によるフォーム検出の有効化
- 02動的フォーム用の静的スケルトン準備
- 03URL エンコードによるフォーム送信
- 04アップロードと完了ページの設定
- 05ハニーポットと reCAPTCHA によるスパム対策
- 06ページネーション付き API による送信データ取得
活用シーン
- 01静的サイトでフォーム送信を収集
- 02SSR または JavaScript 生成フォームの登録と送信
- 03見つからないフォーム送信の調査
- 04スパム送信の取得と確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ netlify/ context-and-tools --skill netlify-formsインストール後、Claude Code で/netlify-formsを入力して読み込まれたか確認します。
詳細
Netlify フォーム
<form> タグに data-netlify="true"(または同等の netlify 属性のみ)を指定して、フォームを検出対象にします。フォームはデプロイ時に最終ビルド済み HTML を解析して検出されます。実行時の API 呼び出しやバックエンドコードはありません。クライアント側で生成されるフォーム、JS でレンダリングされるフォーム、SSR フォームはビルド済み HTML に含まれないため、それだけでは検出されません。静的なスケルトンファイルが必要です(下記参照)。
前提条件:Netlify の UI でフォーム検出を一度有効にする必要があります(Forms > フォーム検出を有効にする)。次回のデプロイから反映されます。
静的 HTML フォーム
<form name="contact" method="POST" data-netlify="true">
<p><label>Your Name: <input type="text" name="name" /></label></p>
<p><label>Your Email: <input type="email" name="email" /></label></p>
<p><label>Message: <textarea name="message"></textarea></label></p>
<p><button type="submit">Send</button></p>
</form>
nameは UI に表示されるフォーム名を設定します。サイトごとに一意である必要があります。- デプロイ時に Netlify は
data-netlify/netlify属性を削除し、<input type="hidden" name="form-name" value="contact" />を挿入します。 - 通知メールの
Reply-toに送信者のアドレスが設定されるよう、<input name="email">を追加します。
JS レンダリング/SSR/フレームワークのフォーム(Next.js、Nuxt、SvelteKit、Astro、Gatsby)
必要な要素は 2 つです。
1. 静的スケルトンファイル public/__forms.html — data-netlify="true" と非表示の form-name 入力フィールド、およびコンポーネントが送信するすべてのフィールドを含む、各フォームの非表示コピーです。フィールド名は完全に一致している必要があります(Netlify はフィールド名を登録済みフォームと照合して検証します)。このファイルがないと、送信は何も通知されずに失敗します。
<form name="pizzaOrder" data-netlify="true" hidden>
<input type="hidden" name="form-name" value="pizzaOrder" />
<input name="order" type="text" />
</form>
2. レンダリングされたフォームには、一致する非表示の form-name 入力フィールドを含めます。
<form name="pizzaOrder" method="post" data-netlify="true" onSubmit={handleSubmit}>
<input type="hidden" name="form-name" value="pizzaOrder" />
<input name="order" type="text" onChange={handleChange} />
<input type="submit" />
</form>
⚠️ SSR の POST 先: SSR アプリでは、fetch("/") は SSR のキャッチオール関数に横取りされ、フォーム処理には到達しません。/ や任意のパスではなく、静的スケルトンファイル自体である /__forms.html に POST してください。
⚠️ Astro のオンデマンドルート: export const prerender = false または output: "server" を指定したルートはビルド時にスキャンされないため、フォームも登録されません。フォームをプリレンダリングされたページに配置するか、静的スケルトンファイルを使用してください。
Next.js Runtime v5(Next.js 13.5 以降): フォーム定義を静的スケルトンファイルに抽出し、ページ全体を遷移する代わりに AJAX で送信してください。https://docs.netlify.com/build/frameworks/framework-setup-guides/nextjs/overview#v5-breaking-changes を参照してください。
AJAX による送信
const handleSubmit = event => {
event.preventDefault();
const formData = new FormData(event.target);
fetch("/__forms.html", { // static sites may POST to "/"; SSR must target the skeleton file
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams(formData).toString()
})
.then(() => alert("Thank you for your submission")) // or navigate("/thank-you")
.catch(error => alert(error));
};
document.querySelector("form").addEventListener("submit", handleSubmit);
- 本文は URL エンコードする必要があります。JSON はサポートされていません。
- レンダリングされたフォームに非表示の
form-name入力フィールドがない場合は、POST 本文にform-nameフィールドを含める必要があります。 - ハニーポットのフィールド名と
g-recaptcha-response(使用する場合)は本文に含める必要があります。FormData()を使えば自動的に含まれます。
ファイルのアップロード
type="file" を追加します。必要に応じて <form> に enctype="multipart/form-data" を指定します。AJAX でファイルをアップロードする場合、Content-Type ヘッダーを設定しないでください。ブラウザーが(multipart の境界とともに)設定します。
document.forms.fileForm.addEventListener("submit", event => {
event.preventDefault();
fetch("/", { body: new FormData(event.target), method: "POST" }) // no headers
.then(() => { /* success */ });
});
制限:フィールドごとにファイルは 1 つ(複数のファイルには複数のフィールドを使用) · リクエストサイズは最大 8 MB · アップロードのタイムアウトは 30 秒 · フォームを削除した後も、アップロード済みファイルは直接 URL から 24 時間アクセスできます。PII を含むアップロードには、追加のセキュリティ対策が必要です(Very Good Security との統合)。
カスタム成功ページ
サイトのルートからの相対パスで、/ で始まる action パスを追加します。拡張子のないパスを使用してください。Netlify は /thank-you で thank-you.html を配信します。.html 付きのパスは 404 を返します。
<form name="contact" action="/thank-you" method="POST" data-netlify="true"></form>
カスタムの成功アラートは AJAX でのみ実現できます(リダイレクトを独自のロジックに置き換えてください)。
スパム対策
すべての送信内容は Akismet によってフィルタリングされます。通過したものは 認証済みの送信内容 に、スパムと判定されたものは スパムの送信内容 に分類されます。ハニーポット/reCAPTCHA の検証に失敗した送信は拒否され、どちらのリストにも表示されません。
ハニーポット: <form> に netlify-honeypot="bot-field" を追加し、その名前のフィールドを CSS で非表示にして含めます。値が入力されると、送信は通知なしで拒否されます。
<form name="contact" method="POST" netlify-honeypot="bot-field" data-netlify="true">
<p class="hidden"><label>Don’t fill this out: <input name="bot-field" /></label></p>
</form>
Netlify reCAPTCHA 2: <form> に data-netlify-recaptcha="true" を追加し、チャレンジを表示する場所に空の <div data-netlify-recaptcha="true"></div> を配置します。Netlify が提供するチャレンジは、1 ページにつき 1 つだけです。複数必要な場合は、カスタム reCAPTCHA を使用してください。JavaScript でレンダリングされるフォームでは、静的スケルトンファイルにも div を追加してください。
カスタム reCAPTCHA 2: 独自の reCAPTCHA スニペットと、<form> の data-netlify-recaptcha="true" に加え、次の環境変数を設定します。
SITE_RECAPTCHA_KEY— サイトキー(スコープ:ビルド+ランタイム)SITE_RECAPTCHA_SECRET— シークレット(スコープ:ランタイム)
メール通知と件名
デフォルトの送信元:[email protected]。件名は、非表示の subject 入力フィールド または Netlify UI(Forms > Submission notifications)で設定します。両方で設定しないでください。HTML の値が常に UI の設定より優先されます。
<input type="hidden" name="subject" value="New lead from %{formName} (%{submissionId})" />
使用できる変数:%{formName}、%{siteName}、%{submissionId}。2023 年 5 月 5 日 より前に作成されたフォームには、件名の先頭に [Netlify] が付きます。subject 入力フィールドに data-remove-prefix 属性を追加すると、この接頭辞を削除できます。
通知(メール/Webhook/Slack)は、UI の Forms > Submission notifications > Add notification で設定します。
ChatGPT の自動化:ChatGPT からフォーム送信イベントを購読し、それをトリガーに自動化を実行できます(例:新しい送信内容を確認し、フォローアップが必要なものにフラグを付ける)。設定方法:https://docs.netlify.com/build/build-with-ai/agent-setup-guides/use-netlify-with-chatgpt/#subscribe-to-netlify-events
API を使った送信内容の読み取り
ドキュメントに記載されたインターフェースのみを使用してください。api.netlify.com のエンドポイントを作り出したり、ローカルの CLI 設定ファイルからトークンを読み取ったりしないでください。リファレンス:https://open-api.netlify.com/#tag/submission/operation/listFormSubmissions
Linkヘッダーを使って結果をページ送りしてください。 最初のレスポンスだけを読み取るコードでは、残りが通知なしで取りこぼされます。listFormSubmissionsは、古いフィールドや削除済みのフィールドのデータも返します。これらは現在 UI に表示されません。?state=spamでスパムを検索します。
送信内容の概要(フィールドの順序が重要)
UI の概要は、フィールドの名前ではなく タイプ に基づいて作成されます。
- タイトル: 最初に見つかった、非表示ではないテキストの
<input>のうち、メールアドレスらしくないもの(type="email"、または名前がemail/mail/from/twitter/senderに一致するものを除く)。該当するものがない場合は、titleまたはsubjectという名前のフィールドが使われます。 - 本文: 最初の
<textarea>。
HTML 内のフィールドの順序によって、概要に表示される内容が変わります。
送信内容が見つからない場合のデバッグ
- まず Akismet の誤判定を疑ってください。 正当な送信内容が見つからない場合、通常はスパムとしてフラグが付けられています。Spam リスト(または API の
?state=spam)を確認し、認証済みとしてマークしてください。最初の手段として、独自の復旧機能を構築したり、スパムフィルタリングを無効にしたりしないでください。 - テスト送信がスパムと判定される場合:実際のメールアドレス(
[email protected]ではないもの)を使い、文章を最後まで書き、同じ IP から大量に送信しないでください。 - 送信がまったくない場合:フォーム検出が有効になっていること(Forms > Form detection)を確認し、再デプロイしてください。
- SSR/JavaScript フォームが通知なしで失敗する場合:静的スケルトンファイルが存在し、フィールド名が完全に一致していること、および AJAX の送信先が
/ではなくスケルトンファイルであることを確認してください。 - 古いフィールドのデータが見つからない場合:UI に表示されるのは、最後にデプロイされたフォームバージョンのフィールドのみです。古いフィールドを削除する代わりに
hiddenとしてマークすると、表示を維持できます。古いデータはlistFormSubmissionsから引き続き取得できます。 - それでも解決しない場合:フォームのデバッグ方法に関する Netlify サポートガイド — https://answers.netlify.com/t/common-issue-how-to-debug-your-form/92
制約
- フォームを削除すると元に戻せません。以後の送信は
404を返し、過去の送信内容は取得できなくなります。先に CSV をエクスポートしてください。 - 送信されたコードはサニタイズされます(
<script>はエスケープされたエンティティになります)。 - 個人を特定できる情報(PII)については、定期的にデータをエクスポートして削除してください。
- データは Netlify のデータベースに保存され、UI/API/CSV 経由でのみアクセスできます。
Netlify のフォームに関する内部ルール
これらは組織内の慣習や現場で学んだガードレールであり、ドキュメントに記載された事実ではありません。ctx-gen によってレンダリングされるスキルに統合され、生成されることはありません。 以前の手書きの netlify-forms スキルから抽出したもので、スキルのメンテナーが管理しています。
- SSR アプリ(Next.js、Nuxt、SvelteKit など)では、
fetch("/")は SSR のキャッチオール関数に横取りされ、Netlify のフォーム処理には到達しません。 AJAX 送信は任意のパスではなく、静的なスケルトンファイル自体(例:/__forms.html)に POST してください。 - ドキュメント化されたインターフェースのみを使用してください。独自に考案したエンドポイント形式で
https://api.netlify.com/...に curl したり、ローカルの CLI 設定ファイル(~/Library/Preferences/netlify/config.json)からトークンを読み取ったりしないでください。 - API 経由で送信内容を読み取る場合は、結果をページ送りしてください(
Linkヘッダー)。最初のレスポンスだけを読み取るコードでは、残りが通知されずに失われます。 - JS レンダリングのフォームと SSR フォームでは、必ず静的なスケルトンファイル
public/__forms.htmlを作成してください。このファイルには、data-netlify="true"を指定した各フォームの非表示コピー、非表示のform-name入力、およびコンポーネントが送信するすべてのフィールドを含めます。フィールド名は完全に一致させてください(Netlify はフィールド名を登録済みフォームと照合して検証します)。このファイルがないと、送信は通知されずに失敗します。 - Astro のオンデマンドでレンダリングされるルート(
export const prerender = false、またはoutput: "server"のルート)はビルド時にスキャンされないため、そのフォームは登録されません。フォームはプリレンダリングされたページに配置するか、静的なスケルトンファイルを使用してください。 - 正当な送信が「見つからない」場合、たいていは Akismet による誤検知です。Spam リスト(または API の
?state=spam)を確認し、検証済みとしてマークしてください。最初の手段として、独自の復旧関数を作成したりスパムフィルタリングを無効にしたりしないでください。 - カスタムの成功ページでは、拡張子のない
actionパス(/thank-you、/thank-you.htmlではない)を使用してください。Netlify は/thank-youでthank-you.htmlを配信し、.htmlのパスは 404 を返します。