리드 수집 폼

리드 수집 폼4분 분량

통화 예약까지 이어지는 데모 요청 폼 만들기

리드를 저장한 뒤 이름과 이메일이 미리 채워진 Cal.com이나 Calendly로 방문자를 보내는 데모 예약 폼입니다.

Preet SutharIkiform 창업자

먼저 데모 요청을 폼 백엔드로 POST하세요. 그러면 방문자가 시간을 고르지 않더라도 리드가 저장되고 팀에 이메일이 갑니다. 그다음 쿼리 문자열에 name과 email을 담아 브라우저를 예약 페이지로 보내세요. Calendly와 Cal.com은 이 값으로 폼을 미리 채웁니다. 소규모 팀은 녹화된 투어 같은 다른 곳으로 보내 캘린더에는 성사될 수 있는 통화만 남기세요.

데모 요청이 다른 점

데모를 요청하는 사람은 이메일 스레드가 아니라 캘린더의 시간을 원합니다. "화요일 괜찮으세요?"가 오갈 때마다 경쟁사와 예약할 기회가 생깁니다. 그래서 폼의 일은 짧습니다. 자격 확인에 충분한 만큼만 받고, 탭이 열려 있는 동안 캘린더를 보여 주는 것입니다.

구현에 영향을 주는 제약은 세 가지입니다.

  • 스케줄러가 열리기 전에 리드가 저장되어야 합니다. 많은 방문자가 예약 페이지를 열고 닫아 버립니다. 그들의 기록이 스케줄러에만 있다면 그 리드는 사라집니다. 먼저 Ikiform으로 POST하고 성공했을 때만 리디렉션하세요.
  • _redirect는 입력한 내용을 담을 수 없습니다. 고정 URL이고, Ikiform은 Allowed domains 중 하나에 있는 https: URL일 때만 따라갑니다. 거기에 cal.com이나 calendly.com을 추가하면 그 사이트에서 오는 POST도 통과하게 됩니다. 대신 내 코드에서 예약 링크를 만드세요.
  • 모든 요청이 실시간 통화를 받을 만한 것은 아닙니다. 팀용 제품의 데모를 요청한 1인 창업자에게는 투어와 가입 링크가 더 낫습니다. 선택형 질문 하나로 브라우저가 다음에 어디로 갈지 정합니다.
데모 요청이 저장된 뒤 어디로 가는지데모 폼이름, 이메일, 회사,팀 규모Ikiform저장, 팀에 이메일팀 규모?예약 페이지이름과 이메일 미리채움녹화된 투어가입 링크 포함전송ok11명 이상1~10명데모 요청이 저장된 뒤 어디로 가는지데모 폼이름, 이메일, 회사, 팀 규모Ikiform저장, 팀에 이메일팀 규모?예약 페이지이름과 이메일 미리 채움녹화된 투어가입 링크 포함전송ok11명 이상1~10명
  1. 방문자가 이름, 업무용 이메일, 회사, 팀 규모를 입력하면 폼이 Ikiform으로 POST합니다.
  2. Ikiform이 요청을 저장하고 팀에 이메일을 보냅니다. ok로 응답하기 전까지는 아무 일도 일어나지 않습니다.
  3. 내 코드가 방문자가 고른 팀 규모를 읽습니다.
  4. 11명 이상인 팀은 쿼리 문자열에 이름과 이메일을 담아 예약 페이지로 갑니다.
  5. 1~10명인 팀은 가입 링크가 있는 녹화된 투어로 갑니다.
분기는 Ikiform이 리드를 받은 뒤 내 코드에서 실행됩니다. 어느 쪽이든 팀은 모든 요청을 받으므로, 통화가 필요했던 소규모 팀도 놓치지 않습니다.

필드 네 개, 그중 하나는 라우팅용

