Branch8

台灣電商直播帶貨導購名單整合 HubSpot 實作教學

Matt Li
November 3, 2026
13 mins read
台灣電商直播帶貨導購名單整合 HubSpot 實作教學

Key Takeaways

  • 先建結構化自訂屬性,不要把直播留言塞進備註欄位
  • 身分解析(LINE userId、PSID、手機)是整合成敗關鍵
  • 用 Batch Upsert 每批 100 筆,避開 429 速率限制
  • Webhook 先回 200 再非同步處理,並以冪等鍵防重複
  • 行銷同意時間戳記應寫入 CRM 並作為 Workflow 條件

台灣電商品牌要把直播帶貨的導購名單整合進 HubSpot,核心是三步:在直播平台(Facebook Live、LINE、Shopee Live)側接 Webhook 擷取留言與下單意圖,統一映射成 HubSpot Contact 自訂屬性,再以 Batch Upsert API 以 Email 或手機號碼去重寫入,最後用 Workflow 觸發跟單。

直播帶貨在台灣已經從「導購工具」變成主要銷售通道之一。但多數品牌的現實是:直播當下留言區 +1 的名單躺在社群小編的 Excel,LINE OA 的私訊名單躺在另一套客服後台,官網訂單在 Shopline 或 Cyberbiz,三套資料從來沒有合在一起。結果是同一位顧客在一週內被三個通路用三種語氣打擾,而真正高意圖的 +1 未成交名單在 48 小時後失溫。

這篇教學會走完一條可落地的資料流:從直播平台事件擷取 → 身分解析(identity resolution)→ HubSpot 寫入 → 生命週期自動化 → 跨境擴張時的資料治理。程式碼以 Node.js 18+ 與 HubSpot CRM API v3 為例,概念同樣適用於 Python 或 n8n、Make 等低程式碼工具。

開始之前需要準備什麼?

HubSpot 端

  1. HubSpot 帳號方案:Marketing Hub Professional 以上(Workflows 自動化與自訂屬性數量限制較寬鬆)。Starter 可以做資料寫入,但無法跑多分支 Workflow。
  2. Private App Access Token:到 Settings → Integrations → Private Apps 建立,勾選 crm.objects.contacts.read、crm.objects.contacts.write、crm.schemas.contacts.write、crm.objects.deals.write。依 HubSpot 開發者文件,Private App 在 Professional / Enterprise 方案的速率上限為每 10 秒 190 次請求,Free / Starter 為每 10 秒 100 次。
  3. 資料模型決策:先決定直播名單要落在 Contact 的自訂屬性,還是另開 Custom Object(Enterprise 才有)。90% 的品牌用自訂屬性就夠。

直播平台端

  • Facebook / Instagram Live:需要 Meta Business 驗證過的 App,權限 pages_read_engagement、pages_manage_metadata,訂閱 Page Webhook 的 live_videos 與 feed 欄位。
  • LINE Official Account:Messaging API Channel 的 Channel Access Token 與 Channel Secret。LINE Developers 文件說明 multicast 單次最多 500 位接收者,這會影響你的名單推播批次設計。
  • 電商平台:Shopline、Cyberbiz、91APP 多半提供訂單 Webhook 或 Open API;若沒有,退而求其次用每日 CSV 排程匯入。

法遵前置

台灣《個人資料保護法》要求蒐集個資時應明確告知蒐集目的、個資類別、利用期間與地區。直播留言 +1 不等於行銷同意——你要在轉入 LINE 或表單的那一步取得明示同意,並把同意時間戳記寫進 CRM。這個欄位後面會用到。

第一步:定義 HubSpot 的直播名單資料模型

不要直接把留言塞進 notes。先建立一組結構化屬性,之後才做得出分眾。用 API 建立比在 UI 點十次快:

1curl -X POST \
2 'https://api.hubapi.com/crm/v3/properties/contacts' \
3 -H "Authorization: Bearer $HUBSPOT_TOKEN" \
4 -H 'Content-Type: application/json' \
5 -d '{
6 "name": "live_last_session_id",
7 "label": "最近一次直播場次 ID",
8 "groupName": "livestream_commerce",
9 "type": "string",
10 "fieldType": "text"
11 }'

