Branch8

台灣個資法(PIPA)CRM 顧客標籤與分眾合規設計指南

Matt Li
September 4, 2026
13 mins read
台灣個資法(PIPA)CRM 顧客標籤與分眾合規設計指南

Key Takeaways

  • 台灣是「個資法/PDPA」,與韓國 PIPA 的同意要求不同,勿共用一套邏輯
  • 標籤分 L1 交易、L2 推論、L3 特種三層;CRM 預設不存 L3
  • 同意應為 append-only 事件表,記錄目的代號、通路與告知版本
  • 所有分眾只能查已套同意過濾的 secure view,禁止直查原始表
  • LLM 生成標籤須限制在封閉白名單,並考量境外 API 屬國際傳輸

在台灣個資法(常被稱為 PIPA)下設計 CRM 標籤與分眾,核心是三件事:每個標籤都要對應「特定目的」、每筆行銷利用都要有可稽核的同意或合法事由、以及每個分眾查詢都必須先經過同意閘門過濾。以下是可直接落地的實作步驟。

先釐清:台灣的法規叫「個資法」,不是 PIPA

很多跨國團隊在做 APAC 合規盤點時,會把台灣寫成「PIPA」——這其實是韓國《개인정보 보호법》(PIPA)的縮寫習慣被套用到台灣。台灣的正式名稱是《個人資料保護法》,依全國法規資料庫公告版本,通常英文譯作 Personal Data Protection Act(PDPA)。

這不只是命名問題。韓國 PIPA、新加坡 PDPA、台灣個資法三者在「行銷同意」的要求上差異很大:

  • 台灣個資法:非公務機關蒐集個資需符合第 19 條法定事由;首次為行銷目的利用時,依第 20 條第 2、3 項,應提供當事人表示拒絕接受行銷之方式,且所需費用由利用者負擔。
  • 韓國 PIPA:行銷用途原則上需要獨立、明示的 opt-in 同意,與服務條款同意分開。
  • 新加坡 PDPA:另有 Do Not Call Registry,電話與簡訊行銷需先比對名單。

如果你的 CDP 是一套 schema 打天下,這三個市場的分眾邏輯遲早會撞牆。實務上我們在協助一家在台、港、星三地都有門市的美妝零售集團整併 Segment 與 Salesforce Marketing Cloud 時,第一個決定就是:同意狀態必須是「市場 × 通路 × 目的」的三維欄位,而不是單一 boolean

另外值得注意的是,2023 年個資法修正後,台灣設立了個人資料保護委員會作為專責主管機關,取代過去分散在各目的事業主管機關的架構。這代表未來的裁罰與檢查會更集中、更專業,CRM 的稽核軌跡(audit trail)價值只會上升。

開始前需要準備什麼?

在寫任何一行 code 之前,先確認這些前置條件到位:

  1. 一份現行的隱私權政策與蒐集告知文字,並且知道每個表單、每個 App 畫面用的是哪一版。
  2. 特定目的代號清單。台灣個資法要求告知蒐集之「特定目的」,法務部與相關主管機關公告有「個人資料保護法之特定目的及個人資料之類別」代號表(例如 040 行銷、090 消費者、客戶管理與服務、069 契約、類似契約或其他法律關係事務)。你的標籤治理應該直接映射到這些代號。
  3. 技術權限:CDP(Segment / mParticle)的 workspace admin、CRM(Salesforce / HubSpot)的 metadata 部署權限、資料倉儲(BigQuery / Snowflake)的 DDL 權限。
  4. 一個 staging 環境。同意欄位改錯會直接造成違法寄送,不要在正式環境試。
  5. 法遵窗口。工程可以設計機制,但「這個標籤屬於哪個特定目的」必須由法遵或 DPO 拍板。

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.

步驟一:把標籤分成三個風險層級

多數 CRM 標籤混亂的根源,是把「事實」「推論」「敏感」三種性質完全不同的資料放在同一個 tag 欄位裡。先建立分類法:

L1 — 交易事實標籤

直接來自交易或帳戶紀錄:purchased_category_skincareltv_band_top10store_pref_taipei_101。這些通常落在「契約或類似契約關係」與「消費者、客戶管理與服務」的特定目的內,行銷再利用時仍需檢查第 20 條。

L2 — 行為推論標籤

來自瀏覽、開信、模型分數:churn_risk_highbrowsed_pregnancy_products這一層最危險,因為推論標籤可能間接揭露特種個資。「瀏覽孕婦用品」實質上推論了健康狀態;「常買清真食品」可能推論宗教信仰。

