humbulls post

HubSpot Stage History を Apps Script 30 行で日次 Snapshot — 上位プラン移行を 3 ヶ月先送り|HubSpot Starter × Claude Code 限界突破 #4|humbulls

作成者: Kazuki Kurita|May 15, 2026 3:00:00 PM

HubSpot Professional の代名詞的機能のひとつ「Stage History (商談ステージ推移)」。Starter プランでは API レベルで取得できず、ここを理由に Professional 移行を迫られる組織は少なくありません。私たち humbulls はある業務用美容機器メーカーの実装で、Apps Script のたった 30 行で「日次粒度の Stage Snapshot」を蓄積し、Professional 相当の Cohort 分析まで接続しました。Pillar 記事「HubSpot Starter で Professional 級ダッシュボード」のシリーズ #4 として、Professional 専用機能の代替実装を公開します。

1. なぜ Stage History が Starter で取れないのか — Professional と Starter の境界線

Stage History の取得 API は Professional 以上で開放されています。Starter で /crm/v3/objects/deals/{dealId}/property-history を叩くと 403 で弾かれます。

HubSpot の Stage History (Deal Pipeline の各ステージに何分滞留したかの履歴) は、公式ドキュメントの記述上では「Sales Hub Professional 以上の機能」として位置付けられています。Starter プランで /crm/v3/objects/deals/{dealId}/property-history を叩くと、ステージ推移に関わるプロパティは 403 Forbidden で返ってきます。※ 本記事の円換算はすべて 1 ドル = 150 円 (2026 年 5 月時点) を基準に計算しています。

実務での選択肢は 2 つです。Professional にアップグレードして公式機能を使う ($890/月 = 年 $10,680 ≒ 約 160 万円)、または「過去履歴の遡及は諦めて、今日から日次 Snapshot を蓄積する」設計に切り替える。前者は確実ですが月額が重く、後者は遡及できないという制約があります。

私たち humbulls は後者を選びました。理由は「過去の Stage 推移が見たいのは経営判断のため」であり、判断は将来に向けて行うものだからです。今日からの 1 ヶ月、3 ヶ月、6 ヶ月の推移が見られれば、ほとんどの意思決定には間に合います。Apps Script で毎朝 1 回 全 Deal の現在ステージを Sheet に追記するだけで、Professional と同等の「ステージ推移」が日次粒度で蓄積されます。

注意点がひとつ。「分単位」「ステージ移動のリアルタイム通知」が必要な業務 (例: インサイドセールスの SLA 監視) は Snapshot で代替できません。この場合は Professional が必要です。日次でモニタリングできれば十分なら、Snapshot で 100% カバーできます。

🤖 AI で実行する — 使ったプロンプト / ワークフロー

目的: Stage History の Professional / Snapshot 代替のどちらが自社に必要かを判断 所要時間: 20 分 ツール: Claude (Opus 4.7)

プロンプト:

あなたは BtoB SaaS のシステム要件アドバイザーです。HubSpot の Stage History 機能を「Professional 直接利用」「Apps Script Snapshot 代替」のどちらで賄うべきか判定してください。

【判定材料】
- 必要な粒度 (分単位 / 時間単位 / 日次)
- 必要な遡及範囲 (過去 6 ヶ月 / 過去 1 年 / 過去 3 年)
- 使うシーン (SLA 監視 / 経営レビュー / 営業会議 / クライアント報告)
- 月次商談数: [規模感を記述]

【出力】
- 推奨構成 (Professional / Snapshot) + 判断根拠 3 行
- Snapshot 代替を選ぶ場合の「諦める領域」リスト

運用 Tips: - 「日次粒度で十分」と言いつつ最終的に分単位が欲しくなるケースが多いので、3 ヶ月運用してみてから再判断する - 経営レビューや週次会議が主用途なら Snapshot で間違いなく十分

📚 参考文献

2. 30 行で解決 — append-only 設計の Snapshot 関数