建議的最小欄位組:

  • live_last_session_id(string)— 場次識別,對應你的直播排程表
  • live_last_sku_interest(string)— 留言中提及的商品代號
  • live_intent_signal(enumeration)— comment_plus_one / dm_inquiry / cart_add / purchased
  • live_channel_source(enumeration)— facebook_live / line_oa / shopee_live / tiktok_live
  • live_session_count(number)— 累計參與場次
  • marketing_consent_ts(datetime)— 行銷同意時間戳記
  • preferred_market(enumeration)— TW / HK / SG / MY,跨境時必備

列舉型屬性要連 options 一起送:

1{
2 "name": "live_intent_signal",
3 "label": "直播意圖訊號",
4 "groupName": "livestream_commerce",
5 "type": "enumeration",
6 "fieldType": "select",
7 "options": [
8 { "label": "留言 +1", "value": "comment_plus_one", "displayOrder": 0 },
9 { "label": "私訊詢問", "value": "dm_inquiry", "displayOrder": 1 },
10 { "label": "加入購物車", "value": "cart_add", "displayOrder": 2 },
11 { "label": "已成交", "value": "purchased", "displayOrder": 3 }
12 ]
13}

屬性 name 只能用小寫字母、數字與底線,建立後不可更名——命名時先想清楚,否則三個月後你會有 live_sku 和 live_sku_v2 兩個欄位並存。

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

第二步:接收直播平台的留言與互動事件

Facebook Live 留言 Webhook

訂閱 Page 的 feed 欄位後,每則直播留言會推送到你的端點。驗證簽章是必要的,否則任何人都能灌假名單:

1import express from 'express';
2import crypto from 'crypto';
3
4const app = express();
5app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf; } }));
6
7function verifyMetaSignature(req) {
8 const signature = req.get('X-Hub-Signature-256') || '';
9 const expected = 'sha256=' + crypto
10 .createHmac('sha256', process.env.META_APP_SECRET)
11 .update(req.rawBody)
12 .digest('hex');
13 return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
14}
15
16app.post('/webhook/meta', async (req, res) => {
17 if (!verifyMetaSignature(req)) return res.sendStatus(401);
18 res.sendStatus(200); // 先回 200,避免 Meta 重送
19
20 for (const entry of req.body.entry ?? []) {
21 for (const change of entry.changes ?? []) {
22 const v = change.value;
23 if (v.item !== 'comment' || !v.message) continue;
24 await queue.add('live-comment', {
25 psid: v.from?.id,
26 name: v.from?.name,
27 message: v.message,
28 sessionId: v.post_id,
29 createdAt: v.created_time,
30 channel: 'facebook_live'
31 });
32 }
33 }
34});

重點:立即回 200 再非同步處理。直播高峰留言每秒可能數十則,同步寫 HubSpot 會被 Meta 判定逾時並重送,造成重複名單。

解析 +1 與商品代號

台灣直播留言的實務寫法非常不規則:+1、+1、+1 M號、A3 兩件、加一。純正則會漏掉一半。混合做法最穩:先用正則抓高信心樣式,剩下的交給 LLM 批次分類。

1const PLUS_ONE = /(\+\s?1|+\s?1|加一|我要)/;
2const SKU = /\b([A-Z]{1,3}\d{1,3})\b/;
3
4export function parseComment(text) {
5 const normalised = text.normalize('NFKC').trim();
6 return {
7 isIntent: PLUS_ONE.test(normalised),
8 sku: normalised.match(SKU)?.[1] ?? null,
9 needsLlm: !PLUS_ONE.test(normalised) && normalised.length <= 40
10 };
11}

把 needsLlm 為真的留言每 50 則打包一次送給模型,要求回傳嚴格 JSON(意圖、SKU、尺寸、數量)。這是 Q1 2026 最實際的 AI 應用場景之一:不是取代小編,而是讓一位小編在單場直播中能處理原本需要三人輪班整理的留言量。記得設定信心門檻,低信心的留言仍進人工佇列。

LINE OA 事件

LINE 的價值在於它是台灣少數能同時拿到穩定身分識別(userId)與對話通道的平台:

1app.post('/webhook/line', (req, res) => {
2 const signature = req.get('x-line-signature');
3 const hash = crypto.createHmac('sha256', process.env.LINE_CHANNEL_SECRET)
4 .update(req.rawBody).digest('base64');
5 if (hash !== signature) return res.sendStatus(401);
6 res.sendStatus(200);
7
8 for (const event of req.body.events ?? []) {
9 if (event.type === 'message' && event.message.type === 'text') {
10 queue.add('line-inquiry', {
11 lineUserId: event.source.userId,
12 message: event.message.text,
13 channel: 'line_oa'
14 });
15 }
16 }
17});

第三步:身分解析——最容易被低估的一關

Facebook 給你 PSID,LINE 給你 userId,電商平台給你 Email 和手機。這三個 ID 之間沒有天然關聯,而 HubSpot 的主鍵是 Email。沒有解決這一步,你得到的是三份互不相干的名單,不是整合。

實務上可行的橋接順序:

  1. 手機號碼正規化後比對(台灣門號 09xxxxxxxx → E.164 +8869xxxxxxxx)。跨境時這一步不能省,否則香港 +852 與台灣門號會撞號。
  2. 以導購動作換取識別:直播中請觀眾加 LINE 領取優惠碼,優惠碼綁定場次與 SKU;兌換時在結帳頁回填,即完成 LINE userId ↔ 訂單 Email 的連結。
  3. 保留原始 ID 當備援欄位:建立 line_user_id、meta_psid 兩個自訂屬性,即使暫時沒有 Email 也能先建 Contact(HubSpot 允許以手機或自訂唯一值作為去重鍵)。

把自訂屬性設成 unique identifier:建立屬性時加上 "hasUniqueValue": true,之後就能用它做 Upsert。

1import { normalizePhone } from './phone.js';
2
3export function resolveIdentity(raw) {
4 const email = raw.email?.toLowerCase().trim() || null;
5 const phone = raw.phone ? normalizePhone(raw.phone, raw.market ?? 'TW') : null;
6 if (email) return { idProperty: 'email', id: email };
7 if (phone) return { idProperty: 'phone', id: phone };
8 if (raw.lineUserId) return { idProperty: 'line_user_id', id: raw.lineUserId };
9 return null; // 無法識別,進人工佇列
10}

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

第四步:用 Batch Upsert 寫入 HubSpot

單筆寫入會在直播高峰撞上速率限制。改用批次端點,單次最多 100 筆:

1const HS = 'https://api.hubapi.com';
2
3async function batchUpsertContacts(records, idProperty = 'email') {
4 const chunks = [];
5 for (let i = 0; i < records.length; i += 100) chunks.push(records.slice(i, i + 100));
6
7 for (const chunk of chunks) {
8 const body = {
9 inputs: chunk.map(r => ({
10 idProperty,
11 id: r.id,
12 properties: {
13 email: r.email,
14 phone: r.phone,
15 firstname: r.name,
16 live_last_session_id: r.sessionId,
17 live_last_sku_interest: r.sku,
18 live_intent_signal: r.intent,
19 live_channel_source: r.channel,
20 preferred_market: r.market ?? 'TW'
21 }
22 }))
23 };
24
25 const res = await fetch(`${HS}/crm/v3/objects/contacts/batch/upsert`, {
26 method: 'POST',
27 headers: {
28 Authorization: `Bearer ${process.env.HUBSPOT_TOKEN}`,
29 'Content-Type': 'application/json'
30 },
31 body: JSON.stringify(body)
32 });
33
34 if (res.status === 429) {
35 const retryAfter = Number(res.headers.get('Retry-After') ?? 10);
36 await new Promise(r => setTimeout(r, retryAfter * 1000));
37 continue; // 重試本批
38 }
39 if (!res.ok) {
40 console.error('upsert failed', res.status, await res.text());
41 continue;
42 }
43 const json = await res.json();
44 console.log(`upserted ${json.results.length} contacts`);
45 }
46}

預期輸出:成功時回 200 或 207(部分成功),results 陣列含每筆的 id 與 updatedAt;部分失敗時 numErrors 與 errors 會列出哪幾筆出問題,常見是 enumeration 值不在選項清單內。

