앱 다운로드 프로모션 유저 플로우차트

🌐 웹 🔀 에어브릿지 🏪 스토어 📤 앱→Braze SDK 이벤트 📡 Braze 인앱 메시지 📝 Braze Custom HTML IAM 🎯 Braze 세그먼트 분기 🔔 OS 권한 💾 DB ✅ 완료 ❌ 미완료
CTA 클릭
미설치
기설치
이탈
설치
true
false
true
false
is_participated_promotion
_{term} = true
(term 또는 event_id로 판별)
확인
is_participated_promotion
_{term} ≠ true
+ 2개 attr 중 미충족
+ link_type = direct
(term 또는 event_id로 판별)
응모 완료하기
is_participated_promotion
_{term} ≠ true
+ 2개 attr 중 미충족
+ link_type = deferred
(term 또는 event_id로 판별)
is_participated_promotion
_{term} ≠ true
+ 2개 attr 모두 충족
+ push_authorization_status
= authorized
(term 또는 event_id로 판별)
확인
is_participated_promotion
_{term} ≠ true
+ 2개 attr 모두 충족
+ push_authorization_status
= not_determined
(term 또는 event_id로 판별)
is_participated_promotion
_{term} ≠ true
+ 2개 attr 모두 충족
+ push_authorization_status
= denied
(term 또는 event_id로 판별)
OS 권한 프롬프트
→ 허용
OS 권한 프롬프트
→ 거부
닫기
설정에서 켜기
닫기
허용 후 앱 복귀
거부 유지
확인
[동의하기] 클릭
(is_all_checked = true)
[확인] 클릭
(동의 고지 페이지)
isPushOn() = true
isPushOn() = false
설정 후 앱 재진입
→ 새 IAM으로 재분기
드롭 성공 (onDropSuccess)
GAS doPost 호출
경품 종류 판단
macbook / ps5 / dinner
(top3)
gas / dept / conv
coupon_50000~1000
closeModal()
handleFinalClose()
완료
🌐 웹 이벤트 페이지
CTA: 앱 다운로드하고 혜택 받기
딥링크: app://event/{eventId}
?apply_event=true&term={term}
🔀 에어브릿지 라우팅
🏪 App Store
서비스 앱
📱 앱 오픈
(Deep Link 콜백)
❌ 이탈
플로우 종료
📱 앱 첫 실행
(Deferred Deep Link 콜백)
apply_event
== true?
📤 앱 → Braze SDK
const term = getQueryParam('term')
const eventId = getPathParam('eventId')
─────────────────
① setCustomAttribute
('push_authorization_status',
'not_determined'/'denied'/'authorized')
② logCustomEvent
('deeplink_open_promotion',
{link_type: 'deferred',
term: term,
event_id: eventId})
🌐 이벤트 페이지만 표시
(Braze 이벤트 미발송)
apply_event
== true?
📤 앱 → Braze SDK
const term = getQueryParam('term')
const eventId = getPathParam('eventId')
─────────────────
① setCustomAttribute
('push_authorization_status',
'not_determined'/'denied'/'authorized')
② logCustomEvent
('deeplink_open_promotion',
{link_type: 'direct',
term: term,
event_id: eventId})
🎯 Braze 대상자 선별
트리거: deeplink_open_promotion
WHERE term = {동적}
또는 event_id = {동적}
─────────────────
세그먼트 필터:
① is_participated attr
② 약관 동의 2개 attr
③ push_authorization_status
④ link_type 프로퍼티
📡 Braze 인앱 메시지
세그먼트: is_participated_promotion
_{term} = true
─────────────────
📌 모달 내 Liquid 동적 처리:
const promoTerm = '{{event_properties
.${term}}}'
const eventId = '{{event_properties
.${event_id}}}'
─────────────────
✅ 이미 이벤트 참여가 완료되었습니다
🏠 서비스 홈
📡 Braze 인앱 메시지
세그먼트:
is_participated_promotion
_{term} ≠ true
+ 2개 attr 중 하나라도 미충족
+ link_type = direct
─────────────────
📌 모달 내 Liquid 동적 처리:
const promoTerm = '{{event_properties
.${term}}}'
const eventId = '{{event_properties
.${event_id}}}'
─────────────────
이미 서비스 앱이 설치되어 있어요!
마케팅 앱 알림을 켜주셔야
응모가 완료돼요
─────────────────
📌 모달 조회 시:
logCustomEvent('view_has_app_modal',
{event_term: promoTerm,
event_id: eventId})
📝 Braze Custom HTML IAM
약관 동의 모달
(미동의 항목만 동적 노출)
☐ 개인정보 마케팅 활용 동의
☐ 마케팅 알림 수신 동의
─────────────────
📌 모달 내 Liquid 동적 처리:
const promoTerm = '{{event_properties
.${term}}}'
const eventId = '{{event_properties
.${event_id}}}'
─────────────────
📌 모달 조회 시:
logCustomEvent('view_terms_consent_modal',
{displayed_items: ['marketing_info',
'marketing_message'],
event_term: promoTerm,
event_id: eventId})
📡 Braze 인앱 메시지
🎉 이벤트 참여 완료!
─────────────────
📌 모달 내 Liquid 동적 처리:
const promoTerm = '{{event_properties
.${term}}}'
const eventId = '{{event_properties
.${event_id}}}'
setCustomUserAttribute(
'is_participated_promotion_'
+ promoTerm, true)
logCustomEvent('view_participated
_promotion_modal',
{event_term: promoTerm,
event_id: eventId})
🏠 서비스 홈
✅ 이벤트 완료
📡 Braze Push Primer IAM
세그먼트:
push_authorization_status
= not_determined
─────────────────
📌 iOS/Android 공통:
not_determined → 앱 내 프롬프트
(iOS: OS 프롬프트,
Android 13+: 바텀업 프롬프트)
─────────────────
🔔 기기 알림을 켜주셔야
이벤트 참여가 완료돼요!
버튼: [알림 허용하기]
on-click: app://braze/
open-notification-settings
?action=open_settings
─────────────────
📌 source 판단 기준:
not_determined → source: 'prompt'
📌 닫기: app://braze/
open-notification-settings
?action=close
📡 Braze Push Primer IAM
세그먼트:
push_authorization_status
= denied
─────────────────
📌 iOS/Android 공통:
denied → 기기 설정 앱으로 이동
─────────────────
🔔 설정에서 알림을 켜주셔야
이벤트 참여가 완료돼요!
버튼: [설정에서 켜기]
on-click: app://braze/
open-notification-settings
?action=open_settings
─────────────────
📌 source 판단 기준:
denied → source: 'settings'
📌 닫기: app://braze/
open-notification-settings
?action=close
📤 앱 → Braze SDK
① setCustomAttribute
('push_authorization_status',
'authorized')
② logCustomEvent
('push_permission',
{status: 'granted',
event_term:
promoTerm,
event_id: eventId,
source: 'prompt'})
📤 앱 → Braze SDK
① setCustomAttribute
('push_authorization_status',
'denied')
② logCustomEvent
('push_permission',
{status: 'denied',
event_term:
promoTerm,
event_id: eventId,
source: 'prompt'})
📤 앱 → Braze SDK
attr 업데이트 없음
(진입 시 값 유지)
② logCustomEvent
('push_permission',
{status: '',
source: '',
event_term:
promoTerm,
event_id: eventId})
📡 Braze 인앱 메시지
이벤트 참여 불가 안내
트리거: push_permission
WHERE status ≠ granted
(denied 또는 빈값)
─────────────────
알림을 켠 후 다시 시도해 주세요
확인 → closeModal()
📌 별도 속성 업데이트 없음
⚙️ 기기 설정 앱
(iOS/Android 공통)
서비스 > 알림
📤 앱 → Braze SDK
① setCustomAttribute
('push_authorization_status',
'authorized')
② logCustomEvent
('push_permission',
{status: 'granted',
source: 'settings',
event_term:
promoTerm,
event_id: eventId})
📤 앱 → Braze SDK
attr 업데이트 없음
(진입 시 값 유지)
② logCustomEvent
('push_permission',
{status: 'denied',
source: 'settings',
event_term:
promoTerm,
event_id: eventId})
🏠 서비스 홈
❌ 이벤트 미완료
📝 brazeBridge 실행:
① logCustomEvent('click_terms_submit_button',
{is_all_checked: true,
checked_items: ['marketing_info',
'marketing_message'],
event_term: promoTerm,
event_id: eventId})
② setCustomUserAttribute
· is_marketing_info_opted_in = true
· is_marketing_message_opted_in = true
③ requestImmediateDataFlush()
④ goToPage('terms-notice') → 동의 고지 표시
📝 handleConsentConfirm()
logCustomEvent('click_consent_confirm',
{event_term: promoTerm, event_id: eventId})
─────────────────
📌 IAM 내 isPushOn() 실행
1순위: foreground_push_enabled = true → ON
2순위: foreground_push_enabled = false/blank
→ push_authorization_status = authorized 체크
fallback: brazeBridge.isPushPermissionGranted()
(미지원 시 Liquid 값 사용)
📝 Braze Custom HTML IAM
PAGE 3A: 체스 드래그앤드롭
나이트를 체스판으로 드래그
─────────────────
드롭 성공 → 경품 추첨 즉시 실행
📝 Braze Custom HTML IAM
PAGE 3B: 푸시 프라이머
알림이 꺼져 있어요 (체인 나이트)
─────────────────
CTA: 알림 키고 나이트 소환하기
→ app://braze/open-notification-settings
?action=open_settings&term={promoTerm}
&allow_use_marketing=1&allow_news_letters=1
닫기: ?action=close&term={promoTerm}
&allow_use_marketing=1&allow_news_letters=1
📝 경품 추첨 + 동시 처리
① 랜덤 추첨
prize_tier: top/mid/base
② claimPrize() → GAS POST
action=claim, prize=gasKey, braze_id
mode: no-cors (fire-and-forget)
③ logParticipation()
setCustomUserAttribute(
'is_participated_promotion_'+promoTerm, true)
setCustomUserAttribute(
'promotion_prize_'+promoTerm, prize.detail)
setCustomUserAttribute(
'promotion_prize_tier_'+promoTerm, prizeTier)
logCustomEvent('view_participated_promotion_modal',
{prize_name, prize_detail, prize_tier, coupon_amount})
💾 Google Apps Script
시트 재고 차감
prize 컬럼 -1
braze_id 로그 기록
경품 결과 분기
gasKey 기준
📝 PAGE: top3 당첨
맥북 / PS5 / 파인다이닝
─────────────────
상세 내용 확인하기
→ 제세공과금 구글폼 직접 랜딩
macbook: forms.gle/n5BmN1gp54auMWun6
ps5: forms.gle/zz1BTMGp5QnGrGZLA
dinner: forms.gle/HMvjR5ZuEhJ2ZBEB9
→ closeModal()
📝 PAGE: confirm
당첨을 축하드려요!
경품 아이콘 + 상세 텍스트
이벤트 종료 후 4/6 일괄 지급
─────────────────
확인 → handleFinalClose()
📝 handleFinalClose()
동의 파라미터 있을 경우:
app://braze/consent
?allow_use_marketing=1
&allow_news_letters=1
→ 300ms 후 brazeBridge.closeMessage()