L3 — 特種個資

個資法第 6 條列舉的病歷、醫療、基因、性生活、健康檢查及犯罪前科,原則上不得蒐集處理利用,除有法定例外。預設規則:CRM 不存 L3。 若業務確實需要(例如藥妝或保健業),必須走獨立的書面同意流程與隔離儲存。

把這個分類法寫成機器可讀的 registry,而不是 Confluence 上的一張表:

1# tag_registry.yaml — 由 CI 驗證,任何新標籤必須先進這份檔案
2- tag: purchased_category_skincare
3 tier: L1
4 purpose_codes: ["069", "090"]
5 markets: [TW, HK, SG]
6 retention_days: 1095
7 marketing_use: allowed_with_optout
8 owner: crm-ops
9
10- tag: browsed_maternity_products
11 tier: L2
12 purpose_codes: ["040"]
13 markets: [TW]
14 sensitivity_flag: health_inference # 觸發人工覆核
15 retention_days: 180
16 marketing_use: requires_explicit_consent
17 owner: growth
18
19- tag: allergy_profile
20 tier: L3
21 purpose_codes: []
22 markets: []
23 marketing_use: prohibited
24 storage: isolated_vault_only

在 CI 加一個檢查,阻擋沒有註冊的標籤進入生產環境:

1# pre-deploy check
2python scripts/validate_tags.py \
3 --registry tag_registry.yaml \
4 --source dbt/models/marts/customer_tags.sql \
5 --fail-on unregistered,L3_in_crm
6
7# 預期輸出
8# ✓ 142 tags validated
9# ✗ ERROR: tag 'health_condition_diabetes' matches L3 pattern, not permitted in CRM layer
10# exit code 1

步驟二:設計可稽核的同意資料模型

同意不是一個布林值,是一筆事件。你需要能回答稽核人員的問題:「2025 年 3 月 12 日寄給王先生的這封 EDM,依據的是哪一次同意、當時的告知文字是什麼版本?」

建立 append-only 的同意事件表:

1-- Snowflake / BigQuery 皆適用
2CREATE TABLE consent_events (
3 event_id STRING NOT NULL,
4 subject_id STRING NOT NULL, -- 內部 customer id,勿用身分證字號
5 market STRING NOT NULL, -- TW / HK / SG / AU
6 purpose_code STRING NOT NULL, -- 對應特定目的代號,例如 040
7 channel STRING NOT NULL, -- email / sms / line / push / call
8 status STRING NOT NULL, -- granted / withdrawn / expired
9 captured_at TIMESTAMP NOT NULL,
10 source STRING NOT NULL, -- web_signup_v4 / pos_tablet / line_oa
11 notice_version STRING NOT NULL, -- 當時展示的告知文字版本
12 evidence_uri STRING, -- 畫面截圖或表單快照存放位置
13 ip_hash STRING,
14 ingested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP()
15);

再建一個 current-state view,給下游分眾使用:

1CREATE OR REPLACE VIEW consent_current AS
2SELECT subject_id, market, purpose_code, channel,
3 status, captured_at, notice_version
4FROM (
5 SELECT *, ROW_NUMBER() OVER (
6 PARTITION BY subject_id, market, purpose_code, channel
7 ORDER BY captured_at DESC
8 ) AS rn
9 FROM consent_events
10)
11WHERE rn = 1;

關鍵設計原則:consent_events 永不 UPDATE、永不 DELETE。撤回同意是新增一筆 status = 'withdrawn',不是改掉舊的那筆。這樣才有完整軌跡。

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.

步驟三:在 Segment 與 CRM 落實同意欄位

Segment 的 Consent Management 功能允許在 track/identify 呼叫中夾帶同意脈絡,並在 destination 層做過濾。實作時把台灣的目的代號直接放進 context:

1// 前端埋點:同意狀態隨事件走
2analytics.identify(userId, {
3 market: 'TW',
4 crm_tier: 'gold'
5}, {
6 consent: {
7 categoryPreferences: {
8 Functional: true,
9 Marketing: true,
10 Advertising: false
11 }
12 },
13 // 自訂欄位:台灣個資法特定目的
14 tw_pdpa: {
15 purpose_codes: ['069', '090', '040'],
16 notice_version: 'tw-privacy-2026-01',
17 optout_channel_url: 'https://example.com/tw/unsubscribe'
18 }
19});

