웹 (이벤트 페이지)
에어브릿지
앱스토어
앱 → Braze SDK
Braze 인앱 메시지
OS
구글시트 (앱스크립트)
# 🌐 웹 ✖ 에어브릿지 📦 스토어 📱 앱 → Braze SDK 🔔 Braze 인앱 📲 OS 📊 구글시트
PHASE 0 — 웹 · 앱 설치 판단
0
CTA 클릭
이벤트 페이지에서 앱 설치 여부 확인
미설치 → 앱 설치 모달 + 스토어 CTA
설치됨 → 딥링크 직접 진입
Deferred Deep Link
파라미터 저장
설치 완료 시 딥링크 자동 실행
PHASE 1 — 딥링크 수신 · SDK 전달
1
에어브릿지
딥링크 파싱 → 앱 오픈
app://event/{event_id}?apply_event=true
link_type: deferred | direct
앱 → Braze SDK
① setCustomAttribute
  'push_authorization_status'
  = 'not_determined' | 'denied' | 'authorized'

② logCustomEvent
  'deeplink_open_promotion'
  {link_type, term, event_id}
① → ② 순서 보장 필수 (Canvas 트리거 전 attr 선행)
PHASE 2 — Braze Canvas 분기
2
Canvas Audience Path
트리거: deeplink_open_promotion

A. is_participated_{term}=true → 이미 참여 IAM
B. 약관 미동의 → 약관 동의 IAM
C. 약관 OK + push_authorization_status ≠ authorized → Push Primer IAM
D. 모두 OK → 참여 완료 IAM
PHASE 3A — 약관 동의 모달
3A
약관 동의 후 SDK
① setCustomAttribute
  'is_marketing_info_opted_in' = true
  'is_marketing_message_opted_in' = true
② logCustomEvent 'terms_agreed'
딥링크: app://braze/consent
약관 동의 IAM
미동의 항목만 동적 표시
brazeBridge Liquid 변수 주입
PHASE 3B — Push Primer IAM (push_authorization_status ≠ authorized)
3B‑1
Push Primer IAM
isPushOn() 함수로 상태 판단
function isPushOn() {
const b = getBridge();
const s = b.getUser()
 .getCustomAttribute(
  'push_authorization_status');
return s === 'authorized';
}
→ true: 참여 완료 처리 / → false: push 안내 분기
OS 권한 프롬프트
not_determined 유저 전용
iOS 시스템 팝업 / Android 13+ 바텀업
허용 → source: 'prompt'
거부 → source: 'prompt', denied
닫기 → 이벤트 없이 IAM_FAIL 직결
3B‑2
푸시 허용 후 SDK
① setCustomAttribute
  'push_authorization_status' = 'authorized'
② logCustomEvent 'push_permission'
  {status: 'granted',
   source: 'prompt' | 'settings',
   event_name, event_id}
PHASE 4 — 참여 완료 모달
4
참여 완료 IAM
Liquid: term, event_id 주입
setCustomUserAttribute
  'is_participated_{term}' = true
logCustomEvent
  'view_participated_promotion_modal'
  {event_name, event_id}
PHASE 5 — 구글시트 앱스크립트 · Canvas 퍼포먼스 자동 fetch
5
Braze REST API
GET /canvas/data_summary
Canvas Analytics 데이터 반환
Google Apps Script
mapping_input 시트 → Canvas_Id
BigQuery UNNEST 배치 쿼리 1회
그로스챕터용 시트 자동 기입
CRM 리포트 → 🚀 배치 실행
Status 빈 행 전체 → '완료'
🌐 웹 🔀 에어브릿지 🏪 스토어 📤 앱→Braze SDK 이벤트 📡 Braze 인앱 메시지 📝 Braze Custom HTML IAM 🎯 Braze 세그먼트 분기 🔔 OS 권한 💾 DB ✅ 완료 ❌ 미완료
PHASE 0 — 웹 · 앱 설치 판단
🌐 웹 이벤트 페이지 CTA: 앱 다운로드하고 혜택 받기
딥링크: app://event/{eventId}
?apply_event=true&term={term}
CTA 클릭
🔀 에어브릿지 라우팅
미설치
기설치
🏪 App Store서비스 앱
이탈
설치
❌ 이탈
📱 앱 첫 실행
(Deferred DL)
📱 앱 오픈
(Deep Link 콜백)
PHASE 1 — apply_event 체크 · SDK 이벤트 발송
신규 설치
apply_event == true?
true
false
📤 앱 → Braze SDK (신규) ① setCustomAttribute
  'push_authorization_status'
  = not_determined/denied/authorized