🔄 동적 프로모션 처리 메커니즘

프로모션 term 값을 2단계에 걸쳐 동적으로 전달합니다. IAM에서 event_properties로 직접 참조하므로 중간 attribute 저장이 불필요합니다. 새 프로모션 추가 시 앱 코드 변경 없이 딥링크 URL과 Canvas 설정만 변경하면 됩니다.

#단계처리 내용코드/설정
앱 → Braze 딥링크의 term 파라미터를 동적 파싱하여 이벤트 프로퍼티로 전송 braze.logCustomEvent('deeplink_open_promotion', { term: getQueryParam('term') })
IAM ← Canvas Entry IAM HTML에서 event_properties로 트리거 이벤트 프로퍼티 직접 참조
User Update 스텝 불필요, 중간 attribute 불필요
var promoTerm = "{{event_properties.${term}}}";
var eventId = "{{event_properties.${event_id}}}";
setCustomUserAttribute('is_participated_promotion_' + promoTerm, true)
📌 새 프로모션 추가 시 변경 사항:
① 웹 이벤트 페이지: 딥링크 URL의 term 파라미터 변경 → 앱 배포 불필요
② Braze Canvas: 기존 Canvas 복제 → Entry 필터 term 값 + Decision Split 1의 attribute 이름 변경
③ IAM HTML 코드: 변경 불필요 (Liquid로 동적 처리)
④ 앱 코드: 변경 불필요 (딥링크 파라미터 동적 파싱)

