リード獲得フォーム

リード獲得フォーム1 分で読めます

商談の予約までつなげるデモ依頼フォームを作る

リードを保存してから、名前とメールアドレスを入力済みの状態で訪問者を Cal.com や Calendly に送るデモ予約フォームです。

Preet SutharIkiform 創業者

まずデモ依頼をフォームバックエンドに送信すれば、訪問者が日時を選ばなくても、リードが保存されチームにメールが届きます。そのあと、クエリ文字列に name と email を付けてブラウザーを予約ページに送ります。Calendly と Cal.com はこれを使ってフォームを事前入力します。小さなチームはデモ動画など別の場所に送り、カレンダーは成約につながる商談のために空けておきましょう。

デモ依頼ならではの違い

デモを依頼する人がほしいのは、メールのやり取りではなくカレンダー上の時間です。「火曜日はいかがですか?」のやり取りが 1 往復増えるたびに、他社で予約される機会が生まれます。だからフォームの役割は短く、見込み度を判断できるだけの情報を集めたら、タブを開いているうちにカレンダーを見せることです。

作りを左右する制約は 3 つあります。

  • 予約ページを開く前にリードを保存する。 予約ページを開いて閉じてしまう訪問者は大勢います。記録が予約ツールの中にしかなければ、そのリードは失われます。先に Ikiform に送信し、成功したときだけリダイレクトしてください。
  • _redirect には入力内容を載せられない。 決まった URL で、Ikiform がそれに従うのは Allowed domains のどれかにある https: の URL の場合だけです。そこに cal.com や calendly.com を追加すると、それらのサイトからの送信も通ってしまいます。代わりに自分のコードで予約リンクを組み立ててください。
  • すべての依頼がライブの商談に値するわけではない。 チーム向け製品のデモを依頼する 1 人の創業者には、デモ動画と登録リンクのほうが役に立ちます。選択式の質問 1 つで、ブラウザーの次の行き先を決めます。
保存したあと、デモ依頼がどこへ向かうかデモフォーム名前、メール、会社、チームの規模Ikiform保存、チームにメールチームの規模は?予約ページ名前とメールを事前入力デモ動画登録リンク付き送信ok11 人以上1〜10 人保存したあと、デモ依頼がどこへ向かうかデモフォーム名前、メール、会社、チームの規模Ikiform保存、チームにメールチームの規模は?予約ページ名前とメールを事前入力デモ動画登録リンク付き送信ok11 人以上1〜10 人
  1. 訪問者が名前、仕事用のメールアドレス、会社、チームの規模を入力し、フォームが Ikiform に送信します。
  2. Ikiform が依頼を保存してチームにメールを送ります。ok が返るまで、ほかには何も起きません。
  3. コードが、訪問者が選んだチームの規模を読みます。
  4. 11 人以上のチームは、クエリ文字列に名前とメールアドレスを付けて予約ページへ。
  5. 1〜10 人のチームは、登録リンク付きのデモ動画へ。
分岐は、Ikiform がリードを受け取ったあとにコードで行います。どちらの場合もチームにはすべての依頼が届くので、商談すべきだった小さなチームも見落としません。

4 つのフィールド、うち 1 つは振り分け用

フィールド種類理由
nameテキスト予約フォームに事前入力されるので、訪問者は 1 回入力するだけ
emailメール予約フォームに事前入力され、通知メールの reply-to になる
companyテキスト、ここでは必須担当者が商談の前に調べる
team_size選択予約ページかデモ動画かを決め、決まった 4 つの値のどれかで届く

用途、時期、電話番号は商談のときに聞きましょう。会議の前に背景を知りたいなら、予約ツール側で質問を 1 つ追加できます。Calendly も Cal.com も、カスタムの質問も事前入力できます。

送信してから引き継ぐ

どの版も依頼を送信し、Ikiform の応答を待ってから、次の URL を組み立てます。例では Cal.com を使っています。Calendly ならイベントのリンクに差し替えてください。Calendly は事前入力のパラメーターとして name と email をドキュメントに記載しており、Cal.com は name と email を含め、どの予約フィールドも識別子で事前入力できます。

フォームとスクリプトをまとめたものです。JavaScript がなくてもフォームは送信され、Redirect after submit のページに移動するので、そこに予備として予約リンクを置いてください。

demo.html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="POST" id="demo-form">
  <label for="name">Name</label>
  <input id="name" name="name" autocomplete="name" required />

  <label for="email">Work email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />

  <label for="company">Company</label>
  <input id="company" name="company" autocomplete="organization" required />

  <label for="team_size">Team size</label>
  <select id="team_size" name="team_size" required>
    <option value="1_10">1 to 10</option>
    <option value="11_50">11 to 50</option>
    <option value="51_200">51 to 200</option>
    <option value="201_plus">201 or more</option>
  </select>

  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <p role="alert" id="demo-error" hidden></p>
  <button>Pick a time</button>
</form>

