Zapier を使って HubSpot と Asana を連携させる方法と、Code by Zapier で集計ロジックを追加するテクニックを紹介します。

HubSpot × Asana 連携の基本

HubSpot(CRM・マーケティング)と Asana(プロジェクト管理)を連携させることで、営業パイプラインとタスク管理を自動化できます。Zapier を使えばノーコードで連携を構築できます。

よくある連携パターン

トリガー(HubSpot)アクション(Asana)ユースケース
新規ディールが作成されたタスクを作成商談ごとにプロジェクトタスクを自動生成
ディールのステージが変わったタスクを更新進捗をリアルタイムに反映
フォーム送信があったタスクを作成問い合わせ対応タスクを自動起票
新規チケットが作成されたタスクを作成サポート対応を Asana で管理

逆方向の連携もあります。

トリガー(Asana)アクション(HubSpot)ユースケース
タスクが完了したコンタクトを更新納品完了を CRM に反映
タスクにコメントが追加されたエンゲージメントを作成活動履歴を CRM に記録

Zapier での連携セットアップ

1. Zap の作成

Zapier にログインし、「Create Zap」から新しい Zap を作成します。

トリガーの設定(例: HubSpot → Asana):

  1. トリガーアプリに HubSpot を選択
  2. トリガーイベントに「New Deal」を選択
  3. HubSpot アカウントを接続
  4. テストを実行して動作確認

アクションの設定:

  1. アクションアプリに Asana を選択
  2. アクションイベントに「Create Task」を選択
  3. Asana アカウントを接続
  4. フィールドをマッピング:
    • Task Name → HubSpot のディール名
    • Project → 対象の Asana プロジェクト
    • Notes → ディールの詳細情報
    • Due Date → クローズ予定日

2. フィールドマッピングのコツ

HubSpot のプロパティを Asana のフィールドに適切にマッピングすることが重要です。

HubSpot Deal Name     → Asana Task Name
HubSpot Deal Amount   → Asana Custom Field (金額)
HubSpot Deal Stage    → Asana Section
HubSpot Close Date    → Asana Due Date
HubSpot Deal Owner    → Asana Assignee

集計ロジックの追加:Code by Zapier

標準のトリガー・アクションだけでは実現できない集計や変換が必要な場合、Code by Zapier ステップを間に挟むことで対応できます。

Code by Zapier とは

Zap のワークフロー内で JavaScript(Node.js 18)または Python のコードを実行できるステップです。

  • JavaScript: 標準ライブラリ + fetch パッケージが利用可能
  • Python: 標準ライブラリ + requests + BeautifulSoup が利用可能
  • 外部パッケージの追加インストールは不可

例1: ディール金額の集計

HubSpot から取得した複数のディール金額を集計して、Asana タスクの説明に含める例です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Code by Zapier (JavaScript)
// Input: dealAmounts (カンマ区切りの金額文字列)
const amounts = inputData.dealAmounts.split(',').map(Number);

const total = amounts.reduce((sum, val) => sum + val, 0);
const average = total / amounts.length;
const max = Math.max(...amounts);
const min = Math.min(...amounts);

output = {
  total: total,
  average: Math.round(average),
  count: amounts.length,
  max: max,
  min: min,
  summary: `合計: ¥${total.toLocaleString()} / 平均: ¥${Math.round(average).toLocaleString()} / 件数: ${amounts.length}`
};

例2: ステージごとのタスク振り分けロジック

ディールのステージに応じて、Asana の異なるプロジェクトやセクションにタスクを作成する分岐ロジックです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Code by Zapier (JavaScript)
// Input: dealStage, dealAmount
const stage = inputData.dealStage;
const amount = Number(inputData.dealAmount);

let project = '';
let section = '';
let priority = 'medium';

if (stage === 'closedwon') {
  project = 'オンボーディング';
  section = amount >= 1000000 ? 'エンタープライズ' : 'スタンダード';
  priority = amount >= 1000000 ? 'high' : 'medium';
} else if (stage === 'contractsent') {
  project = '契約管理';
  section = '契約書送付済み';
} else {
  project = '商談進行中';
  section = stage;
}

output = {
  project: project,
  section: section,
  priority: priority
};

例3: Python で日付ベースの集計

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Code by Zapier (Python)
# Input: created_dates (カンマ区切りの日付文字列)
from datetime import datetime
from collections import Counter

dates = input_data['created_dates'].split(',')
months = [datetime.strptime(d.strip(), '%Y-%m-%d').strftime('%Y-%m') for d in dates]
monthly_counts = Counter(months)

summary_lines = [f"{month}: {count}件" for month, count in sorted(monthly_counts.items())]

output = {
    'monthly_summary': '\n'.join(summary_lines),
    'total': len(dates),
    'latest_month': max(monthly_counts, key=monthly_counts.get)
}

より高度な集計: Zapier Functions

標準の Code by Zapier ではライブラリの追加ができませんが、Zapier Functions を使えば、外部パッケージを含む本格的な Python コードを実行できます。