シンプルなのが正解。_StageSnapshots シートに 1 行ずつ追記するだけの実装で、後から削除・更新を考えなくていい構造にします。

蓄積型データを扱う際の鉄則は 「append-only」 です。一度書いた行は削除も更新もせず、新しいデータは常に末尾に追加するだけ。これを破ると「過去データが壊れている」事故が発生しやすくなります。Apps Script の appendRow() または getRange().setValues() で末尾追記を行うのが定石です。

従来このような蓄積型実装は、データベース設計の経験がないと「上書きすべきか / 追記すべきか」の判断で迷い、最初の設計に半日溶けることが珍しくありません。Apps Script に詳しいエンジニアでも、Sheet を DB として使う発想に慣れていないと「DELETE → INSERT」のような壊れやすい設計に流れがちです。

私たち humbulls の運用では、Claude Code に「HubSpot から全 Deal の現在ステージを Sheet に append する 30 行の Apps Script を書いて」と指示し、出てきたコードをそのまま採用しました:

function recordStageSnapshot() {
  const ss = SpreadsheetApp.openById('YOUR_SHEET_ID');
  const sheet = ss.getSheetByName('_StageSnapshots');
  const today = Utilities.formatDate(new Date(), 'JST', 'yyyy-MM-dd');

  const deals = fetchAllDeals(['dealname', 'amount', 'dealstage', 'hubspot_owner_id', 'createdate']);
  const stagesMaster = fetchStagesMaster();

  const rows = deals.map(d => [
    today,
    d.id,
    d.properties.dealname,
    Number(d.properties.amount) || 0,
    d.properties.dealstage,
    stagesMaster[d.properties.dealstage]?.label || 'unknown',
    d.properties.hubspot_owner_id,
    d.properties.createdate
  ]);

  if (rows.length > 0) {
    sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, 8).setValues(rows);
  }
  Logger.log(`Appended ${rows.length} rows on ${today}`);
}

ポイントは 3 つです。today を行ごとに付与するので、後から WHERE snapshot_date = '2026-05-15' のように日付絞り込みが効きます。stagesMaster を別途読み込んで stage_jp 列を生成しておくと、Looker Studio 側で VLOOKUP が不要になります。appendRow ではなく setValues を使うのは、1 日分まとめて書き込む方が高速だからです (Companies + Contacts + Deals 合計 1,300 件で 1 秒以内)。

注意点がひとつ。_StageSnapshots シートが肥大化していくので、半年〜 1 年経過したら別シートに退避する仕組みも入れておくと安心です。1,300 件 × 365 日 = 約 47 万行は Sheets の上限 (1,000 万セル) に余裕で収まりますが、Looker Studio の描画は重くなります。

🤖 AI で実行する — 使ったプロンプト / ワークフロー

目的: Stage Snapshot を append-only で蓄積する Apps Script を生成 所要時間: 15 分 ツール: Claude Code

プロンプト:

HubSpot の全 Deal の現在ステージを毎朝 Google Sheets に append する Apps Script を書いてください。

【要件】
- シート名: `_StageSnapshots`
- カラム: snapshot_date / deal_id / dealname / amount / stage_id / stage_jp / owner_id / create_date
- HubSpot の dealstage プロパティ ID を `pipelines_master` シートで stage_jp に変換
- append-only (= 既存行は変更しない、末尾に追加のみ)
- 1 日分まとめて setValues で書き込み

【出力】 recordStageSnapshot() 関数 + 必要なヘルパー関数 (fetchAllDeals / fetchStagesMaster)

運用 Tips: - Trigger 登録時は「毎日 6:00-7:00」がデータ整合性的に安全 (夜間バッチ完了後) - 失敗時に _StageSnapshots が中途半端な状態にならないよう、書き込み前に rows.length をログに出す

📚 参考文献

3. Cohort 分析へ接続する _DealCurrentState の役割