🔗 딥링크 구조

딥링크 URL 포맷
app://event/{eventId}?apply_event=true&term={term}
파라미터설명
eventId (URL path)이벤트 페이지 식별 ID
term (query string)프로모션 식별자. 이벤트 프로퍼티 + attribute 키 생성에 사용
apply_event (query string)true일 때만 Braze 이벤트 발송. false이면 페이지만 표시
📌 consent deeplink 처리 방식 변경
app://braze/consent 단독 호출 폐기 → handleFinalClose()에서 300ms 후 brazeBridge.closeMessage() 호출로 통합
Android WebView에서 딥링크 2회 연속 호출 시 두 번째 미실행 이슈 대응
약관 동의 후 푸시 프라이머 경로: consent 파라미터를 open-notification-settings 딥링크에 통합하여 1회만 호출

📋 "모두 동의" 조건 정의

Braze 세그먼트 분기에서 "모두 동의"로 판정하려면 아래 2개 attribute가 모두 충족되어야 합니다.

#Attribute타입동의 값Braze 세그먼트 필터
is_marketing_info_opted_in Custom Attr (Boolean) true Custom Attribute → is_marketing_info_opted_in = true
is_marketing_message_opted_in Custom Attr (Boolean) true Custom Attribute → is_marketing_message_opted_in = true
⚠️ "약관 미충족" = 위 2개 조건 중 하나라도 미충족 → 약관 동의 모달 노출 필요
📌 Braze 세그먼트 구성: 2개 조건을 AND로 결합. 미충족 세그먼트는 "NOT (① AND ②)" 사용
📌 참고: email_subscribe, push_subscribe는 Braze Canvas HTML에서 Liquid로 불러올 수 없으므로 제외