Zapier Functions とは

Zapier Functions は、Zapier 内でサーバーレス Python 関数を作成・実行できるサービスです。概念的には AWS Lambda に近いですが、Zapier のエコシステムに統合されている点が異なります。

観点Zapier FunctionsAWS Lambda
位置づけZapier 内のサーバーレス関数AWS のサーバーレスコンピューティング
言語PythonPython, Node.js, Go, Java 他多数
外部パッケージPandas, NumPy, TensorFlow 等の主要パッケージpip/npm 等で自由にインストール可能
実行時間制限5 分最大 15 分
トリガーZap のステップ、Agent、MCP サーバーAPI Gateway, S3, SQS 等多数
シークレット管理組み込みの Secrets 機能AWS Secrets Manager / Parameter Store
デプロイZapier UI 上で直接編集・保存ZIP アップロード、SAM、CDK 等
再利用性複数の Zap / Agent から呼び出し可能API Gateway 等経由で任意に呼び出し可能
インフラ管理不要(フルマネージド)不要(フルマネージド)
料金Zapier プランに含まれる(オープンベータ)実行回数・時間による従量課金

Code by Zapier との違い

Zapier Functions は Code by Zapier の上位互換ではなく、別のサービスとして提供されています。

観点Code by ZapierZapier Functions
用途Zap 内のインラインスクリプト独立した再利用可能な関数
言語JavaScript (Node.js 18) / PythonPython
外部パッケージ不可(標準ライブラリ + fetch/requests のみ)Pandas, NumPy, TensorFlow 等が利用可能
実行時間30 秒(プランにより延長あり)5 分
メモリ256 MB非公開(より大きいと推定)
シークレット管理なし(Input Data に直接入力)組み込みの Secrets 機能で安全に管理
再利用Zap ごとにコードを記述1 つの関数を複数の Zap / Agent から呼び出し可能
開発環境Zapier エディタ内のテキストエリア専用の開発環境(ファイル分割可能)
ステータスGA(正式リリース)オープンベータ

Zapier Functions のアーキテクチャ

Zapier Functions は以下の構成要素で動作します。

[Zap / Agent / MCP サーバー]
    ↓ Call a Function アクション
[Zapier Functions]
    ├── Start a Function トリガー(入力フィールド定義)
    ├── Python コード(外部パッケージ + Secrets 利用可能)
    └── Return from Function アクション(結果を呼び出し元に返却)
    ↓
[呼び出し元に結果を返す]
  1. Start a Function トリガー: 入力パラメータを定義する。Zap から渡されるデータのスキーマを設定
  2. Python コード: メインのロジックを記述。外部パッケージのインポートや Secrets の参照が可能
  3. Return from Function アクション: 処理結果を呼び出し元(Zap / Agent)に返す。これにより呼び出し元は結果を待ってから次のステップに進める

Secrets 管理

Zapier Functions には組み込みのシークレット管理機能があり、API キーやトークンを安全に保存できます。

1
2
3
4
5
# Zapier Functions (Python)
# シークレットは環境変数のように参照可能
import os

hubspot_token = os.environ['HUBSPOT_API_KEY']  # Secrets に登録した値

Code by Zapier では Input Data にトークンを直接入力する必要がありましたが、Functions ではシークレットとして暗号化管理されるため、よりセキュアです。

利用例: Pandas でディールデータを集計

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Zapier Functions (Python)
import pandas as pd

# HubSpot から取得したディールデータ
deals = pd.DataFrame(input_data['deals'])

# ステージ別の集計
stage_summary = deals.groupby('stage').agg(
    count=('amount', 'count'),
    total=('amount', 'sum'),
    average=('amount', 'mean')
).round(0)

output = {
    'report': stage_summary.to_string(),
    'total_pipeline': int(deals['amount'].sum())
}

どちらを使うべきか

  • Code by Zapier: 簡単なデータ変換、フォーマット処理、単純な API コールなど、数行で済む処理
  • Zapier Functions: 外部パッケージが必要な処理、複数の Zap で共有したいロジック、API キーを安全に管理したい場合、30 秒以上かかる処理
  • AWS Lambda: Zapier のエコシステム外で動かしたい場合、Python 以外の言語を使いたい場合、15 分以上の処理、完全なカスタマイズが必要な場合

実践例: Asana タスクを集計して HubSpot Deal に Line Item を追加する

Asana のタスクデータを集計し、その結果を HubSpot の Deal に Line Item として追加するケースを考えます。Zapier の標準 HubSpot アクションには「Line Item を作成して Deal に紐付ける」アクションが直接用意されていないため、Code by Zapier から HubSpot API を直接呼び出す方法で実現します。

Zap の全体構成

[トリガー] Asana: タスク完了
    ↓
[アクション] Code by Zapier: Asana データ集計 + HubSpot API 呼び出し