<script>
  const BOOKING = "https://cal.com/acme/demo";
  const SELF_SERVE = "/tour";
  const form = document.getElementById("demo-form");
  const error = document.getElementById("demo-error");

  form.addEventListener("submit", async (event) => {
    event.preventDefault();
    const data = new FormData(form);
    form.querySelector("button").disabled = true;
    error.hidden = true;
    try {
      const response = await fetch(form.action, {
        method: "POST",
        headers: { Accept: "application/json" },
        body: data,
      });
      const result = await response.json();
      if (!result.ok) throw new Error(Object.values(result.error.fields ?? {})[0]?.[0] ?? result.error.message);
      const small = data.get("team_size") === "1_10";
      const next = new URL(small ? SELF_SERVE : BOOKING, location.href);
      next.searchParams.set("name", String(data.get("name")));
      next.searchParams.set("email", String(data.get("email")));
      location.assign(next);
    } catch (failure) {
      error.textContent = failure instanceof Error ? failure.message : "Couldn't send. Try again.";
      error.hidden = false;
      form.querySelector("button").disabled = false;
    }
  });
</script>
サーバー側の版はシークレットキー付きで送信するので、Ikiform は Allowed domains と人間確認をスキップします。その場合はすべての送信がサーバーの IP から来るため、訪問者ごとに 1 分あたり 5 件という Standard の制限が、全訪問者をまとめて数えることになります。サーバー経由で送信するフォームには Relaxed か Custom のレート制限を選び、IKIFORM_SECRET_KEY はサーバー専用の環境変数に置いてください。サーバー側の fetch は Origin を送らず、Ikiform は無料の localhost テストをそこから判別するので、サーバーの版は訪問者の Origin ヘッダーを転送します。

Gmail をブロックせずに仕事用のメールアドレスを扱う

Ikiform には、フリーメールのプロバイダーを拒否する設定はありません。メールのフィールドの allowed_domains オプションは許可リストで、自社のドメインに限った社内フォームには便利ですが、公開のデモフォームには向きません。それで問題ありません。Gmail をブロックすると、スマートフォンからフォームに入力する創業者、コンサルタント、購入検討者もブロックしてしまうからです。

代わりに、チームが目にする場所でそうした依頼にタグを付けましょう。この関数は、各依頼をチャットや CRM に送るリレーの中で動き、商談の前に担当者にヒントを与えます。

lib/demo-tag.ts
const FREE_MAIL = new Set(["gmail.com", "googlemail.com", "outlook.com", "hotmail.com", "yahoo.com", "icloud.com", "proton.me"]);

export function demoTag(fields: Record<string, unknown>) {
  const domain = String(fields.email ?? "").split("@")[1]?.toLowerCase() ?? "";
  const size = String(fields.team_size ?? "");
  if (FREE_MAIL.has(domain)) return "personal address, check the company";
  if (size === "51_200" || size === "201_plus") return "priority";
  return "standard";
}

verifyWebhook のあとに event.data.fields を渡して呼び、タグをチャットのメッセージか CRM のプロパティに追加します。リレーの全体は HubSpot や Pipedrive にリードを送るにあります。

動作を確認する

  1. Allowed domains にサイトのドメインと localhost を追加します。
  2. チームの規模を 51 to 200 にして送信します。名前とメールアドレスが入力済みの状態で予約ページが開きます。
  3. 日時を選ばずに予約ページを閉じます。依頼は Submissions に残っていて、通知メールも受信トレイに届いています。
  4. 1 to 10 でもう一度送信し、デモ動画に移動することを確認します。
  5. 無効なメールアドレスで送信します。フォームにエラーが表示され、予約ページは開きません。
  6. テストの会議を予約し、予約ツールの確認メールが入力したアドレスに届くことを確認します。

ハマりどころ

  • 予約されたデモ 1 件につき記録は 2 つ。 Ikiform が依頼を、予約ツールが会議を持っています。CRM では名前ではなくメールアドレスで照合してください。
  • Ikiform からの確認メールはない。 Ikiform はフォームに入力した人にはメールを送りません。予約された商談は、予約ツール自身の確認メールとカレンダーの招待でカバーされます。予約に至らなかった依頼には、その日のうちに通知メールから返信してください。
  • クエリ文字列は見える。 予約 URL の名前とメールアドレスは、ブラウザーの履歴と予約ツールのアナリティクスに残ります。それ以外のものは渡さないでください。
  • 埋め込み。 代わりに予約ツールを自分の /book ページに埋め込む場合、Cal.com がページのクエリパラメーターを引き継ぐのは forwardQueryParams をオンにしたときだけです。Calendly は埋め込み時の事前入力を JavaScript の埋め込みの prefill オブジェクトで行うと記載しているので、素の iframe ではなくそちらを使ってください。
  • スパムチェック。 Spam check を Ikiform にしている場合、ブラウザーの版は送信前に @ikiform/sdk の challenge() を呼ぶ必要があり、呼ばないと 403 challenge_required が返ります。サーバーの版はチェックをスキップします。

よくある質問

手順で詰まったときや、あなたの状況に合うガイドがほしいときはメールでどうぞ: hello@ikiform.com