② logCustomEvent
  'deeplink_open_promotion'
  {link_type:'deferred', term, event_id}
🌐 이벤트 페이지만Braze 이벤트 미발송
|
기설치
apply_event == true?
true
false
📤 앱 → Braze SDK (기설치) ① setCustomAttribute
  'push_authorization_status'
  = not_determined/denied/authorized
② logCustomEvent
  'deeplink_open_promotion'
  {link_type:'direct', term, event_id}
🌐 이벤트 페이지만Braze 이벤트 미발송
PHASE 2 — Braze 대상자 선별 · Canvas 분기
🎯 Braze 대상자 선별 트리거: deeplink_open_promotion
WHERE term = {동적} 또는 event_id = {동적}
─────────────────
세그먼트 필터:
① is_participated_promotion_{term} attr
② 약관 동의 2개 attr (marketing_info / marketing_message)
③ push_authorization_status
④ link_type 프로퍼티
분기 A — 이미 참여
is_participated = true
📡 이미 참여 완료 IAM ✅ 이미 이벤트 참여가
완료되었습니다
Liquid: event_properties로
term/event_id 동적 처리
확인
🏠 서비스 홈
분기 B — 기설치+약관미충족
미참여+미충족+direct
📡 기설치 안내 IAM 이미 서비스 앱이 설치되어 있어요!
마케팅 앱 알림을 켜주셔야
응모가 완료돼요
응모 완료하기 →
📝 약관 동의 Custom HTML IAM 미동의 항목만 동적 노출
☐ 개인정보 마케팅 활용 동의
☐ 마케팅 알림 수신 동의
[동의하기] 클릭
📝 brazeBridge 실행 ① logCustomEvent 'click_terms_submit_button'
② setCustomUserAttribute
 is_marketing_info_opted_in=true
 is_marketing_message_opted_in=true
③ requestImmediateDataFlush()
④ goToPage('terms-notice')
[확인] → isPushOn()?
true→
📝 체스 드래그앤드롭
PAGE 3A
false→
📝 Push Primer
PAGE 3B
분기 C — 신규+약관미충족
미참여+미충족+deferred
📝 약관 동의 IAM (바로) 분기 B와 동일한 약관 동의 모달
(기설치 안내 모달 없이 직접)
→ 분기 B와 동일 처리
↑ B와 동일한 flow
분기 D — 모두동의+Push OK
미참여+약관충족+authorized
📡 이벤트 참여 완료 IAM 🎉 이벤트 참여 완료!
setCustomUserAttribute
'is_participated_'+term = true
logCustomEvent
'view_participated_promotion_modal'
확인
🏠 서비스 홈
✅ 이벤트 완료
분기 E — 모두동의+Push 미허용
E-1 not_determined
📡 Push Primer IAM 🔔 기기 알림을 켜주셔야
이벤트 참여가 완료돼요!
버튼: [알림 허용하기]
source: 'prompt'
허용
📤 SDKstatus:authorized
push_permission
{granted,prompt}
→ 참여완료 IAM
거부
📤 SDKstatus:denied
push_permission
{denied,prompt}
→ IAM_FAIL
닫기
📤 SDKattr 업데이트 없음
push_permission
{status:'',source:''}
→ IAM_FAIL
E-2 denied
📡 Push Primer IAM 🔔 설정에서 알림을 켜주셔야
이벤트 참여가 완료돼요!
버튼: [설정에서 켜기]
source: 'settings'
⚙️ 기기 설정 앱
서비스 > 알림
허용후복귀
📤authorized
push_permission
{granted,settings}
↓ 참여완료IAM
거부유지
📤attr없음
push_permission
{denied,settings}
↓ IAM_FAIL
닫기
📤 SDKattr없음
{status:'',source:''}
IAM_FAIL
CASE FAIL — 이벤트 참여 불가
📡 IAM_FAIL — 이벤트 참여 불가 안내 트리거: push_permission WHERE status ≠ granted (denied 또는 빈값)
알림을 켠 후 다시 시도해 주세요 → closeModal()
📌 별도 속성 업데이트 없음
확인
🏠 서비스 홈
❌ 이벤트 미완료
PHASE 3 — 체스 드롭 · 경품 추첨 · 종료
📝 PAGE 3A: 체스 드래그앤드롭 나이트를 체스판으로 드래그
드롭 성공 → 경품 추첨 즉시 실행
드롭 성공 (onDropSuccess)
📝 경품 추첨 + 동시 처리 ① 랜덤 추첨 (prize_tier: top/mid/base)
② claimPrize() → GAS POST (no-cors)
③ setCustomUserAttribute
 'is_participated_'+promoTerm = true
 'promotion_prize_'+promoTerm = prize
 'promotion_prize_tier_'+promoTerm = tier