前提条件

  • HubSpot の Private App を作成し、以下のスコープを付与しておく:
    • crm.objects.line_items.write(Line Item の作成)
    • crm.objects.line_items.read(Line Item の読み取り)
    • crm.objects.deals.read(Deal の読み取り)
  • Private App のアクセストークンを Zapier の Input Data に設定する

Code by Zapier の実装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Code by Zapier (JavaScript)
// Input Data:
//   hubspotToken - HubSpot Private App のアクセストークン
//   dealId       - 対象の HubSpot Deal ID
//   taskName     - Asana タスク名(Line Item の名前に使用)
//   hours        - Asana タスクの作業時間(カスタムフィールド等から取得)
//   hourlyRate   - 時間単価

const dealId = inputData.dealId;
const taskName = inputData.taskName;
const hours = Number(inputData.hours);
const hourlyRate = Number(inputData.hourlyRate || 5000);
const amount = hours * hourlyRate;

// HubSpot API で Line Item を作成し、Deal に紐付ける
const response = await fetch(
  'https://api.hubapi.com/crm/v3/objects/line_items',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${inputData.hubspotToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      properties: {
        name: taskName,
        price: amount,
        quantity: 1,
        description: `Asana タスク「${taskName}」: ${hours}時間 × ¥${hourlyRate.toLocaleString()}`
      },
      associations: [
        {
          to: { id: dealId },
          types: [
            {
              associationCategory: 'HUBSPOT_DEFINED',
              associationTypeId: 20
            }
          ]
        }
      ]
    })
  }
);

const result = await response.json();

if (!response.ok) {
  throw new Error(`HubSpot API error: ${JSON.stringify(result)}`);
}

output = {
  lineItemId: result.id,
  lineItemName: taskName,
  amount: amount,
  status: 'created'
};

既存の Product を使う場合

HubSpot に登録済みの Product(商品)から Line Item を作成する場合は、hs_product_id プロパティを指定します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 既存の Product ID を指定して Line Item を作成
body: JSON.stringify({
  properties: {
    hs_product_id: inputData.productId,  // HubSpot の Product ID
    quantity: Number(inputData.hours),
    // price は Product のデフォルト価格が使われる(上書きも可能)
  },
  associations: [
    {
      to: { id: dealId },
      types: [
        { associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 20 }
      ]
    }
  ]
})

複数タスクを一括で Line Item にする場合

Asana の複数タスクをまとめて処理する場合、Zapier の Looping by Zapier と組み合わせるか、Code ステップ内で一括処理します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Code by Zapier (JavaScript)
// Input Data:
//   tasks - JSON 文字列(Asana タスクの配列)
//   hubspotToken, dealId

const tasks = JSON.parse(inputData.tasks);
const results = [];

for (const task of tasks) {
  const res = await fetch(
    'https://api.hubapi.com/crm/v3/objects/line_items',
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${inputData.hubspotToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        properties: {
          name: task.name,
          price: task.amount,
          quantity: 1
        },
        associations: [
          {
            to: { id: inputData.dealId },
            types: [
              { associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 20 }
            ]
          }
        ]
      })
    }
  );

  const data = await res.json();
  results.push({ id: data.id, name: task.name, status: res.ok ? 'ok' : 'error' });
}

output = {
  created: results.filter(r => r.status === 'ok').length,
  errors: results.filter(r => r.status === 'error').length,
  details: JSON.stringify(results)
};

注意点

  • API レート制限: HubSpot API は Private App の場合、秒間 100 リクエストまで。大量のタスクを処理する場合は注意が必要
  • トークン管理: Private App のアクセストークンは Zapier の Input Data に直接入力するため、チーム内での共有・管理方法を検討すること
  • 代替手段: API を直接叩く代わりに Webhooks by Zapier(Custom Request アクション)でも同様のことが可能。集計ロジックが不要な場合はこちらの方がシンプル

ネイティブ連携との使い分け

HubSpot には Asana とのネイティブ連携(公式インテグレーション)も用意されています。

観点ネイティブ連携Zapier 連携
セットアップHubSpot の設定画面から直接接続Zapier アカウントが必要
カスタマイズ性限定的高い(Code ステップで自由に拡張)
集計・変換不可Code by Zapier で対応可能
コスト無料Zapier のプランに依存
信頼性高い(直接接続)Zapier の稼働状況に依存

集計ロジックやカスタム変換が必要な場合は Zapier、シンプルな双方向同期だけであればネイティブ連携がおすすめです。

まとめ

  • Zapier を使えば HubSpot と Asana の連携をノーコードで構築できる
  • Code by Zapier(JavaScript / Python)で集計・変換ロジックを追加できる
  • Code by Zapier から HubSpot API を直接呼び出すことで、Line Item の作成・Deal への紐付けも自動化できる
  • より高度な集計には Zapier Functions(Pandas 等のライブラリ対応)が利用可能
  • シンプルな同期であれば HubSpot のネイティブ連携も選択肢になる