필드유형이유
name텍스트예약 폼을 미리 채우므로 방문자는 한 번만 입력합니다
email이메일예약 폼을 미리 채우고 알림 이메일의 reply-to가 됩니다
company텍스트, 여기서는 필수통화 전에 담당자가 조회합니다
team_sizeselect예약 페이지와 투어 중 어디로 갈지 정하며, 정해진 네 값 중 하나로 도착합니다

사용 사례, 일정, 전화번호는 통화에서 물으세요. 미팅 전에 맥락이 필요하면 스케줄러가 자체 질문을 하나 할 수 있고, Calendly와 Cal.com 모두 커스텀 질문도 미리 채울 수 있습니다.

POST한 뒤 넘겨주기

각 버전은 요청을 POST하고 Ikiform의 응답을 기다린 뒤에야 다음 URL을 만듭니다. 예시는 Cal.com을 씁니다. Calendly라면 이벤트 링크로 바꾸세요. Calendly는 name과 email을 미리 채우기 파라미터로 문서화하고 있고, Cal.com은 name과 email을 포함해 모든 예약 필드를 식별자로 미리 채웁니다.

폼과 스크립트를 함께 씁니다. JavaScript가 없어도 폼은 POST하고 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>
서버 측 버전은 시크릿 키로 POST하므로 Ikiform이 Allowed domains와 사람 확인을 건너뜁니다. 그러면 모든 POST가 서버의 IP에서 오고, 방문자당 분당 5회인 Standard 리밋이 모든 방문자를 함께 셉니다. 서버를 거쳐 POST하는 폼에는 Relaxed나 Custom 레이트 리밋을 고르고, IKIFORM_SECRET_KEY는 서버 전용 환경 변수에 두세요. 서버 버전은 방문자의 Origin 헤더를 전달합니다. 서버 측 fetch는 이 헤더를 보내지 않는데, Ikiform은 이 헤더로 무료 localhost 테스트를 판별하기 때문입니다.

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~200명으로 제출하세요. 이름과 이메일이 채워진 예약 페이지가 열립니다.
  3. 시간을 고르지 않고 예약 페이지를 닫으세요. 요청은 여전히 Submissions에 있고, 알림 이메일도 받은편지함에 있습니다.
  4. 1~10명으로 다시 제출하고 투어로 이동하는지 확인하세요.
  5. 잘못된 이메일로 제출하세요. 폼에 오류가 표시되고 예약 페이지는 열리지 않습니다.
  6. 테스트 미팅을 예약하고, 스케줄러의 확인 메일이 입력한 주소로 오는지 확인하세요.

주의할 점

  • 예약된 데모마다 레코드가 두 개입니다. Ikiform에는 요청이, 스케줄러에는 미팅이 있습니다. CRM에서 이름이 아니라 이메일로 맞추세요.
  • Ikiform의 확인 이메일은 없습니다. Ikiform은 폼을 작성한 사람에게 이메일을 보내지 않습니다. 예약된 통화는 스케줄러의 확인 메일과 캘린더 초대로 충분합니다. 예약하지 않은 요청에는 그날 알림 이메일에서 답장하세요.
  • 쿼리 문자열은 보입니다. 예약 URL의 이름과 이메일은 브라우저 기록과 스케줄러의 분석에 나타납니다. 그 밖의 것은 넘기지 마세요.
  • 임베드. 대신 내 /book 페이지에 스케줄러를 임베드한다면, Cal.com은 forwardQueryParams를 켰을 때만 페이지의 쿼리 파라미터를 전달합니다. Calendly는 JavaScript 임베드의 prefill 객체로 미리 채우기를 지원하므로 일반 iframe 대신 그것을 쓰세요.
  • 스팸 검사. Spam check가 Ikiform으로 설정되어 있으면 브라우저 버전은 POST 전에 @ikiform/sdk의 challenge()를 호출해야 하며, 그러지 않으면 403 challenge_required를 받습니다. 서버 버전은 이 검사를 건너뜁니다.

질문

막히는 단계가 있거나 내 상황에 맞는 가이드가 필요하다면 이메일을 보내세요: hello@ikiform.com.