📤 deeplink_open_promotion SDK

앱이 발송하는 진입 이벤트 (apply_event=true일 때만)
순서항목설명
setCustomAttribute('push_authorization_status', ...)OS 푸시 권한 상태: not_determined / denied / authorized
logCustomEvent('deeplink_open_promotion', {...})딥링크 진입 이벤트
deeplink_open_promotion 프로퍼티
PropertyType설명
link_typeStringdeferred = 신규 설치 | direct = 기설치
termString프로모션 식별자 — 딥링크에서 동적 추출 (예: appinstall_2603)
event_idString이벤트 페이지 ID — 딥링크 path에서 동적 추출
// 앱 딥링크 콜백 (Swift 예시)
func handleDeepLink(url: URL, isDeferred: Bool) {
  let params = parseParams(url)
  let eventId = getPathParam(url, "eventId")
  let apply_event = params["apply_event"]
  let term = params["term"]

  // apply_event가 true일 때만 Braze 이벤트 발송
  guard apply_event == "true" else { return }

  // ① 푸시 권한 상태 확인 후 attribute 설정
  UNUserNotificationCenter.current().getNotificationSettings { settings in
    let status: String
    switch settings.authorizationStatus {
    case .notDetermined: status = "not_determined"
    case .denied: status = "denied"
    case .authorized, .provisional: status = "authorized"
    default: status = "unknown"
    }
    Braze.setCustomAttribute("push_authorization_status", status)

    // ② 딥링크 이벤트 발송 (term, event_id 동적)
    Braze.logCustomEvent("deeplink_open_promotion", properties: [
      "link_type": isDeferred ? "deferred" : "direct",
      "term": term,
      "event_id": eventId
    ])
  }
}

🎯 Braze 대상자 선별 조건 Braze

공통 트리거: deeplink_open_promotion WHERE term={동적} 또는 event_id={동적}
IAM에서 event_properties로 직접 참조 (User Update 불필요)
분기세그먼트 필터 조건결과 IAM
A. 이미 참여 is_participated_promotion_{term} = true ✅ "이미 참여 완료"
B. 기설치 + 미충족 is_participated… ≠ true
+ 약관 2개 중 하나라도 미충족
+ link_type = direct
👋 기설치 안내 모달
C. 신규 + 미충족 is_participated… ≠ true
+ 약관 2개 중 하나라도 미충족
+ link_type = deferred
📝 약관 동의 모달 (바로)
D. 모두 동의 + 푸시 OK is_participated… ≠ true
+ 약관 2개 모두 충족
+ foreground_push_enabled = true
또는 push_authorization_status = authorized
📝 약관 동의 IAM → 동의 고지 → 체스 드롭 (IAM 내 isPushOn()=true)
E. 모두 동의 + 푸시 미허용 is_participated… ≠ true
+ 약관 2개 모두 충족
+ foreground_push_enabled ≠ true
+ push_authorization_status ≠ authorized
📝 약관 동의 IAM → 동의 고지 → 푸시 프라이머 (IAM 내 isPushOn()=false)
📌 Canvas 레벨 E-1/E-2 분기 폐기 → IAM 내부에서 통합 처리
💡 트리거 필터: Canvas Entry에서 term 또는 event_id로 프로모션별 필터링 가능
💡 "약관 2개 모두 충족" = is_marketing_info_opted_in=true AND is_marketing_message_opted_in=true