Salesforce 這邊,不要自己造輪子——Salesforce 已有標準的 Individual、ContactPointEmail、ContactPointConsent 等 Consent Management 物件。用 SOQL 檢查:

1SELECT Id, ContactPointEmail.EmailAddress, DataUsePurpose.Name,
2 PrivacyConsentStatus, EffectiveFrom, CaptureSource
3FROM ContactPointConsent
4WHERE ContactPointEmail.ParentId = :individualId
5 AND DataUsePurpose.Name = 'TW_Marketing_040'
6 AND PrivacyConsentStatus = 'OptIn'

加一個 Apex trigger 做最後防線,避免有人繞過 Journey Builder 直接寄送:

1trigger BlockNonConsentedSend on MarketingSendRequest__c (before insert) {
2 Set<Id> individualIds = new Set<Id>();
3 for (MarketingSendRequest__c r : Trigger.new) individualIds.add(r.Individual__c);
4
5 Map<Id, ContactPointConsent> consented = new Map<Id, ContactPointConsent>();
6 for (ContactPointConsent c : [
7 SELECT Id, ContactPointEmail.ParentId
8 FROM ContactPointConsent
9 WHERE ContactPointEmail.ParentId IN :individualIds
10 AND DataUsePurpose.Name = 'TW_Marketing_040'
11 AND PrivacyConsentStatus = 'OptIn'
12 ]) {
13 consented.put(c.ContactPointEmail.ParentId, c);
14 }
15
16 for (MarketingSendRequest__c r : Trigger.new) {
17 if (r.Market__c == 'TW' && !consented.containsKey(r.Individual__c)) {
18 r.addError('TW PDPA: 缺少特定目的 040 之有效同意,寄送已阻擋。');
19 }
20 }
21}

HubSpot 使用者則可透過 Subscription Types 建立對應台灣特定目的的訂閱類型,並在 Legal Basis 欄位選擇對應法源,再用 Active List 篩選。重點一樣:訂閱類型要按目的與通路拆開,不要只有一個「行銷電子郵件」

步驟四:讓每個分眾查詢都通過同意閘門

最常見的違規來源不是同意沒收集,而是分析師自己寫了一段 SQL 拉名單匯出成 CSV。解法是:不讓任何人直接查原始表,只暴露已經套過同意過濾的 view。

1-- 這是唯一允許行銷團隊查詢的 audience 來源
2CREATE OR REPLACE SECURE VIEW audience_tw_email_marketing AS
3SELECT
4 c.subject_id,
5 c.email_hash,
6 t.tag,
7 t.tag_tier,
8 cc.notice_version,
9 cc.captured_at AS consent_captured_at
10FROM customers c
11JOIN customer_tags t ON t.subject_id = c.subject_id
12JOIN consent_current cc
13 ON cc.subject_id = c.subject_id
14 AND cc.market = 'TW'
15 AND cc.purpose_code = '040'
16 AND cc.channel = 'email'
17 AND cc.status = 'granted'
18JOIN tag_registry r ON r.tag = t.tag
19WHERE c.market = 'TW'
20 AND r.tier IN ('L1','L2')
21 AND r.marketing_use <> 'prohibited'
22 AND t.updated_at >= DATEADD(day, -r.retention_days, CURRENT_DATE());

用 dbt 把這層固化成契約模型,並加上測試:

1# models/marts/schema.yml
2models:
3 - name: audience_tw_email_marketing
4 tests:
5 - dbt_utils.expression_is_true:
6 expression: "tag_tier != 'L3'"
7 - dbt_utils.expression_is_true:
8 expression: "consent_captured_at is not null"
9 columns:
10 - name: subject_id
11 tests: [unique_combination_of_columns, not_null]

執行後預期輸出:

1$ dbt test --select audience_tw_email_marketing
211:42:03 Running 4 tests
311:42:07 PASS expression_is_true_tag_tier ......... [PASS in 3.1s]
411:42:09 PASS expression_is_true_consent_captured . [PASS in 1.8s]
511:42:09 Done. PASS=4 WARN=0 ERROR=0

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.

步驟五:把「拒絕行銷」做成一等公民

個資法第 20 條要求,首次為行銷利用時應提供當事人表示拒絕的方式,且費用由利用者負擔。落到工程上有三個具體要求:

  1. 每一個行銷通路都要有 opt-out 入口。Email 有退訂連結不代表 SMS 與 LINE 官方帳號也有。
  2. 免費。不能要求消費者打付費電話或寄回郵資自付的信函。
  3. 傳播要快。退訂應在數分鐘內同步到所有下游 destination,而不是等隔夜批次。

