ブログ目次
HubSpotカスタムコードアクション活用法|Node.js/Pythonで実装する高度なワークフロー自動化
「HubSpotの標準ワークフローアクションでは、やりたいことが実現できない」「外部APIとの連携を自動化したいが、Zapierを挟むと遅延やコストが気になる」——HubSpotのワークフローを本格的に活用すると、標準機能だけでは対応しきれないケースに必ず遭遇します。
HubSpotのカスタムコードアクションは、ワークフロー内でNode.jsまたはPythonのコードを直接実行できる機能です。Data Hub Professional以上(旧Operations Hub Professional以上)のプランで利用可能で、外部APIの呼び出し、複雑なデータ変換、条件分岐ロジックなど、標準アクションでは不可能な処理をワークフローに組み込めます。
本記事では、カスタムコードアクションの基本設定から、Node.js・Pythonでの具体的な実装パターン、エラーハンドリング、実務での活用ユースケースまでを体系的に解説します。
この記事でわかること
- カスタムコードアクションの利用要件と基本的な設定手順
- Node.jsでの実装パターン(外部API呼び出し、データ変換、CRM操作)
- Pythonでの実装パターン(計算ロジック、通知送信、データ処理)
- エラーハンドリングとデバッグのベストプラクティス
- 実務で使える5つのユースケースと設計の考え方
カスタムコードアクションの概要
利用要件

