個人開発中の日記アプリでお問い合わせフォームにreCAPTCHA v3を導入したので、その記録をまとめました。
フロントエンドは Next.js (App Router)、フォーム送信には Backform を利用しています。
この記事では、Next.js(App Router)でreCAPTCHA v3を導入するための具体的な手順と、つまずきやすいポイントを解説していきます。
v2とv3の違いはこちらの記事を参照。
目次
reCAPTCHA v3 導入手順
1. Google reCAPTCHA 管理画面でキーを発行
Google reCAPTCHAのサイト登録画面にて、サイトを登録。
- v3 を選択
- 対象ドメインを登録(本番・ステージング・localhost)

「送信」すると、以下の2種類のキーが発行されます。
- サイトキー(フロント用)
- シークレットキー(Backform に登録する)
サイトキーはフロント、シークレットキーは Backform で管理します。
2. Backform 側でシークレットキーを登録
Backform の管理画面で該当フォームの設定画面を開く。基本設定>Google reCAPTCHA v3の設定
より下記を設定し、保存する。
- Google reCAPTCHA v3を有効にする にチェック
- 先ほど発行されたシークレットキーを入力

3. Next.js 側でサイトキーを環境変数に設定
# env.local
NEXT_PUBLIC_RECAPTCHA_SITE_KEY=xxxxx_your_site_key_xxxxx
4. フロントエンドに reCAPTCHA スクリプトを追加
app/layout.tsx などで <head>
内に script タグを追加します
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
const siteKey = process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY;
return (
<html lang="ja">
<body>
{children}
<Script
src={`https://www.google.com/recaptcha/api.js?render=${siteKey}`}
strategy="afterInteractive"
/>
</body>
</html>
);
}
5. フォーム送信時にトークンを付与
もともと作成していたフォームのコンポーネントに下記を追記。
"use client"
import { useEffect, useState } from "react";
function ContactForm() {
// reCAPTCHA トークンを管理
const [token, setToken] = useState<string>("");
// reCAPTCHA トークンを取得して hidden input にセット
const handleGenerateToken = async () => {
if (!window.grecaptcha) return;
const newToken = await window.grecaptcha.execute(
process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY!,
{ action: "submit" }
);
setToken(newToken);
};
useEffect(() => {
// ページロード時に一度トークン発行
handleGenerateToken();
}, []);
return (
<form
className="c-form"
action="https://backform.biz/api/c/2JlOGYey"
method="POST"
onSubmit={handleGenerateToken}>
// (中略)
{/* reCAPTCHA トークンを hidden input として送信 */}
<input type="hidden" name="g-recaptcha-response" value={token} />
<div>
<button className="c-form__send" type="submit">この内容で送信する</button>
</div>
</form>
)
}
export default ContactForm
以上で設定完了しました 🎉

ハマりポイント
ステージングでメール送信がエラーになる問題
- Backform 側の「送信後リダイレクトURL」が本番になっていた
- ステージング用に設定していなかったため
?error=reCAPTCHA verification failed
が出ていた
ドメイン登録忘れ
- reCAPTCHA 管理画面で、本番・ステージング・localhost 全て登録しておくこと
v2 と v3 のキーを間違えて使っていた
- v2 用のキーでは v3 の API が使えないので注意
実装後の挙動
- 問い合わせ送信時に reCAPTCHA が自動実行され、スパム送信を防げるようになった(はず)
- ユーザー側は「チェックボックスなし」で自然に送信できるので良い感じ。