🎨

HubDB × サーバレス関数でHubSpotフォームの送信上限を実現する方法【コード付き】💻


目次

はじめに 🌿

HubSpotのフォームに「送信上限」をつけられない。このもやもやを解決するために、HubDBサーバレス関数を使って実装してみました💻

ChatGPT Image 2025年4月29日 22_53_21 (1)

この記事では、その構成や実装手順をコード付きで解説しています✨ まずはざっくり流れを知りたい人は、前編の記事もあわせて読んでね!


デモ動画 🎥

この仕組みでは、こんな動きをしてるよ!

  • サーバレス関数経由でHubDBの数値をカウントアップ

  • 上限数に達したらフォーム非表示(メッセージ表示)

  • 申込み期限(UTC基準)を過ぎたら自動でフォーム非表示!


前提について少し整理 ☕️

シナリオ 🍵

  • HubSpotフォームを使って申し込んでもらう

  • 予約者数に制限をかけたい

  • 定数超えたらフォームを自動非表示に

  • ついでに、フォーム送信ができる期限のタイミングもつけたい

構成イメージ 🌎

  1. HubDBでフォームごとに情報を管理

  2. CMSテンプレート内で利用

  3. フォーム送信時にカウントアップ

  4. サーバレス関数側でHubDB APIを使って更新

ChatGPT Image 2025年4月29日 22_54_38 (1)

使った技術 ・ ファイル ・ ツール ⚡️


 

実装コードの概要 🔧

HubDB のテーブル

カラム名 用途 データ型
form_guid 対象のフォームID(送信元の特定に使用) 文字列(text)
current_submissions 現在の送信数 数値(number)
max_submissions 送信可能な最大数 数値(number)
deadline 申込み締切日時(UTC) 日時(datetime)

 

📝
このテーブルは フォームごとの送信状態を管理するためのもので、テンプレート側のif文で送信数の上限や締切日をもとにフォームの表示/非表示を切り替えます

 

テンプレート内のHubL

Page template
{# 今この瞬間のローカル時間を取得してUNIXタイムに変換してるよ #}
{% set today = unixtimestamp(local_dt) %} 
{# HubDBのテーブルIDを指定してデータを取得! #}
{% set table = hubdb_table_rows("HUBDB_ID_HERE") %} 
{% for row in table %}
  {% if row.form_guid  "FORM_GUID_HERE" %}
    {% set current_submissions = row.current_submissions %}
    {% set submission_limit = row.max_submissions %}
    {% set deadline_timestamp = row.deadline %}

    {% if current_submissions < submission_limit and today < deadline_timestamp %}
      {# 送信数も期限もOKならフォームを表示するよ! #}
      <div id="my-form-wrapper">
        <div id="my-form-target"></div>
        <script src="https://js.hsforms.net/forms/v2.js"></script>
        <script>
          hbspt.forms.create({
            region: "na1",
            portalId: "YOUR_PORTAL_ID",
            formId: "FORM_GUID_HERE",
            target: '#my-form-target',
            onFormSubmit: function($form) {
              // 送信時にカウントアップするためにサーバレス関数を叩く!
              fetch('/_hcms/api/update-form-submissions', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ form_guid: 'FORM_GUID_HERE' })
              });
            }
          });
        </script>
      </div>
    {% else %}
      {# 上限達成または締切すぎたら、締め切りメッセージを出す! #}
      <div class="form-closed-message">
        <p>このフォームは締め切りました🙇‍♀️</p>
      </div>
    {% endif %}
  {% endif %}
{% endfor %}
📝
if current_submissions < submission_limit and today < deadline_timestampで、送信数も期限にも制限に達していない場合のみフォームが表示されるようになっているよ

 

サーバレス関数

form-limit-updater.js
const HUBSPOT_PRIVATE_APP_TOKEN = process.env.FORM_LIMIT_MANAGER; // 環境変数にトークンをセット!

exports.main = async (context = {}, sendResponse) => {
  try {
    const body = context.body || {};
    const formGuid = body.form_guid;
    const tableId = 'YOUR_TABLE_ID'; //HubDBのテーブルIDを指定

    if (!formGuid) {
      return sendResponse({ statusCode: 400, body: { message: 'form_guid がリクエストに含まれていません' } });
    }

    // HubDBの行データを取得して、該当するform_guidを探す
    const recordsResponse = await fetch(`https://api.hubapi.com/cms/v3/hubdb/tables/${tableId}/rows`, { ... });
    const records = await recordsResponse.json();
    const targetRecord = records.results.find(record => record.values.form_guid = formGuid);

    if (!targetRecord) {
      return sendResponse({ statusCode: 404, body: { message: '該当レコードが見つかりませんでした' } });
    }

    // 現在の送信数を+1する準備!
    const rowResponse = await fetch(`https://api.hubapi.com/cms/v3/hubdb/tables/${tableId}/rows/${targetRecord.id}`, { ... });
    const rowData = await rowResponse.json();
    const updatedValues = {
      ...rowData.values,
      current_submissions: (targetRecord.values.current_submissions || 0) + 1
    };

    // draftに更新して...
    await fetch(`https://api.hubapi.com/cms/v3/hubdb/tables/${tableId}/rows/${targetRecord.id}/draft`, { ... });

    // そしてpublishして確定!
    await fetch(`https://api.hubapi.com/cms/v3/hubdb/tables/${tableId}/draft/publish`, { ... });

    return sendResponse({ statusCode: 200, body: { message: '送信数を更新して公開しました', newCount: updatedValues.current_submissions } });
  } catch (error) {
    return sendResponse({ statusCode: 500, body: { message: 'エラーが発生しました', error: error.message } });
  }
};

 

serverless.json
{"runtime":"nodejs18.x","version":"1.0","secrets":["FORM_LIMIT_MANAGER"],"endpoints":{"update-form-submissions":{"method":"POST","file":"form-limit-updater.js"}}}
📝
このサーバレス関数はフォーム送信がされたイベントをトリガーとしてリクエストが実行されて、HubDBの "current_submissions" 列の値を +1 します

注意ポイント ⚡

  • deadlineやmax_submissionsを手動で管理する必要あり

  • 今のテンプレートはテンプレート内で form guid を指定しているから、複数フォームが出てきたときの処理に工夫が必要かも

  • HubDBのドラフト更新・公開の流れをミスらないように注意!

 

まとめ ✨

HubSpotの標準機能だけでは難しかった「送信上限&期限制御」も、 ちょっとカスタムすればここまでできる!

仕組みをしっかり作り込めば、イベントやワークショップ管理がとっても楽になるよ🌸

無理せず楽しくHubSpotを育てていこうね〜!

ChatGPT Image 2025年4月29日 23_04_04

 


あわせて読みたい 📖

サーバレス関数の作り方について詳しく学ぶなら、以下シリーズがおすすめ!💡:

 

Reina

Written by Reina

HubSpot CMS (現 Content Hub) をメインに 気になったことをまとめます #vibe coding

💬 コメントしてみる?