Gatsbyのお問合せ保存先としてHubspot Formsにデータを送信してみる

2022.06.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どうも、ベルリンオフィスの小西です。

過去の記事でも紹介したように、Gatsbyでは簡単に動的な問い合わせフォームを作ることができます。

その際、問い合わせ内容をメールで管理者や問い合わせした本人に自動転送するのは簡単なのですが、問い合わせ内容をどこかに保存しようとすると地味に面倒くさいなと思いました。

まず思いつくのがGoogle スプレッドシートに問い合わせ内容を保存することですが、GoogleのSheets APIは都度アクセストークンを取得する必要があり、そのための認証情報のjsonをGatsbyのような静的サイトだとどこに保存するかが悩ましいです。

そこでHubspotのForms機能のAPIでデータを差し込めないかと考えました。

やってみたとろ、その実装の手軽さもそうなのですが、無料版の範囲でも問い合わせ管理が非常にしやすくなるという点でけっこう良さそう、と思ったのでその方法を共有します。

やること

フォームのフロントはGatsbyで作成し、submitをトリガーにHubspotにPOSTリクエストを送信します。

Hubspotでフォームは生成しますが、それ自体は利用せず、あくまでAPIでのデータPOST先として利用します(もちろんそのままフォームを埋め込んで使うこともできますが、デザイン的な自由度は非常に低いです)。

Hubspot側の準備

Hubspotに登録を済ませて [新規フォーム] を作成します。

hubspot screenshot

[埋め込みフォーム]を選択。

hubspot screenshot

さくっと作りたいので、[登録] テンプレートを選択して [開始] します。

hubspot screenshot

Eメール、氏名、電話番号だけの簡素なフォームができましたので、右上 [埋め込み] をクリックします。

hubspot screenshot

[埋め込みコード] タブから [portalId][formId] をコピーしておきます。

hubspot screenshot

これでHubspot側の準備ができましたので、テストデータをPOSTしてみたいと思います。

ちなみにAPIのエンドポイントは下記のフォーマットです。

https://api.hsforms.com/submissions/v3/integration/submit/:portalId/:formGuid

試しに、ローカルのターミナルからPOSTリクエストを送信します。

curl -X POST https://api.hsforms.com/submissions/v3/integration/submit/XXXX/XXXX \
-H "Content-Type: application/json" \
-d '{"fields":[{"objectTypeId":"0-1","name":"email","value":"example@example.com"},{"objectTypeId":"0-1","name":"firstname","value":"Taro"},{"objectTypeId":"0-1","name":"lastname","value":"Tanaka"},{"objectTypeId":"0-1","name":"phone","value":"012345678"}]}'

成功すると返り値はこんな感じです。

{"inlineMessage":"フォームをご送信いただき、ありがとうございます。"}%

Gatsby側の構築

次にGatsby側を準備します。

以前Gatsby Functionsでフォームを作った記事を参考に、途中まで一緒です。

https://dev.classmethod.jp/articles/gatsby-functions-contact/

今回はさくっとフロント側でやってしまうので、 /src/pages/form.js を修正します。

import React, { useState } from 'react';
import Layout from "../components/layout"

