外部サービス連携

Webフォームからリードを作るときの落とし穴

2026.07.28 / 読了 9分 / 水本 勲

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 へのメールのみ。宛先はカスタマイズできません
reCAPTCHAv2 のみ対応(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と業務システムの連携支援のページに、その進め方を書いています。

あわせて読む

これは公開前のモックです(2026-08-13 ソル作成)

気になった箇所はページ名で指摘してください。すぐ直します。