用 webhook 把退訂即時寫回同意事件表:

1# FastAPI 範例:統一 opt-out 端點,所有通路共用
2@app.post("/consent/withdraw")
3async def withdraw(payload: WithdrawRequest):
4 event = {
5 "event_id": str(uuid4()),
6 "subject_id": resolve_subject(payload.token),
7 "market": payload.market,
8 "purpose_code": "040",
9 "channel": payload.channel, # email / sms / line / push / call
10 "status": "withdrawn",
11 "captured_at": datetime.now(timezone.utc),
12 "source": payload.source,
13 "notice_version": payload.notice_version,
14 }
15 await warehouse.insert("consent_events", event)
16 # 即時推回 CDP,不等 batch
17 await segment.track(
18 user_id=event["subject_id"],
19 event="Marketing Consent Withdrawn",
20 properties={"channel": payload.channel, "market": payload.market},
21 )
22 return {"status": "ok", "effective": "immediate"}

踩過的坑:如果 opt-out 端點需要登入才能使用,實務上會大幅提高門檻,也容易被主管機關認為「未提供合理的拒絕方式」。用一次性簽章 token(HMAC + 短效期)取代登入牆。

步驟六:跨境傳輸與 APAC 多市場架構怎麼設計?

個資法第 21 條規定,中央目的事業主管機關於特定情形下(例如涉及國家重大利益、接受國對個資保護未有完善法規致有損當事人權益之虞)得限制國際傳輸。實務上,金融、電信、醫療等特許行業另有主管機關的個別函釋與限制。

對於總部在美國或歐洲、但把 CRM 營運放在亞太的企業,務實的架構是:

資料落地:分區儲存,集中治理

把台灣顧客的可識別欄位(PII)留在台灣或有適足性認定的區域,分析層只同步假名化後的 subject_id 與標籤。多數雲端倉儲支援 region-pinned dataset:

1-- BigQuery:建立區域鎖定的資料集
2CREATE SCHEMA `proj.crm_tw`
3OPTIONS (location = 'asia-east1', default_table_expiration_days = 1095);
4
5-- 分析層只收假名化輸出
6CREATE TABLE `proj.analytics_global.tw_tags_pseudonymised` AS
7SELECT TO_HEX(SHA256(CONCAT(subject_id, @pepper))) AS pid,
8 tag, tag_tier, updated_at
9FROM `proj.crm_tw.customer_tags`;

一份治理、多份設定

標籤 registry 是全球共用的,但 marketsmarketing_use 欄位讓同一個標籤在不同市場有不同行為。台灣走「告知 + 可拒絕」,韓國走「明示 opt-in」,新加坡加 DNC 比對,澳洲遵循 Spam Act 的同意要求。程式碼一套,政策參數化。

這也是為什麼跨時區的營運團隊有實質價值:台北工程時間與新加坡、香港重疊,可以在同一個工作日內完成「法遵確認 → schema 變更 → 部署驗證」,而不是每次改動都跨一個夜晚。

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.

步驟七:自動化保存期限與刪除

個資法第 11 條規定,個資特定目的消失或期限屆滿時,應主動或依當事人請求刪除、停止處理或利用。把它寫成排程任務:

1-- 每日執行:清除逾期標籤
2DELETE FROM customer_tags ct
3USING tag_registry r
4WHERE ct.tag = r.tag
5 AND ct.updated_at < CURRENT_DATE() - r.retention_days;
6
7-- 休眠客戶:超過 36 個月無互動且無有效契約關係
8UPDATE customers
9SET status = 'pending_erasure', flagged_at = CURRENT_TIMESTAMP()
10WHERE last_interaction_at < DATEADD(month, -36, CURRENT_DATE())
11 AND active_contract = FALSE
12 AND market = 'TW';

當事人行使刪除權時,記得同意事件表本身要保留(作為已履行義務的證明),但要把 subject_id 換成不可逆的 tombstone id,並清除 ip_hashevidence_uri 等可識別欄位。

步驟八:LLM 生成標籤的合規邊界在哪裡?

2026 年許多團隊開始用 LLM 從客服對話、評論、通話逐字稿自動生成顧客標籤。這在效率上很有吸引力,但風險集中在兩點:

  1. LLM 很擅長生成 L2/L3 標籤而不自知。從客服對話抽出「客戶提到懷孕」是一鍵的事,而這就是健康推論。
  2. 把原始對話送到境外模型 API,本身就是一次國際傳輸