📤 기타 Custom Event

SDK Event: push_permission
PropertyType설명
statusStringgranted = 허용 | denied = 거부/닫기
event_termString프로모션 식별자 (예: promotion_appinstall_2603)
sourceString권한 허용 출처: prompt / settings (선택)
OS 푸시 권한 결과에 따라 앱에서 즉시 발송
status=granted: 참여 완료 IAM 트리거
status=denied: 실패 IAM 트리거
Braze IAM Event: view_participated_promotion_modal
PropertyType설명
event_termString프로모션 식별자 (예: promotion_appinstall_2603)
참여 완료 모달 조회 시 brazeBridge.logCustomEvent()로 발송
Braze IAM Event: view_has_app_modal
PropertyType설명
event_termString프로모션 식별자 (예: promotion_appinstall_2603)
기설치 안내 모달 조회 시 brazeBridge.logCustomEvent()로 발송
Braze IAM Event: view_terms_consent_modal
PropertyType설명
displayed_itemsArray노출된 동의 항목 목록 (예: ['marketing_info', 'marketing_message'])
약관 동의 모달 조회 시 brazeBridge.logCustomEvent()로 발송
Braze IAM Event: click_terms_submit_button
PropertyType설명
is_all_checkedBoolean모든 체크박스 선택 여부 (true = 활성화된 버튼 클릭)
checked_itemsArray선택된 항목 목록 (예: ['marketing_info', 'marketing_message'])
event_termString프로모션 식별자 (예: promotion_appinstall_2603)
약관 동의 버튼 클릭 시 brazeBridge.logCustomEvent()로 발송

📡 인앱 메시지 트리거 조건 Braze

인앱 메시지타입트리거 + 세그먼트
✅ 이미 참여 완료 Custom HTML deeplink_open_promotion
WHERE term={term} / event_id={event_id}
+ is_participated_promotion_{term} = true
👋 기설치 안내 Custom HTML deeplink_open_promotion
WHERE term={term} / event_id={event_id}
+ 미참여 + 약관 미충족 + link_type=direct
📝 약관 동의 모달 Custom HTML deeplink_open_promotion
WHERE term={term} / event_id={event_id}
+ 미참여 + 약관 미충족 + link_type=deferred
또는 기설치 안내 모달에서 이동
🎉 참여 완료 📌 Custom HTML deeplink_open_promotion 또는 push_permission WHERE status=granted
세그먼트: 2개 attr 충족 + push_authorization_status = authorized
📌 모달 조회 시 is_participated_promotion_{term} = true
🔔 Push Primer (not_determined) 📌 Custom HTML 세그먼트: 2개 attr 충족 + push_authorization_status = not_determined
버튼: [알림 허용하기] → Request Push Permission
🔔 Push Primer (denied) 📌 Custom HTML 세그먼트: 2개 attr 충족 + push_authorization_status = denied
버튼: [설정에서 켜기] → 설정 앱 딥링크
🔕 비활성화 안내 Custom HTML push_permission WHERE status=denied

📝 약관 동의 Custom HTML IAM 상세 스펙 Custom HTML

항목내용
메시지 타입Custom Code (HTML Upload)
트리거 이벤트deeplink_open_promotion (신규 미동의)
또는 기설치 안내 모달에서 이동 (기설치 경유)
brazeBridge 메서드 getUser().setCustomUserAttribute(), getUser().setEmailNotificationSubscriptionType(), getUser().setPushNotificationSubscriptionType(), logCustomEvent(), requestImmediateDataFlush(), closeMessage()
약관 동의 처리brazeBridge로 Braze 즉시 반영 + open-notification-settings 딥링크에 consent 파라미터 통합
app://braze/open-notification-settings?action=open_settings&term={term}&consent=allow_use_marketing%3D1%26allow_news_letters%3D1
📌 안드로이드 WebView에서 딥링크 2회 호출 시 두 번째가 실행되지 않는 이슈로 1회 통합