live_session_count 這種累計欄位不要在 Upsert 時硬寫,否則會被覆蓋。改用 HubSpot Workflow 的 "Increment property value" 動作,或在寫入前先 GET 現值再 +1(但要注意併發競態,高流量場次建議交給 Workflow 處理)。

第五步:把名單變成自動化跟單流程

資料進了 CRM 只是起點。直播名單的衰退曲線很陡——當場未結帳的 +1,隔天熱度就掉了一大截。設計三條 Workflow:

Workflow A:未結帳高意圖(直播後 30 分鐘觸發)

  • Enrollment:live_intent_signal = comment_plus_one 且 live_last_session_id 等於本場 且 無對應 Deal
  • 動作:建立 Deal(Pipeline = 直播導購,Stage = 待結帳)→ 指派值班客服 → 透過 Webhook 動作呼叫你的服務,推送 LINE 一對一訊息附帶預填購物車連結
  • 分支:24 小時後若 Deal 仍在待結帳,發送限時優惠;48 小時後標記為 cold 並停止推播

Workflow 的 Webhook 動作可以直接打你的 LINE 推播服務:

1app.post('/hooks/hubspot/line-push', async (req, res) => {
2 const { lineUserId, sku, couponCode } = req.body;
3 await fetch('https://api.line.me/v2/bot/message/push', {
4 method: 'POST',
5 headers: {
6 Authorization: `Bearer ${process.env.LINE_CHANNEL_TOKEN}`,
7 'Content-Type': 'application/json'
8 },
9 body: JSON.stringify({
10 to: lineUserId,
11 messages: [{
12 type: 'text',
13 text: `您在直播中預訂的 ${sku} 已為您保留,30 分鐘內結帳可用 ${couponCode}`
14 }]
15 })
16 });
17 res.sendStatus(200);
18});

Workflow B:高頻觀眾分群

live_session_count >= 3 且 90 天內有成交 → 加入「直播 VIP」靜態名單,優先推播新品預告與場次提醒。這群人的再行銷效率通常遠高於冷流量。

Workflow C:同意管理與靜音

marketing_consent_ts 為空的聯絡人,只允許交易型訊息(訂單確認、到貨通知),不得進入行銷推播。這條規則要寫在 Workflow 的 enrollment 條件,而不是靠人記得。

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

直播名單整合常見的六個坑

重複聯絡人暴增

症狀:一場直播後 Contact 數跳增,但多是同一人。 原因:Upsert 用了會變動的 ID(例如留言 ID),或手機號碼未正規化。 處理:統一 E.164 格式、固定 idProperty,並定期跑 HubSpot 內建的重複項管理工具合併。

429 Too Many Requests

依 HubSpot 文件,Private App 在 Professional / Enterprise 為每 10 秒 190 次請求。直播高峰很容易打滿。解法是佇列 + 批次(每批 100 筆)+ 指數退避,並尊重回應中的 Retry-After 標頭。

Webhook 重送導致重複處理

Meta 與 LINE 在未收到 200 時會重送。在佇列層做冪等:以 channel + platform_event_id 作為去重鍵存入 Redis,TTL 設 24 小時。

列舉值寫入失敗

錯誤訊息類似 PROPERTY_DOESNT_EXIST 或值不在選項內。新增通路(例如開始做 TikTok Live)時,要先更新屬性 options 再送資料,否則整批 207 部分失敗。

中文全形字元造成比對失效

+1 與 +1 在未正規化前是兩個字串。所有留言文字先跑 normalize('NFKC')。

時區錯位

HubSpot datetime 屬性以 UTC 毫秒時間戳儲存。台灣 UTC+8、香港 UTC+8、新加坡 UTC+8、澳洲東岸 UTC+10/+11。如果報表直接用 UTC 日期切分,晚上 8 點的直播會被算成隔天。在 Workflow 與報表層統一指定時區,而不是在寫入時偷偷加 8 小時。

跨境擴張時,這套架構要怎麼調整?

台灣品牌把直播模式複製到香港、新加坡、馬來西亞時,技術架構多半可沿用,但有三件事必須重新設計。