實務做法是在 prompt 層與輸出層都設限,並且只允許模型從封閉清單中挑選:

1ALLOWED_TAGS = load_registry(tier_in=["L1", "L2"], market="TW",
2 exclude_flags=["health_inference", "religion_inference"])
3
4response = client.chat.completions.create(
5 model="gpt-4.1-mini",
6 messages=[{
7 "role": "system",
8 "content": (
9 "你只能從下列封閉清單中選擇標籤,不得自行創造。"
10 "若對話涉及健康、醫療、宗教、政治或性生活,回傳 {\"tags\": [], \"blocked\": true}。\n"
11 f"允許清單:{json.dumps(ALLOWED_TAGS, ensure_ascii=False)}"
12 )
13 }, {"role": "user", "content": redact_pii(transcript)}],
14 response_format={"type": "json_schema", "json_schema": TAG_SCHEMA}
15)
16
17# 輸出後再過一次白名單,不信任模型自律
18tags = [t for t in json.loads(response.choices[0].message.content)["tags"]
19 if t in ALLOWED_TAGS]

redact_pii() 應在送出前移除姓名、電話、地址、身分證字號、信用卡號。若合規要求資料不得出境,改用可在本地或區域內部署的模型;主要雲端供應商在台灣、新加坡、東京都有可選區域。

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. 生產環境中有多少標籤不在 registry 裡?目標為零。
  2. 隨機抽 10 個已寄送對象,能否在 60 秒內調出同意時間、來源與告知版本?
  3. 從按下退訂到所有 destination 生效,實測延遲是多久?
  4. 過去 90 天有無 L3 樣態的欄位進入 CRM?
  5. 哪些標籤已超過保存期限但仍存在?

疑難排解

症狀:退訂後仍收到 EDM。 多半是 ESP(如 SendGrid、Braze)本地維護了一份 suppression list,而 CDP 的撤回事件沒有推到那一層。檢查 destination 的 sync 模式是否為「僅新增不刪除」。

症狀:同一個人有多筆互相矛盾的同意狀態。 通常是身分解析(identity resolution)把兩個帳號合併時,同意欄位用了「取最寬鬆值」的合併規則。正確做法是取最保守值,並保留兩筆原始事件。

症狀:dbt 測試在 staging 過、在 production 失敗。 檢查 tag_registry 是否也同步部署——registry 若只存在於 repo 而未載入倉儲,production 的 JOIN 會靜默漏掉整個過濾條件。建議把 registry 載入設為 dbt seed,納入同一次部署。

症狀:法遵要求提供某位當事人的完整資料副本(個資法第 3 條查詢與複製權),但資料散在 5 個系統。 建一個以 subject_id 為 key 的 subject access request 端點,聚合各系統輸出成單一 JSON,並記錄每次請求。

落地順序建議

如果你從零開始,不要一次做完。實務上比較穩的順序是:

  1. 先建 consent_events 表與 registry,即使一開始只有 20 個標籤。
  2. 把最大的一條行銷路徑(通常是 email)改走同意閘門 view。
  3. 統一 opt-out 端點,涵蓋所有通路。
  4. 加 CI 檢查與 dbt 測試,防止回歸。
  5. 最後才處理跨境架構與 LLM 標籤。

合規設計的價值不只在避免裁罰。當同意狀態、特定目的、保存期限都是結構化欄位時,分眾本身也會變乾淨——你會很清楚哪些人可以溝通、用什麼通路、講什麼主題。


Branch8 在香港設有總部,並於台北、新加坡、吉隆坡、胡志明市與雪梨設有交付團隊,協助跨國品牌在多個亞太法域同時落地 CRM 與 CDP 架構。若你正在整併台灣、香港、東南亞的顧客資料,或需要把既有的 Salesforce / Segment / HubSpot 設定調整成可稽核的同意模型,歡迎與我們的團隊聊聊你的架構現況。

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.

Sources

FAQ

不是。台灣的法規是《個人資料保護法》,英文通常譯為 Personal Data Protection Act(PDPA);PIPA 是韓國《個人情報保護法》的英文縮寫。兩者在行銷同意上差異明顯:韓國原則上要求獨立明示的 opt-in 同意,台灣則依個資法第 20 條要求首次行銷利用時提供免費的拒絕方式。

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.