📐 [응모 완료하기] 버튼 클릭 시 실행 시퀀스

1
유효성 검증 — 2개 체크박스 모두 체크 확인 (is_all_checked = true)
2
버튼 클릭 이벤트 발송
logCustomEvent('click_terms_submit_button', {is_all_checked: true, checked_items: ['marketing_info', 'marketing_message'], event_term: promoTerm, event_id: eventId})
3
Braze attribute 업데이트 (brazeBridge)
setCustomUserAttribute('is_marketing_info_opted_in', true)
setCustomUserAttribute('is_marketing_message_opted_in', true)
4
전송requestImmediateDataFlush()
5
동의 고지 페이지(terms-notice) 표시 → 동의 일시, 동의 항목 안내
6
[확인] 클릭 → handleConsentConfirm() → isPushOn() 실행
1순위: foreground_push_enabled = true → 3A(체스 드롭)으로 이동
2순위: foreground_push_enabled = false/blankpush_authorization_status = authorized 체크
fallback: brazeBridge.isPushPermissionGranted() (미지원 시 Liquid 값 사용)
isPushOn() = false → 3B(푸시 프라이머)로 이동
// PAGE 1: 약관 동의 제출
function handleTermsSubmit() {
  const user = brazeBridge.getUser();

  // ① Braze attribute 즉시 반영
  user.setCustomUserAttribute("is_marketing_info_opted_in", true);
  user.setCustomUserAttribute("is_marketing_message_opted_in", true);

  // ② 동의 완료 이벤트 + flush
  brazeBridge.logCustomEvent("click_terms_submit_button", { ... });
  brazeBridge.requestImmediateDataFlush();

  // ③ 동의 고지 페이지로 이동
  goToPage('terms-notice');
}

// PAGE 2: 동의 고지 확인 → 푸시 분기
function handleConsentConfirm() {
  // brazeBridge 실시간 값 우선, 없으면 Liquid fallback
  var b = getBridge();
  if(b && typeof b.isPushPermissionGranted === 'function') {
    isPushPermissionGranted() ? goToPage('chess-drop') : goToPage('push-primer');
  } else {
    isPushOn() ? goToPage('chess-drop') : goToPage('push-primer');
  }
}

// PAGE 3B: 푸시 프라이머 → 설정 이동 (consent 파라미터 통합)
function handleOpenSettings() {
  var url = 'app://braze/open-notification-settings?action=open_settings&term=' + promoTerm;
  var consentStr = buildConsentParams().join('&');
  if(consentStr) url += '&' + consentStr;
  window.location = url;
  // 📌 Android WebView 딥링크 2회 호출 이슈로 consent를 별도 호출 없이 통합
}

🎉 참여 완료 모달 — 경품 추첨 & attribute 생성 시점

항목내용
트리거체스 드롭 성공 (onDropSuccess) 즉시 실행
경품 추첨prize_tier_appinstall_2603 (top/mid/base) 기반 랜덤 추첨
재고 확인 후 claimPrize() → GAS POST (no-cors, fire-and-forget)
결과 분기top3 (macbook/ps5/dinner) → 구글폼 랜딩 (제세공과금 입력)
일반 경품 (gas/dept/conv/coupon_*) → confirm 모달 → handleFinalClose()
설정할 attribute is_participated_promotion_{term} = true
promotion_prize_{term} = 경품명 (예: "서비스 쿠폰 10,000원")
promotion_prize_tier_{term} = top / mid / base
promotion_coupon_amount_{term} = 쿠폰 금액 (쿠폰 당첨 시만)
이벤트view_participated_promotion_modal
프로퍼티: prize_name, prize_detail, prize_tier, coupon_amount
// 참여 완료 IAM 내 — 모달이 표시될 때 즉시 실행
appboyBridge.getUser().setCustomUserAttribute(
  "is_participated_promotion_{term}", true
);
appboyBridge.requestImmediateDataFlush();

🔑 Braze Custom Attribute