④ logCustomEvent 'view_participated_promotion_modal'
GAS doPost
💾 Google Apps Script 시트 재고 차감
prize 컬럼 -1
braze_id 로그 기록
경품 종류 판단
경품 결과 분기
gasKey 기준
macbook/ps5/dinner
📝 top3 당첨 맥북/PS5/파인다이닝
구글폼 직접 랜딩
(제세공과금 입력)
gas/dept/conv/coupon
📝 confirm 모달 당첨을 축하드려요!
경품 아이콘+상세
이벤트 종료 후 4/6 지급
handleFinalClose()
📝 handleFinalClose() 동의 파라미터 있을 경우:
app://braze/consent
?allow_use_marketing=1
&allow_news_letters=1
→ 300ms 후 brazeBridge.closeMessage()
완료
🏠 서비스 홈
✅ 이벤트 완료
📝 PAGE 3B: Push Primer 알림이 꺼져 있어요
CTA: 알림 키고 나이트 소환하기
app://braze/open-notification-settings
?action=open_settings&term={promoTerm}
닫기: ?action=close
설정 후 앱 재진입
→ 새 IAM으로 재분기
→ PAGE 3A로 이동
Custom Events
deeplink_open_promotion 앱 SDK Canvas 트리거 이벤트 — 딥링크 수신 직후 발송
PropertyType설명
link_typeStringdeferred / direct신규 설치(deferred) / 기설치 유저(direct)
termStringappinstall_2603프로모션 식별자 (Canvas Audience Path 분기에 사용)
event_idString예: {event_id}이벤트 고유 ID
⚠️ 순서 보장 필수: setCustomAttribute('push_authorization_status', ...) 설정 후 이 이벤트를 발송해야 Canvas Audience Path에서 attribute 값을 정확히 읽을 수 있음
terms_agreed 앱 SDK 약관 동의 완료 후 발송
PropertyType설명
termStringappinstall_2603프로모션 식별자
event_idString예: {event_id}이벤트 고유 ID
딥링크 app://braze/consent 호출로 앱에 동의 완료 신호 전달. 동시에 is_marketing_info_opted_in, is_marketing_message_opted_in attribute 세팅
push_permission 앱 SDK OS 권한 요청 결과 또는 설정 앱 복귀 후 발송
PropertyType설명
statusStringgranted / denied허용 / 거부
sourceStringprompt / settingsOS 프롬프트에서 결정 / 설정 앱에서 변경 후 복귀
event_nameStringappinstall_2603프로모션 식별자
event_idString예: {event_id}이벤트 고유 ID
⚠️ 닫기 시 미발송: Push Primer에서 닫기 클릭 시 이 이벤트를 발송하지 않음. Braze IAM dismiss 자동 트래킹으로 대체. push_authorization_status attribute도 업데이트 안 함.
view_participated_promotion_modal brazeBridge 참여 완료 IAM 조회 시 Custom HTML IAM 내부에서 발송
PropertyType설명
event_nameStringappinstall_2603Liquid로 주입: {{canvas_entry_properties.${term}}}
event_idString예: {event_id}Liquid로 주입: {{canvas_entry_properties.${event_id}}}
이 이벤트 발송과 동시에 setCustomUserAttribute('is_participated_{term}', true) 실행. 이후 재진입 시 "이미 참여 완료" 분기로 라우팅됨.
Custom Attributes
Attribute KeyType세팅 주체세팅 시점
push_authorization_status String not_determined / denied / authorized 앱 SDK 딥링크 수신 직후 (deeplink_open_promotion 발송 전)
is_participated_{term} Boolean true brazeBridge 참여 완료 IAM 조회 시 (impression)
is_marketing_info_opted_in Boolean true 앱 SDK 약관 동의 완료 후
is_marketing_message_opted_in Boolean true 앱 SDK 약관 동의 완료 후
Canvas 세그먼트 분기 조건
분기세그먼트 조건노출 IAM
A — 이미 참여 is_participated_{term} = true 이미 참여 완료 안내 IAM
B — 약관 미동의 is_participated_{term} ≠ true
+ is_marketing_info_opted_in ≠ true OR is_marketing_message_opted_in ≠ true
약관 동의 IAM (미동의 항목 동적 표시)
C — Push 미허용 is_participated_{term} ≠ true
+ 약관 2개 모두 true
+ push_authorization_status ≠ authorized
Push Primer IAM
D — 모두 OK is_participated_{term} ≠ true
+ 약관 2개 모두 true
+ push_authorization_status = authorized
참여 완료 IAM
UI 유형 구분
UI유형트리거
📝 약관 동의 모달Braze Custom HTML IAMCanvas 분기 B
🔔 Push Primer IAMBraze Custom HTML IAMCanvas 분기 C — isPushOn() 내부 분기
🎉 참여 완료Braze Custom HTML IAMCanvas 분기 D (또는 C → 허용 후)
✅ 이미 참여 완료Braze Custom HTML IAMCanvas 분기 A
🔕 미완료 안내 (IAM_FAIL)Braze Custom HTML IAMPush Primer 닫기 → dismiss
isPushOn() 함수 스펙