export default function FormPage() {
  const [value, setValue] = React.useState({})
  const [serverResponse, setServerResponse] = React.useState()

  function handleChange(e) {
    setValue({
      ...value,
      [e.target.name]: e.target.value
    })
  }

  const portalId = "XXXX"
  const formGuid = "XXXX"
  const payload = {
    "fields":[
      {"objectTypeId": "0-1", "name": "email", "value": value.email ? value.email : ""},
      {"objectTypeId": "0-1", "name": "firstname", "value": value.firstname ? value.firstname : ""},
      {"objectTypeId": "0-1", "name": "lastname", "value": value.lastname ? value.lastname : ""},
      {"objectTypeId": "0-1", "name": "phone", "value": value.email ? value.email : ""}
  ]}

  async function onSubmit(e) {
    e.preventDefault()
    const response = await window
      .fetch('https://api.hsforms.com/submissions/v3/integration/submit/' + portalId + '/' + formGuid, {
        method: 'POST',
        headers: {
          "content-type": "application/json",
        },
        body: JSON.stringify(payload),
      })
      .then(res => res.json())
    setServerResponse(response)
  }

  return (
  <Layout>
    <h1>Let us know about you</h1>
    <form onSubmit={onSubmit} className="formWrapper">
      <div className="formBlock">
        <label>
          <span>Email</span>
          <input
            type="email"
            name="email"
            id="email"
            value={value['email'] || ``}
            onChange={handleChange}
            required />
        </label>
      </div>
      <div className="formBlock">
        <label>
          <span>First Name</span>
          <input
            type="text"
            name="firstname"
            id="firstname"
            value={value['firstname'] || ``}
            onChange={handleChange}
            required />
        </label>
      </div>
      <div className="formBlock">
        <label>
          <span>Last Name</span>
          <input
            type="text"
            name="lastname"
            id="lastname"
            value={value['lastname'] || ``}
            onChange={handleChange}
            required />
        </label>
      </div>
      <div className="formBlock">
        <label>
          <span>Phone</span>
          <input
            type="tel"
            name="phone"
            id="phone"
            value={value['phone'] || ``}
            onChange={handleChange} />
        </label>
      </div>
      <div className="formBlock">
        <input type="submit" />
      </div>
    </form>
    <div style={{border:"solid 6px #eee", padding: "20px"}}>
      <h2 style={{fontSize:"0.95rem"}}>サーバーレスポンス</h2>
      <p style={{fontSize:"0.8rem", background:"#eee", padding: "20px"}}>{JSON.stringify(serverResponse)}</p>
      <h2 style={{fontSize:"0.95rem"}}>Payload</h2>
      <p style={{fontSize:"0.8rem", background:"#eee", padding: "20px"}}>{payload && JSON.stringify(payload)}</p>
    </div>
  </Layout>
)}

フォーム送信処理は上記だけで完結します。

下記のようなページができます(実際は少しスタイルをcssファイルで当てているので異なるはずですが)。

gatsby screenshot

実際にデータ送信してみる

上記のページで実際にSubmitしてみます。

Hubspotからメッセージが返ってきました。

gatsby screenshot

Hubspotダッシュボードのほうも見てみます。

無事データが届いていました。

hubspot screenshot

以上、簡単にGatsbyからHubspotにデータを送信できました。

さらにAPI経由でデータが登録された場合でも、管理者向けにHubspotから通知が行くので一石二鳥ですね。

問い合わせデータの分析やデータ取り扱いの利便性を上げるために、APIのオプションも利用することができます。

https://legacydocs.hubspot.com/docs/methods/forms/submit_form

エンドポイントの制限

Hubspot FormsのAPIは手軽に利用できる一方、当たり前ですがいくつか制限や注意事項が存在します。

  • エンドポイントへのリクエストは 10秒ごと50回まで に制限されています。
  • このエンドポイントは、サーバーサイドのHTTPリクエストを受け付けるだけでなく、Cross-Origin AJAX(CORS)リクエストも受け付けるので、JavaScriptを使用してクライアントサイドからHubSpotに直接フォームデータを送信することができます。
  • フォームのフィールドは、HubSpotアカウントの既存の contact properties に対応している必要があります。
  • reCAPTCHAをサポートしていません。reCAPTCHAが有効化されているフォームの場合、データ送信は成功しません
  • (submitAt値を送信する場合)フォームの最初のページビューがsubmitAtタイムスタンプ値より後の場合、コンタクトのオリジナルの値が影響を受ける可能性があります。

以上、Gatsbyのお問合せフォームからのデータ保存先として、Hubspot Forms APIを利用してみました。

無料版でもかなりの範囲を利用できるので、フォームのフロントは自由にいじりたいけどデータ管理は専用のSaaSに任せたい、という場合にぜひ利用してみてください。

参考

https://legacydocs.hubspot.com/docs/methods/forms/submit_form