Attribute타입설정 주체
push_authorization_status String 앱 SDK 딥링크 진입 시
값: not_determined / denied / authorized
📌 iOS/Android 13+ 공통: not_determined → 앱 내 프롬프트, denied → 기기 설정 이동
is_participated_promotion
_{term}
Boolean Braze IAM 참여 완료 모달 조회 시 ⚡
event_properties.${term}으로 동적 생성
is_marketing_info_opted_in Boolean brazeBridge 약관 동의 모달 ⚡
is_marketing_message_opted_in Boolean brazeBridge 약관 동의 모달 ⚡
promotion_prize_{term} String brazeBridge 경품 추첨 완료 시
예: "서비스 쿠폰 10,000원", "SK 주유권 5만 원"
promotion_prize_tier_{term} String brazeBridge 경품 추첨 완료 시
값: top / mid / base
promotion_coupon_amount_{term} Number brazeBridge 쿠폰 당첨 시만 설정
값: 1000 / 5000 / 10000 / 30000 / 50000

🔄 UI 유형 구분

UI트리거
📝 약관 동의 모달deeplink_open_promotion 또는 기설치 안내 모달에서 이동
👋 기설치 안내deeplink_open_promotion
🎉 참여 완료 📌deeplink_open_promotion 또는 push_permission WHERE status=granted
조회 시 is_participated… = true
🔔 Push Primer (not_determined) 📌세그먼트: push_authorization_status = not_determined
🔔 Push Primer (denied) 📌세그먼트: push_authorization_status = denied
🔕 비활성화 안내push_permission WHERE status=denied
✅ 이미 참여 완료deeplink_open_promotion

📋 유저 타입별 플로우 요약

유저 타입플로우Braze 분기 조건최종 결과
신규 + 모두 동의 + 푸시 허용 📤 deeplink_open_promotion
WHERE term={term} / event_id={event_id} AND link_type=deferred
🎯 분기 D 🎉 참여 완료 (attr 생성)
미참여 + 약관2개 충족 + Push OK 🎉 완료
신규 + 약관 미충족 + 기기 허용 📤 → 🎯 분기 C📝 약관 동의 → 🎉 참여 완료 미참여 + 2개 중 미충족 + deferred + authorized 🎉 완료
신규 + 약관 미충족 + 기기 미허용 📤 → 🎯 분기 C📝 약관 동의🔔 Push Primer → ... 미참여 + 2개 중 미충족 + deferred + not_determined/denied 허용→🎉 / 거부→❌
신규 + 모두 동의 + 푸시 미허용 📤 → 🎯 분기 E🔔 Push Primer IAM → OS 권한 프롬프트 → ... 미참여 + 약관2개 충족 + push_authorization_status≠authorized 허용→🎉 / 거부→❌
기설치 + 모두 동의 + 푸시 허용 📤 deeplink_open_promotion
WHERE term={term} / event_id={event_id} AND link_type=direct
🎯 분기 D 🎉 참여 완료 (attr 생성)
미참여 + 약관2개 충족 + Push OK 🎉 완료
기설치 + 약관 미충족 + 기기 허용 📤 → 🎯 분기 B → 👋 기설치 안내 → 📝 약관 동의 → 🎉 참여 완료 미참여 + 2개 중 미충족 + direct + authorized 🎉 완료
기설치 + 약관 미충족 + 기기 미허용 📤 → 🎯 분기 B → 👋 기설치 안내 → 📝 약관 동의🔔 Push Primer → ... 미참여 + 2개 중 미충족 + direct + not_determined/denied 허용→🎉 / 거부→❌
기설치 + 모두 동의 + 푸시 미허용 📤 → 🎯 분기 E🔔 Push Primer IAM → OS 권한 프롬프트 → ... 미참여 + 약관2개 충족 + push_authorization_status≠authorized 허용→🎉 / 거부→❌
중복 참여 (공통) 📤 → 🎯 분기 A → ✅ "이미 참여 완료" is_participated_promotion_{term} = true ✅ 이미 참여

📌 참고 사항