Snapshot だけだと「過去推移」しか取れません。_DealCurrentState (毎日上書き) との 2 シート構造にして、はじめて Cohort × 経過日数 × 勝率の分析が成立します。

_StageSnapshots (毎日追記) だけでは、Looker Studio で「直近の Deal 一覧」を表示する際にもデータ全件を走査する必要があり、描画が重くなります。同じデータを「現在の状態だけ」見たいユースケースのために、別シート _DealCurrentState (毎日上書き) を持たせる二段構成にします。

従来の設計だと「1 シートで両方賄う」発想で、_StageSnapshots から MAX(snapshot_date) の行だけフィルタする、という方式が取られがちです。動くには動きますが、Looker Studio のフィルタが重く、Pivot 等で複雑な絞り込みをする際にパフォーマンスが落ちます。

私たち humbulls の運用は 「上書き先と追記先を物理的に分離する」 設計です:

シート名 書き込み方式 役割 利用先
_StageSnapshots append-only (日次追記) 過去推移 / Cohort / 経過日数分析 Pivot table (#5 Cohort 記事)
_DealCurrentState overwrite (日次上書き) 現在の Deal 一覧 / Pipeline ファネル Funnel chart / Table

Apps Script 側では recordStageSnapshot()recordDealCurrentState() の 2 関数を、共通の Deal 取得関数 (fetchAllDeals) からデータを共有しつつ、それぞれ別シートに書き込む形にします:

function syncDealsOrchestrator() {
  const deals = fetchAllDeals(['dealname', 'amount', 'dealstage', 'hubspot_owner_id', 'createdate']);
  const stagesMaster = fetchStagesMaster();

  recordStageSnapshot(deals, stagesMaster);  // 追記
  recordDealCurrentState(deals, stagesMaster); // 上書き
}

これで Looker Studio 側のデータソースは 2 つに分かれ、用途別に高速にレンダリングできます。Cohort 分析 (#5) や Pipeline ファネル (#3) で具体的にどう使い分けるかは、それぞれの記事を参照してください。

なお _DealCurrentState を「上書き」と言っても、Sheets 側で sheet.clearContents() してから setValues() を呼ぶ実装です。Range.clear() だと書式設定まで消えてしまうので、clearContents() を使うのが安全です。

注意点がひとつ。_DealCurrentState には過去履歴がないので、ここから Cohort 分析を組もうとすると失敗します。Cohort は必ず _StageSnapshots 側を参照させてください。

🤖 AI で実行する — 使ったプロンプト / ワークフロー

目的: 2 シート構成のオーケストレーター関数を生成 所要時間: 20 分 ツール: Claude Code

プロンプト:

Apps Script で HubSpot の Deal データを 2 シートに振り分ける Orchestrator 関数を書いてください。

【要件】
- 1 度の API 呼び出し結果を、2 つの書き込み関数で共有する
- `_StageSnapshots`: append-only (日次追記)
- `_DealCurrentState`: overwrite (clearContents → setValues)
- どちらも同じ Deal 一覧 / stages master を使う

【出力】
- syncDealsOrchestrator() / recordStageSnapshot() / recordDealCurrentState() の 3 関数
- 各関数の単体テスト方法 (= 試し書き用のダミーシート設定)

運用 Tips: - 2 関数のうち 1 つが失敗しても、もう 1 つは独立して動くよう try-catch で分離 - _DealCurrentState の書き込み失敗は Snapshot で代替できるので、Slack 通知は Snapshot 失敗時のみで十分

📚 参考文献

4. 「明日始めれば 3 ヶ月後の自分が感謝する」蓄積型ノウハウ

蓄積型データは「過去を諦めて、未来を取りに行く」設計です。Professional 月額 $890 × 3 ヶ月 = 約 40 万円のアップグレード判断を、3 ヶ月先送りにできます。

蓄積型データの最大の特徴は 「始めた瞬間からしか価値が生まれない」 ことです。今日 Snapshot 蓄積を始めると、1 ヶ月後には 1 ヶ月分の推移、3 ヶ月後には 3 ヶ月分の推移、1 年後には 1 年分の推移が手に入ります。逆に「Professional にアップグレードしてから始めよう」と先送りすると、その判断を待っている期間中の履歴は永遠に取れません。

実務で見られる失敗パターンが「Professional 移行を半年検討して、結局移行しなかった」というケースです。半年間 Snapshot を蓄積していれば、今頃 6 ヶ月分の Cohort 分析ができたはずなのに、判断を待った時間が機会損失になります。

私たち humbulls は「とりあえず明日から Snapshot を蓄積し、3 ヶ月後の判断材料にする」という運用方針を採用しました。3 ヶ月の Snapshot データが手元にあると、Professional が本当に必要かを「自社のデータ」で判断できます:

経過 蓄積データ できる分析 Professional 移行判断
1 ヶ月後 約 30 日分 直近 30 日のステージ滞留 データ不足
3 ヶ月後 約 90 日分 月次 Cohort × 経過日数 × 勝率 判断材料が揃う
6 ヶ月後 約 180 日分 四半期トレンド + 季節性 Professional 無しでもほぼ代替可能
1 年後 約 365 日分 年次トレンド + 前年比 Professional 移行は不要のケース多数

Professional の月額は $890 (約 13.4 万円) なので、3 ヶ月先送りで $890 × 3 = $2,670 (約 40 万円) のコスト削減になります。Snapshot 実装コストは Apps Script 30 行 + Trigger 設定の 30 分程度です。

注意点がひとつ。「いずれ Professional に行くつもりだから Snapshot は要らない」と判断して、Professional 移行を 3 ヶ月先送りした結果「履歴が無い」と気付くのが典型的な失敗です。Professional 移行が確定していても、移行までの期間は Snapshot を回しておくと安全網になります。

🤖 AI で実行する — 使ったプロンプト / ワークフロー

目的: Snapshot 蓄積開始の意思決定を経営層 / 上長に提案する文書を生成 所要時間: 20 分 ツール: Claude (Opus 4.7)

プロンプト:

あなたは BtoB マーケティング戦略コンサルタントです。HubSpot Starter で「日次 Stage Snapshot を Apps Script で蓄積する」提案を、経営層向けに 1 ページの稟議文書に整理してください。

【含めるべき要素】
- なぜ Professional ではなく Snapshot で十分か (= 必要な粒度の整理)
- 3 ヶ月後 / 6 ヶ月後 / 1 年後にできる分析の例
- 実装コスト (人日) と 月額削減 (Professional 月額 $890 × 先送り月数)
- リスクと回避策 (= Professional 必要になった時の引き継ぎ)

【出力形式】 1 ページマークダウン (見出し / 表 / 箇条書きで構造化)

運用 Tips: - 経営層向けの稟議文書では「年間コスト削減額」を太字で 1 箇所だけ強調する - 数字根拠は「自社の Deal 数 × Professional 月額」で具体化、汎用論にしない

📚 参考文献

5. Professional へ移行するタイミング判断 — Snapshot から Professional へのスムーズな引き継ぎ

Snapshot は「Professional 移行の延期策」ではなく「Professional 移行までの保険」です。最終的に Professional へ移行する場合、Snapshot データは捨てる必要がありません。

蓄積した Snapshot データは、Professional 移行後も _StageSnapshots シートに残しておけば、Professional の Stage History 機能と並走できます。Professional の Stage History は「Professional 契約開始以降の履歴のみ」を取得するので、それ以前のデータは Snapshot 側でしか参照できません。むしろ Professional 契約前の履歴を残せるという観点で、Snapshot 実装は Professional 契約後も価値が続きます。

従来のように「Professional に上げたから Snapshot は廃止」と判断すると、Professional 契約前の貴重な履歴を失います。Professional の Stage History は契約日以前の遡及取得ができないので、これは取り返しがつかない損失です。

私たち humbulls の運用ルールは 「Professional 移行後も Snapshot は半年継続」 です。理由は以下です:

状態 Snapshot の役割
Starter のみ Stage History の唯一の代替
Professional 移行直後 (0-3 ヶ月) Professional の Stage History と並走、データ齟齬の検証用
Professional 移行後 (3-6 ヶ月) Professional 契約前の履歴データ参照用
Professional 移行 6 ヶ月以降 アーカイブ保存 (Sheet を別ファイルに退避)

Professional 移行のタイミング判断は、Snapshot で取れない領域 (分単位の粒度 / SLA 監視 / 公式 UI での履歴表示) が業務クリティカルになった時です。具体的には以下のいずれかが該当した場合に Professional を検討します:

  1. インサイドセールスの SLA 監視で「30 分以内に商談化」のような分単位ルールが必要になった
  2. 営業マネージャーが HubSpot UI 上で「この商談のステージ推移」を確認する習慣が根付き、Sheet を見るオペレーションが回らない
  3. Professional 専用の他機能 (Sequences / Forecasting / Custom Objects) も同時に必要になった

なお Professional 移行は 1 ヶ月単位の契約なので、繁忙期だけ Professional / 閑散期は Starter という運用も技術的には可能ですが、データ移行のオーバーヘッドが大きいので推奨しません。

注意点がひとつ。Professional へ移行後に「Snapshot をやめる」判断は慎重に。Professional 契約を解約して Starter に戻る可能性が少しでもあるなら、Snapshot は継続しておく方が安全です。

🤖 AI で実行する — 使ったプロンプト / ワークフロー

目的: Professional 移行 / Snapshot 継続の意思決定マトリクスを生成 所要時間: 25 分 ツール: Claude (Opus 4.7)

プロンプト:

あなたは BtoB SaaS の意思決定アドバイザーです。HubSpot Starter + Snapshot 運用から Professional 移行を判断するチェックリストを作ってください。

【判断材料】
- 分単位粒度の必要性 (Yes/No)
- HubSpot UI 上での履歴閲覧の必要性 (Yes/No)
- Professional 専用の他機能 (Sequences / Forecasting 等) の必要性 (Yes/No)
- 月次商談数 (規模感)
- 営業組織の規模 (人数)

【出力】
- 判断マトリクス (5 軸 × 移行 / 継続のスコアリング)
- 移行を決めた場合の Snapshot データ引き継ぎ手順
- 移行後も Snapshot を継続すべき期間 (3 ヶ月 / 6 ヶ月 / 永続)

運用 Tips: - 3 軸中 2 軸以上で Yes なら Professional 検討、1 軸以下なら Starter + Snapshot 継続 - 引き継ぎ手順書はチームの誰かが必ずアクセスできる場所 (Notion / Google Drive) に置く

📚 参考文献

サブ記事ナビゲーション

Pillar 記事「HubSpot Starter で Professional 級ダッシュボード」を起点に、シリーズ全 6 本でデータ層から可視化層までを解説しています。

# タイトル 役割
#1 (Pillar) HubSpot Starter を Claude Code で限界突破!上位プランでしかできなかったレポートダッシュボードを再現 全体設計
#2 Apps Script で HubSpot ↔ Google Sheets を月額 $0 で自動同期 データ層
#3 Looker Studio で HubSpot ダッシュボードを 30 分で組む 可視化層
#4 (本記事) Stage History を Apps Script 30 行で日次 Snapshot Professional 専用機能の代替
#5 月次コホート × 経過日数 × 勝率 — AI で 1 時間設計 分析フレームワーク
#6 Kintone と HubSpot の並行運用 — 増分同期で破綻させない 既存 CRM 統合

humbulls の Growth Partner サービス では、Professional 移行判断から Snapshot 実装まで伴走しています。

実装テンプレと判断マトリクスを一括でダウンロードしたい方は、BtoB マーケ AI 活用ガイド もご活用ください。