Webフォームからリードを作るときの落とし穴
Web-to-Lead は設定だけで使えて便利ですが、 リードが作られなかったときに、送信した人の画面には成功として見えます。 気づかないうちに問い合わせを落としている可能性があります。
何が起きるのか
Web-to-Lead は、HTMLのフォームから Salesforce のエンドポイントへ直接POSTする仕組みです。 設定画面でHTMLを生成して貼るだけで動きます。開発が要りません。
ただし、送信を受けた側でリードが作られない場合があります。原因はいくつかあります。
- 入力規則に引っかかった
- 必須項目が空だった
- 重複ルールが既存のレコードと一致した
- 都道府県・国の選択リストが有効で、国の指定なしに都道府県を送った
- 1日の上限(500件)を超えた
このとき、Salesforce は「Default Lead Creator」に設定されたユーザーへメールを送ります。 件名は「Salesforce could not create this Lead」です。 管理者はメールを見れば気づけます。
問題は送信した人の側です。Web-to-Lead にはフォーム上に成功・失敗を出す仕組みがありません。
指定した retURL のページに遷移するだけなので、
そこに「送信ありがとうございました」と書いてあれば、失敗していても成功に見えます。
イベントの申込フォームだと、これが事故になります。 同じ人が何度も申し込むので重複ルールに当たりやすく、しかも本人は申し込めたと思っています。
ほかに知っておきたい制約
| 項目 | 内容 |
|---|---|
| 1日の上限 | 500件/24時間。超えた分はキューに入り、翌日以降に処理されます。キューは Web-to-Case と合算で5万件まで。それを超えると破棄されます |
| 失敗の通知 | Default Lead Creator へのメールのみ。宛先はカスタマイズできません |
| reCAPTCHA | v2 のみ対応(v3は動きません)。組織IDがフォームのHTMLに含まれるため、フォームを経由せず直接POSTされる余地があります |
| 画面表示 | 成功・失敗のメッセージをフォーム上に出せません |
| 項目の制御 | 条件による表示切り替えや、項目同士の依存関係は作れません |
どう作れば取りこぼさないか
フォームから Salesforce のエンドポイントへ直接POSTするのをやめて、 間にサーバー側の処理を1つ挟みます。 そこから REST API でリードを作ります。
こうすると、API のレスポンスが読めます。成功か失敗かが分かるので、 送信した人の画面に正しく返せます。これがいちばん大きな違いです。
// サーバー側(例:Cloudflare Pages Functions / Node) // 1. トークンを取る(クライアントクレデンシャル) const tok = await fetch(`${SF_URL}/services/oauth2/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'client_credentials', client_id: env.SF_CLIENT_ID, client_secret: env.SF_CLIENT_SECRET, }), }).then(r => r.json()); // 2. リードを作る const res = await fetch( `${SF_URL}/services/data/v64.0/sobjects/Lead`, { method: 'POST', headers: { Authorization: `Bearer ${tok.access_token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ LastName: form.lastName, Company: form.company || '', // 空でも可 Email: form.email, Inquiry__c: form.body, LeadSource: 'Website', FormType__c: 'お問い合わせ', SubmittedURL__c: form.pageUrl, }), } ); // 3. 結果を利用者に返す ── ここが直接POSTとの決定的な違い if (!res.ok) { const err = await res.json(); console.error(err); // 原因はログへ return fail('送信できませんでした'); // 画面に正直に出す } return ok();
エラーの本文には FIELD_CUSTOM_VALIDATION_EXCEPTION などの原因が入ってきます。何が起きたか分かります。
やってはいけないこと
「取りこぼしを防ぐために、送信内容をいったんこちら側に保存しておく」という設計を考えたくなります。 これはやめたほうがいいです。
問い合わせの内容には個人情報が含まれます。Salesforce 以外にもう1か所コピーができると、 保存期間・暗号化・アクセス権・削除の責任者・障害復旧時の重複防止まで設計しなければなりません。 取りこぼし対策のために、別の漏えいリスクを作ることになります。
REST 経由にする本当の価値は「失敗を正しく伝えられること」です。 失敗したら画面に出して、電話番号やメールアドレスなど別の連絡手段を案内する。 それで足ります。保存する必要はありません。
権限は「作成だけ」にする
サーバー側の処理に持たせる権限は、リードの作成だけにしてください。 参照・編集・削除は与えません。
既存のリードを検索して更新する(Upsertする)作りにしたくなりますが、 そのためには参照権限が必要になります。 もし認証情報が漏れたときに、既存の顧客データを読み出される余地が生まれます。 重複の整理は Salesforce 側のフローや重複ルールでやるほうが安全です。
まとめ
- Web-to-Lead は、失敗しても送信者の画面には成功に見えます
- 失敗の通知は Default Lead Creator へのメールだけで、宛先は変えられません
- 同じ人が何度も送るフォーム(イベント申込など)では事故になります
- サーバー側を1つ挟んで REST API で作れば、結果を正しく返せます
- 取りこぼし対策で送信内容を保存するのはやめましょう。個人情報が2か所になります
- 権限は「作成だけ」に絞ります
この記事の背景
自社サイトの作り替えで、この判断を実際にしました。 当初は「取りこぼしたときのために保存する」設計を書いていましたが、 別の視点から検証したところ、個人情報を二重に持つことになると分かって撤回しています。 AIと業務システムの連携支援のページに、その進め方を書いています。
あわせて読む
- 問い合わせの取りこぼしを、仕組みで止めた ── ここで書いた考え方を実際に適用した事例です
- Salesforceカスタマイズ ── フォームと Salesforce をつなぐご相談はこちらから