항목설명
이벤트 프로퍼티 vs 세그먼트 term, link_type트리거 조건(이벤트 프로퍼티 필터)
is_participated…, is_marketing_info_opted_in, is_marketing_message_opted_in세그먼트 필터(custom attribute)
"모두 동의" 세그먼트 구성 2개 조건을 AND로 결합:
is_marketing_info_opted_in = true AND is_marketing_message_opted_in = true
AND Email Subscription = opted_in OR subscribed
AND Push Subscription = opted_in OR subscribed
"약관 미충족" = NOT (위 조건)
attribute 생성 시점 is_participated_promotion_{term}참여 완료 모달 조회 시 생성.
requestImmediateDataFlush() 반드시 호출.
Subscription 참고 email_subscribe, push_subscribe는 Braze Standard Subscription으로
Canvas HTML IAM에서 Liquid로 불러올 수 없음 → 약관 판별에 사용하지 않음
약관 동의는 is_marketing_info_opted_in + is_marketing_message_opted_in 2개로만 판별
IAM 우선순위 동일 이벤트에 여러 IAM 트리거 가능 → 우선순위 설정 필수
권장: 이미 참여(Highest) > 기설치 안내 > 약관 동의 > 참여 완료
IAM 연속 트리거 triggerMinimumTimeInterval 5초로 설정
경품 추첨 로직 드롭 성공 즉시 실행. prize_tier_appinstall_2603 (top/mid/base) 기반 랜덤 추첨
top: 맥북/PS5/파인다이닝 포함 / mid: 주유권까지 / base: 쿠폰만
claimPrize()는 fire-and-forget (콜백 없음, 재추첨 없음)
GAS 재고 차감 IAM → Google Apps Script POST (no-cors mode)
action=claim, prize=gasKey, braze_id 전송
재고 0 이하여도 클라이언트 측 추첨은 진행됨 (서버에서 차감 거부)
경품 결과 분기 top3 (macbook/ps5/dinner): 구글폼 직접 랜딩 (제세공과금 입력)
일반 경품 (gas/dept/conv/coupon_*): confirm 모달 → handleFinalClose()
지급: 이벤트 종료 후 4/6 일괄 지급
딥링크 스킴 Custom HTML IAM에서 앱 네이티브로 위임 (서버 직접 호출 없음 → CORS 불필요)
응모 처리: app://event/:eventId?apply_event=true (화면 이동 없이 응모, target 기본값=customer)
알림 설정 (약관 충족): app://braze/open-notification-settings?action=open_settings&term={term}
알림 설정 (약관 미충족, consent 통합): app://braze/open-notification-settings?action=open_settings&term={term}&consent=allow_use_marketing%3D1%26allow_news_letters%3D1
닫기 (약관 미충족, consent 통합): app://braze/open-notification-settings?action=close&term={term}&consent=allow_use_marketing%3D1%26allow_news_letters%3D1
📌 app://braze/consent 단독 호출 폐기 — 안드로이드 WebView에서 딥링크 2회 연속 호출 시 두 번째 미실행
분기 D/E 푸시 판단 (IAM 내부) Canvas 레벨 E-1/E-2 분기 폐기 → 약관 동의 IAM 내 isPushOn()으로 통합 처리
우선순위:foreground_push_enabled = true → 체스 드롭
foreground_push_enabled = false/blankpush_authorization_status = authorized 체크
③ fallback: brazeBridge.isPushPermissionGranted() (미지원 시 Liquid 값 사용)
isPushOn() = false → IAM 내 푸시 프라이머 페이지(3B)로 이동
Push Primer 닫기 처리 닫기 = 아무 행동도 하지 않은 것 → 모두 빈값으로 통일
push_authorization_status: 업데이트 안 함 (진입 시 값 유지)
push_permission: {status: '', source: ''}
not_determined든 denied든 닫기는 OS 팝업도 안 뜨고 설정 이동도 안 한 것이므로 동일 처리
source 판단 기준 앱에서 OS 팝업/설정 이동 여부를 정확히 알 수 없으므로,
진입 시 push_authorization_status 값 기준으로 판단:
not_determinedsource: 'prompt' (허용/거부 모두)
deniedsource: 'settings' (허용/거부유지 모두)
닫기 → source: '' (빈값, 행동 없이 닫은 경우만)
프로모션별 attribute is_participated_promotion_{term}event_properties.${term}으로 동적 생성됨.
IAM HTML에서 event_properties로 트리거 이벤트 프로퍼티를 직접 참조하므로 User Update 스텝이나 중간 attribute가 불필요.
새 프로모션 시 IAM HTML 변경 불필요. Canvas 복제 + term 필터 변경만 하면 됨.