Custom HTML IAM 내부 JS — push_authorization_status attribute를 읽어 분기 판단

// Push Primer IAM 내부
function isPushOn() {
  const b = getBridge();  // brazeBridge 또는 appboyBridge
  const s = b.getUser()
    .getCustomAttribute('push_authorization_status');
  return s === 'authorized';
}

// 약관 동의 완료 후 분기 (handleAfterTerms)
function handleAfterTerms() {
  if (isPushOn()) {
    goToPage('participation-complete'); // 참여 완료 바로 이동
  } else {
    goToPage('push-guide');           // Push Primer 표시
  }
}
구글시트 앱스크립트 연동

mapping_input 시트 구조

항목설명
APromotion_Name프로모션명
BYear_Month연월 (예: 2603)
CUser_Type유저 타입
DCanvas_IdBraze Canvas ID
EPrimary_Conv주요 전환 이벤트명
FSecondary_Conv보조 전환 (쉼표 구분)
GEvent_TitleBigQuery 이벤트명
HLanding_URL랜딩 URL
IStatus완료 / 오류 자동 기입

실행 방법 및 결과

실행상단 메뉴 CRM 리포트 → 🚀 배치 실행
Status 빈 행 전체를 1회 쿼리로 처리
쿼리 방식BigQuery UNNEST 배치 쿼리
Canvas step별 지표 추출
결과 시트그로스챕터용
채널별 Recipient / Impression / Click / Conversion / CTR / CVR 자동 기입
완료 표시Status 열 → '완료' 자동 기입