カスタムコードアクションを利用するには、以下の条件を満たす必要があります。
| 項目 | 要件 |
|---|---|
| プラン | Data Hub Professional以上(旧Operations Hub Professional以上) |
| 対応言語 | Node.js 20(JavaScript)、Python 3.9 |
| 実行時間制限 | 最大20秒 |
| メモリ制限 | 128MB |
| シークレット | 最大5個(APIキー等の安全な保管) |
| 利用可能なnpmパッケージ | axios, @hubspot/api-client, lodash 等 |
| 出力データ | 最大5つの出力変数(後続アクションで使用可能) |
標準アクションとの使い分け
カスタムコードアクションは強力な機能ですが、標準アクションで実現できる処理には使う必要はありません。以下の表で使い分けを判断してください。
| 処理内容 | 標準アクション | カスタムコード |
|---|---|---|
| プロパティ値の更新 | 推奨 | 不要 |
| メール送信 | 推奨 | 不要 |
| 単純な条件分岐 | 推奨 | 不要 |
| 外部API呼び出し | 不可 | 必須 |
| 複雑なデータ変換・計算 | 不可 | 必須 |
| 複数レコードの一括処理 | 不可 | 必須 |
| カスタムバリデーション | 不可 | 必須 |
| 動的な条件分岐ロジック | 限定的 | 推奨 |
カスタムコードアクションの設定手順
ステップ1:ワークフローにアクションを追加
ワークフローエディタで「アクションを追加」→「カスタムコード」を選択します。言語(Node.jsまたはPython)を選び、コードエディタが表示されます。
ステップ2:入力プロパティの定義
コード内で使用するCRMプロパティを「プロパティを含める」セクションで定義します。たとえば、コンタクトのメールアドレスや会社名をコード内で参照する場合、ここで対象プロパティを選択します。
ステップ3:シークレットの設定
外部APIのAPIキーやトークンは、「シークレット」として安全に保管します。シークレットはコード内で環境変数として参照でき、ワークフローの設定画面にプレーンテキストで表示されることはありません。
ステップ4:コードの記述とテスト
コードエディタにロジックを記述し、「テスト」ボタンで動作を確認します。テスト実行時には実際のCRMレコードを選択して、リアルなデータで検証できます。
ステップ5:出力変数の定義
後続のワークフローアクションで使用するデータを「出力」として定義します。外部APIから取得したスコアやステータスを出力変数に格納し、次の条件分岐で使用する連携が可能です。
Node.jsでの実装パターン
パターン1:外部APIを呼び出してデータエンリッチメント
外部のデータエンリッチメントAPIを呼び出し、コンタクト情報を自動補完する例です。
`javascript
const axios = require('axios');
exports.main = async (event, callback) => {
const email = event.inputFields['email'];
const apiKey = process.env.ENRICHMENT_API_KEY;
try {
const response = await axios.get(
https://api.clearbit.com/v2/people/find,
{
params: { email: email },
headers: { Authorization: Bearer ${apiKey} }
}
);
const { company, title } = response.data;
callback({
outputFields: {
enriched_company: company?.name || '',
enriched_title: title || '',
enrichment_status: 'success'
}
});
} catch (error) {
callback({
outputFields: {
enriched_company: '',
enriched_title: '',
enrichment_status: 'failed'
}
});
}
};
`
パターン2:取引データに基づくカスタムスコアリング
取引金額、ステージ、経過日数を組み合わせた独自のスコアリングロジックです。
`javascript
exports.main = async (event, callback) => {
const dealAmount = parseFloat(event.inputFields['amount']) || 0;
const dealStage = event.inputFields['dealstage'];
const createDate = new Date(event.inputFields['createdate']);
const now = new Date();
const daysSinceCreation = Math.floor(
(now - createDate) / (1000 60 60 * 24)
);
let score = 0;
// 金額ベースのスコア
if (dealAmount >= 10000000) score += 40;
else if (dealAmount >= 5000000) score += 30;
else if (dealAmount >= 1000000) score += 20;
else score += 10;
// ステージベースのスコア
const stageScores = {
'appointmentscheduled': 10,
'qualifiedtobuy': 20,
'presentationscheduled': 30,
'decisionmakerboughtin': 40,
'contractsent': 50
};
score += stageScores[dealStage] || 0;
// 経過日数によるペナルティ
if (daysSinceCreation > 90) score -= 10;
if (daysSinceCreation > 180) score -= 20;
const priority = score >= 60 ? 'high'
: score >= 30 ? 'medium' : 'low';
callback({
outputFields: {
deal_score: score.toString(),
deal_priority: priority
}
});
};
`
パターン3:HubSpot APIで関連レコードを取得
コンタクトに関連する会社情報をAPIで取得し、プロパティを更新する例です。
`javascript
const hubspot = require('@hubspot/api-client');
exports.main = async (event, callback) => {
const hubspotClient = new hubspot.Client({
accessToken: process.env.HUBSPOT_TOKEN
});
const contactId = event.object.objectId;
try {
const associations = await hubspotClient.crm.contacts
.associationsApi.getAll(contactId, 'companies');
if (associations.results.length > 0) {
const companyId = associations.results[0].id;
const company = await hubspotClient.crm.companies
.basicApi.getById(companyId, [
'industry', 'numberofemployees', 'annualrevenue'
]);
callback({
outputFields: {
company_industry: company.properties.industry || '',
company_size: company.properties.numberofemployees || '',
company_revenue: company.properties.annualrevenue || ''
}
});
} else {
callback({
outputFields: {
company_industry: '',
company_size: '',
company_revenue: ''
}
});
}
} catch (error) {
callback({
outputFields: {
company_industry: 'error',
company_size: '',
company_revenue: ''
}
});
}
};
`
Pythonでの実装パターン
パターン1:LTV(顧客生涯価値)の自動計算
`python
def main(event):
monthly_revenue = float(
event.get('inputFields', {}).get('monthly_revenue', 0)
)
churn_rate = float(
event.get('inputFields', {}).get('churn_rate', 5)
) / 100
gross_margin = float(
event.get('inputFields', {}).get('gross_margin', 70)
) / 100
if churn_rate > 0:
avg_lifespan_months = 1 / churn_rate
ltv = monthly_revenue gross_margin avg_lifespan_months
else:
ltv = monthly_revenue gross_margin 120
if ltv >= 10000000:
segment = 'enterprise'
elif ltv >= 3000000:
segment = 'mid-market'
elif ltv >= 500000:
segment = 'smb'
else:
segment = 'starter'
return {
"outputFields": {
"calculated_ltv": str(int(ltv)),
"customer_segment": segment,
"avg_lifespan_months": str(int(avg_lifespan_months))
}
}
`
パターン2:取引ステージ変更時のSlack通知
`python
import os
import json
from urllib.request import Request, urlopen
from urllib.error import URLError
def main(event):
deal_name = event.get('inputFields', {}).get('dealname', '不明')
deal_amount = event.get('inputFields', {}).get('amount', '0')
deal_stage = event.get('inputFields', {}).get('dealstage', '不明')
slack_webhook = os.environ.get('SLACK_WEBHOOK_URL')
message = {
"text": "取引ステージ変更通知",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": (
f"取引名: {deal_name}\n"
f"金額: {deal_amount}\n"
f"新ステージ: {deal_stage}"
)
}
}
]
}
try:
req = Request(
slack_webhook,
data=json.dumps(message).encode('utf-8'),
headers={'Content-Type': 'application/json'}
)
urlopen(req)
status = 'sent'
except URLError as e:
status = f'failed: {str(e)}'
return {
"outputFields": {
"notification_status": status
}
}
`
エラーハンドリングのベストプラクティス
必ず対策すべきエラーパターン
| エラーパターン | 原因 | 対処法 |
|---|---|---|
| タイムアウト(20秒超過) | 外部APIの応答遅延 | タイムアウト設定、リトライ上限 |
| API認証エラー(401/403) | トークン期限切れ、権限不足 | シークレットの定期更新、エラー通知 |
| レート制限(429) | API呼び出し頻度超過 | リトライ待機、バッチ処理 |
| データ型エラー | null値、予期しない型 | デフォルト値設定、型チェック |
| メモリ超過 | 大量データの処理 | データの分割処理、不要変数の解放 |
エラーが発生した場合でも、callback(Node.js)またはreturn(Python)で必ず出力を返すように実装してください。エラー時の出力にステータス情報を含めることで、後続のワークフローアクションで条件分岐による制御が可能になります。
実務で使える5つのユースケース
ユースケース1:リードエンリッチメント
フォーム送信時に、メールアドレスから企業情報を自動取得してCRMに補完します。ClearbitやApolloなどのエンリッチメントAPIと連携し、会社名、従業員数、業種、売上規模などを自動入力します。
ユースケース2:カスタムリードスコアリング
HubSpotの標準スコアリングでは対応できない、独自の重み付けロジックを実装します。行動データ(ページ閲覧、メール開封)とデモグラフィックデータ(企業規模、業種)を組み合わせた多変量スコアリングが可能です。
ユースケース3:外部システムへのリアルタイムデータ同期
取引のステージ変更や新規コンタクト作成をトリガーに、基幹システムやERPにリアルタイムでデータを同期します。REST API呼び出しで、HubSpotを起点とした双方向のデータ連携を実現します。
ユースケース4:動的な通知・アラート制御
取引金額、顧客セグメント、チームの状況に応じて、通知の内容や送信先を動的に切り替えます。標準の通知アクションでは固定的な通知しかできませんが、カスタムコードなら条件に応じた柔軟な制御が可能です。
ユースケース5:データ品質の自動チェック
CRMに入力されたデータの品質を自動検証し、不正データを検出・修正します。電話番号のフォーマット統一、住所の正規化、重複検出アラートなどに活用できます。
制約事項と注意点
セキュリティの考慮
APIキーやトークンは必ず「シークレット」機能を使って保管してください。コード内にハードコードすると、ワークフローの編集権限を持つすべてのユーザーに露出します。また、外部APIへの通信はHTTPS(TLS 1.2以上)を使用することが必須です。
パフォーマンスの最適化
20秒の実行時間制限があるため、大量のデータ処理や複数の外部API呼び出しを1回のアクションで行うことは推奨されません。処理が重い場合は、複数のカスタムコードアクションに分割するか、非同期処理の設計を検討してください。
よくある質問(FAQ)
Q1. カスタムコードアクションで使用できるライブラリに制限はありますか?
Node.jsの場合、axios、@hubspot/api-client、lodashなど一部のnpmパッケージが利用可能です。任意のパッケージをインストールすることはできません。Pythonの場合も、標準ライブラリに加えて一部の外部ライブラリが利用可能です。最新の対応パッケージリストはHubSpotの公式ドキュメントで確認してください。
Q2. デバッグはどのように行いますか?
ワークフローエディタの「テスト」機能で、実際のCRMレコードを使ったテスト実行が可能です。console.log(Node.js)やprint(Python)の出力はテスト結果画面に表示されるため、変数の値やAPIレスポンスの確認に活用できます。ワークフローの実行履歴からも各アクションの入出力値を確認できます。
Q3. カスタムコードが失敗した場合、ワークフローは停止しますか?
デフォルトでは、カスタムコードアクションがエラーで失敗すると、それ以降のワークフローステップは実行されません。エラーハンドリングを適切に実装し、エラー時にもcallback/returnで出力を返すようにすれば、後続アクションを条件分岐で制御できます。
Q4. Node.jsとPython、どちらを選ぶべきですか?
外部API連携やHubSpot APIの操作にはNode.jsが適しています。@hubspot/api-clientパッケージが利用できるため、HubSpot APIとの連携がスムーズです。一方、数値計算やデータ分析のロジックにはPythonが適しています。チームの技術スタックに合わせて選択してください。
HubSpotのカスタムコードアクションは、標準ワークフローの制約を超えた高度な自動化を実現する強力な機能です。外部API連携、複雑なデータ処理、カスタムロジックの実装により、HubSpotを企業の業務自動化基盤として最大限に活用できます。まずは小さなユースケースから始めて、段階的に活用範囲を広げていくことを推奨します。
カテゴリ: HubSpotエンタープライズ | HubSpot
株式会社StartLinkは、事業推進に関わる「販売促進」「DXによる業務効率化(ERP/CRM/SFA/MAの導入)」などのご相談を受け付けております。 サービスのプランについてのご相談/お見積もり依頼や、ノウハウのお問い合わせについては、無料のお問い合わせページより、お気軽にご連絡くださいませ。
著者情報
今枝 拓海 / Takumi Imaeda
株式会社StartLinkの代表取締役。
HubSpotのトップパートナーである株式会社H&Kにて、HubSpotのCRM戦略/設計/構築を軸として、 国内・外資系エンタープライズ企業へコンサルティング支援を実施。
パーソルホールティングス株式会社にて、大規模CRM/SFA戦略の策定・PERSOLグループ横断のグループAI戦略/企画/開発ディレクションの業務を遂行経験あり。
株式会社StartLinkでは、累計100社以上のHubSpotプロジェクト実績を元にHubSpot×AIを軸にした経営基盤DXのコンサルティング事業を展開。