一、通路權重不同。 台灣與泰國以 LINE 與 Facebook Live 為主,香港與新加坡 WhatsApp 與 Instagram Live 佔比更高,印尼則偏向 TikTok Live 與 Shopee Live。live_channel_source 這個欄位要從一開始就設計成可擴充,推播服務要抽象成 channel adapter 介面,而不是把 LINE API 硬寫進 Workflow。

二、個資法規不同。 台灣適用《個人資料保護法》,新加坡適用 PDPA(由 PDPC 主管,含 Do Not Call 名冊規範),香港適用《個人資料(私隱)條例》,若你有歐盟顧客則落入 GDPR。實務上最省事的做法是以最嚴格的同意標準(明示 opt-in + 可撤回 + 時間戳記)統一設計,再用 preferred_market 做區域性例外,而不是每個市場蓋一套。

三、營運時區覆蓋。 直播通常在晚間,而跟單黃金時間是結束後兩小時。單一市場團隊做兩三場還撐得住,一週跨三個市場就會崩。這也是為什麼不少歐美與澳洲品牌把直播營運與 CRM 維運放在亞洲——香港、台北、新加坡同屬 UTC+8,加上胡志明市與吉隆坡的團隊,能把跟單視窗接續成接近全日覆蓋。

Branch8 曾為一家在台灣與香港同時營運的多品牌零售集團建置類似的直播名單管線:前端以 Node.js 服務接 Meta 與 LINE Webhook,中介層用 Redis 做冪等與佇列,資料落到 HubSpot 的 Contact 與自訂 Deal Pipeline,LLM 僅負責留言意圖分類並保留人工覆核佇列。架構上最花時間的從來不是 API 串接,而是身分解析規則與各市場同意文案的治理。

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

上線前的驗收清單

  1. 用 HubSpot 的 Sandbox 或測試 Portal 跑完整流程,確認屬性都有值而非空白
  2. 模擬 500 則留言的壓力測試,確認佇列不塞車、沒有 429 連續失敗
  3. 故意送重複事件,確認冪等鍵生效、Contact 不重複
  4. 檢查 marketing_consent_ts 為空的聯絡人確實被排除在行銷 Workflow 之外
  5. 確認報表時區設定為 Asia/Taipei,直播場次歸因日期正確
  6. 建立 Webhook 失敗告警(連續 5 次非 2xx 即通知),直播當下沒有人會盯 log

把這六項跑過一遍,再上第一場正式直播。單場直播的名單只有一次機會,補不回來。

如果你的團隊正在把直播、LINE、官網與 HubSpot 的資料串成單一顧客視圖,或準備把台灣驗證過的直播模式複製到香港、新加坡與東南亞市場,Branch8 在亞太七個據點的 CRM 與 CDP 實作團隊可以協助你規劃資料模型、身分解析與跨市場的同意治理架構——歡迎與我們聊聊你的現況。

Sources

FAQ

不行。台灣《個人資料保護法》要求蒐集個資時明確告知蒐集目的、類別與利用範圍,公開留言 +1 只代表購買意圖,不等於同意接受行銷推播。建議在引導加入 LINE 或填寫表單的步驟取得明示同意,並把同意時間戳記寫入 HubSpot 的 marketing_consent_ts 屬性,作為行銷 Workflow 的進入條件。

About the Author

Matt Li

Co-Founder & CEO, Branch8 & Second Talent

Matt Li is Co-Founder and CEO of Branch8, a Y Combinator-backed (S15) Adobe Solution Partner and e-commerce consultancy headquartered in Hong Kong, and Co-Founder of Second Talent, a global tech hiring platform ranked #1 in Global Hiring on G2. With 12 years of experience in e-commerce strategy, platform implementation, and digital operations, he has led delivery of Adobe Commerce Cloud projects for enterprise clients including Chow Sang Sang, HomePlus (HKBN), Maxim's, Hong Kong International Airport, Hotai/Toyota, and Evisu. Prior to founding Branch8, Matt served as Vice President of Mid-Market Enterprises at HSBC. He serves as Vice Chairman of the Hong Kong E-Commerce Business Association (HKEBA). A self-taught software engineer, Matt graduated from the University of Toronto with a Bachelor of Commerce in Finance and Economics.