「スパムは止めたい、でもCVRは落としたくない」——採用サイトの現場で一番悩ましいテーマを、“段階的ブロック”ד入力しやすさ”で両立させるテンプレに落とし込みました。reCAPTCHA v3とハニーポット、エラー表示の作法、autocomplete
やinputmode
の活用、途中保存、そしてINP(操作応答性)まで、今日から使える実装をまとめます。
1. 目標KPIと計測のセット
- 到達(form_view)→開始(form_start)→送信(form_submit)をイベント分解
- 送信成功(apply_success)とエラー率(error_rate=エラー発生/開始)を別トラック
- スパム判定ログ(bot_flag)を別途計測し、CVRから除外して媒体/導線を正しく評価
2. スパムを止める“二段構え”
2-1. reCAPTCHA v3(スコア判定)
- ユーザーに負担をかけずにスコア(0.0〜1.0)で判定。
action
ごとにスコアを分解して監視 - 推奨フロー:最初は記録のみ → しきい値(例0.5)を決める → サーバー側で可変アクション(即ブロックではなく遅延・二段確認)
<!-- 1) reCAPTCHA v3 を読み込み(sitekey を差し替え) -->
<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY"></script>
<form id="apply-form" action="/apply" method="post" novalidate>
<!-- 通常の項目 -->
<label for="name">氏名</label>
<input id="name" name="name" type="text" required autocomplete="name" inputmode="text">
<label for="tel">電話番号</label>
<input id="tel" name="tel" type="tel" required autocomplete="tel" inputmode="tel">
<label for="email">メールアドレス</label>
<input id="email" name="email" type="email" required autocomplete="email" inputmode="email">
<!-- 2) ハニーポット(人間には見えない) -->
<div class="hp">
<label for="company">会社名(記入しないでください)</label>
<input id="company" name="company" type="text" tabindex="-1" autocomplete="off">
</div>
<!-- 3) reCAPTCHA のトークン受け取り用 -->
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response">
<button id="apply-submit" type="submit">30秒で応募</button>
<!-- エラー表示領域(スクリーンリーダーに通知) -->
<div id="form-errors" role="alert" aria-live="assertive"></div>
</form>
<style>
/* ハニーポットは「非表示」ではなく画面外へ(bot は埋めやすい/人は見えない) */
.hp{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden;}
</style>
<script>
(function(){
const form = document.getElementById('apply-form');
const btn = document.getElementById('apply-submit');
const err = document.getElementById('form-errors');
// 入力バリデーション(簡易)
function validate(){
err.textContent = '';
const required = ['name','tel','email'];
for (const id of required){
const el = document.getElementById(id);
if(!el.value.trim()){ err.textContent = '未入力の必須項目があります。'; return false; }
}
// ハニーポット:値が入っていたら即中断
if(document.getElementById('company').value.trim()){ err.textContent = '送信に失敗しました。'; return false; }
return true;
}
form.addEventListener('submit', function(e){
e.preventDefault();
if(!validate()) return;
btn.disabled = true; btn.textContent = '送信中...';
// reCAPTCHA v3 を実行(action="apply")
grecaptcha.ready(function(){
grecaptcha.execute('YOUR_SITE_KEY', {action: 'apply'}).then(function(token){
document.getElementById('g-recaptcha-response').value = token;
form.submit(); // 最後にサーバへ
}).catch(function(){
err.textContent = '認証に失敗しました。時間をおいて再度お試しください。';
btn.disabled = false; btn.textContent = '30秒で応募';
});
});
});
})();
</script>
※サーバー側では /recaptcha/api/siteverify
で必ず検証し、score
とaction
をチェック。しきい値を下回る場合は即ブロックよりも「メール確認を要求」「送信間隔の制限(レートリミット)」など段階制御にするとCVRを守れます。
2-2. ハニーポット(ゼロ摩擦)
- “人間には見えないテキスト入力”を置き、入力されていたらボットと判断
display:none
ではなく画面外へオフセット(単純botがより反応)
3. 入力しやすさでCVRを上げる(WCAG/ブラウザ支援)
- ラベルは必須:各
<input>
に明示ラベル+エラーはテキストで説明(色だけにしない) - エラーは近くに/即時に:誤りのある項目を特定して、どう直すかを短く表示(
role="alert"
やaria-live
で支援技術へ通知) - 入力補助:
autocomplete
(例:name
/email
/tel
)、inputmode
(tel
/email
)でソフトキーボード最適化
4. 途中保存と夜間応答で離脱を減らす
- 途中保存:ローカルストレージに名前・電話・メール程度を自動保存(明示同意を得る)。復元可視化で“書き直し疲れ”を防止
- 夜間応募:受付自動返信に「翌営業日に必ずご連絡」を明記。LINE導線があるなら追加入り口を併記
5. INP(操作応答性)を落とさない実装
- 送信/開閉/タブ切替などユーザー操作直後の処理を軽く:重い処理は
requestIdleCallback
やWeb Workerへ - 長い同期処理は分割(Long Tasksを回避):バリデーションやマスキングの重い正規表現は最適化
- 外部ウィジェット(チャット/解析/ABテスト)は遅延読込+必要ページのみに限定
6. よくある失敗と回避策
- 「reCAPTCHAのスコアだけで即ブロック」→ 一時的に良ユーザーも弾く。二段制御で被害最小化
- 「エラーが色だけ」→ テキスト説明+アイコン併用、
aria-live
で補助技術にも通知 - 「autocomplete=offの多用」→ 使える所は積極活用。入力負担を減らして送信率を上げる
チェックリスト(実装前/後の確認)
- form_view / form_start / form_submit を計測し、各ステップの到達率が出る
- reCAPTCHA v3 の
action
別スコアをまず蓄積→しきい値決定→段階制御 - ハニーポットは画面外オフセット、ログでヒット率を監視
- ラベル・エラーメッセージはテキスト+視覚的強調、
aria-live
あり autocomplete
とinputmode
を適切に設定- 送信直後の処理は軽量化(INP対策)、外部タグは遅延読込
まとめ
スパム防止はレイヤーで重ねる、CVR改善は入力を楽に/間違いを早く直せる。両輪を満たすと、媒体や導線の評価もブレなくなります。まずは「記録→しきい値決定→段階制御」から始めましょう。
コメント