프로모션 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}}}"; |
term 파라미터 변경 → 앱 배포 불필요term 값 + Decision Split 1의 attribute 이름 변경| 딥링크 URL 포맷 | |
|---|---|
app://event/{eventId}?apply_event=true&term={term} | |
| 파라미터 | 설명 |
eventId (URL path) | 이벤트 페이지 식별 ID |
term (query string) | 프로모션 식별자. 이벤트 프로퍼티 + attribute 키 생성에 사용 |
apply_event (query string) | true일 때만 Braze 이벤트 발송. false이면 페이지만 표시 |
app://braze/consent 단독 호출 폐기 → handleFinalClose()에서 300ms 후 brazeBridge.closeMessage() 호출로 통합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 |
email_subscribe, push_subscribe는 Braze Canvas HTML에서 Liquid로 불러올 수 없으므로 제외
| 앱이 발송하는 진입 이벤트 (apply_event=true일 때만) | ||
|---|---|---|
| 순서 | 항목 | 설명 |
| ① | setCustomAttribute('push_authorization_status', ...) | OS 푸시 권한 상태: not_determined / denied / authorized |
| ② | logCustomEvent('deeplink_open_promotion', {...}) | 딥링크 진입 이벤트 |
| deeplink_open_promotion 프로퍼티 | ||
| Property | Type | 설명 |
link_type | String | deferred = 신규 설치 | direct = 기설치 |
term | String | 프로모션 식별자 — 딥링크에서 동적 추출 (예: appinstall_2603) |
event_id | String | 이벤트 페이지 ID — 딥링크 path에서 동적 추출 |
공통 트리거: 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 내부에서 통합 처리 |
term 또는 event_id로 프로모션별 필터링 가능is_marketing_info_opted_in=true AND
is_marketing_message_opted_in=true
SDK Event: push_permission | ||
|---|---|---|
| Property | Type | 설명 |
status | String | granted = 허용 | denied = 거부/닫기 |
event_term | String | 프로모션 식별자 (예: promotion_appinstall_2603) |
source | String | 권한 허용 출처: prompt / settings (선택) |
| OS 푸시 권한 결과에 따라 앱에서 즉시 발송 → status=granted: 참여 완료 IAM 트리거→ status=denied: 실패 IAM 트리거 | ||
Braze IAM Event: view_participated_promotion_modal | ||
| Property | Type | 설명 |
event_term | String | 프로모션 식별자 (예: promotion_appinstall_2603) |
| 참여 완료 모달 조회 시 brazeBridge.logCustomEvent()로 발송 | ||
Braze IAM Event: view_has_app_modal | ||
| Property | Type | 설명 |
event_term | String | 프로모션 식별자 (예: promotion_appinstall_2603) |
| 기설치 안내 모달 조회 시 brazeBridge.logCustomEvent()로 발송 | ||
Braze IAM Event: view_terms_consent_modal | ||
| Property | Type | 설명 |
displayed_items | Array | 노출된 동의 항목 목록 (예: ['marketing_info', 'marketing_message']) |
| 약관 동의 모달 조회 시 brazeBridge.logCustomEvent()로 발송 | ||
Braze IAM Event: click_terms_submit_button | ||
| Property | Type | 설명 |
is_all_checked | Boolean | 모든 체크박스 선택 여부 (true = 활성화된 버튼 클릭) |
checked_items | Array | 선택된 항목 목록 (예: ['marketing_info', 'marketing_message']) |
event_term | String | 프로모션 식별자 (예: promotion_appinstall_2603) |
| 약관 동의 버튼 클릭 시 brazeBridge.logCustomEvent()로 발송 | ||
| 인앱 메시지 | 타입 | 트리거 + 세그먼트 |
|---|---|---|
| ✅ 이미 참여 완료 | Custom HTML | deeplink_open_promotionWHERE term={term} / event_id={event_id} + is_participated_promotion_{term} = true |
| 👋 기설치 안내 | Custom HTML | deeplink_open_promotionWHERE term={term} / event_id={event_id} + 미참여 + 약관 미충족 + link_type=direct |
| 📝 약관 동의 모달 | Custom HTML | deeplink_open_promotionWHERE 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 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회 통합 |
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)setCustomUserAttribute('is_marketing_message_opted_in', true)
requestImmediateDataFlush()foreground_push_enabled = true → 3A(체스 드롭)으로 이동foreground_push_enabled = false/blank → push_authorization_status = authorized 체크brazeBridge.isPushPermissionGranted() (미지원 시 Liquid 값 사용)| 항목 | 내용 |
|---|---|
| 트리거 | 체스 드롭 성공 (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} = truepromotion_prize_{term} = 경품명 (예: "서비스 쿠폰 10,000원")promotion_prize_tier_{term} = top / mid / basepromotion_coupon_amount_{term} = 쿠폰 금액 (쿠폰 당첨 시만)
|
| 이벤트 | view_participated_promotion_modal프로퍼티: prize_name, prize_detail, prize_tier, coupon_amount |
| Attribute | 타입 | 설정 주체 |
|---|---|---|
push_authorization_status |
String | 앱 SDK 딥링크 진입 시 값: not_determined / denied / authorized 📌 iOS/Android 13+ 공통: not_determined → 앱 내 프롬프트, denied → 기기 설정 이동 |
is_participated_promotion |
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 | 트리거 |
|---|---|
| 📝 약관 동의 모달 | 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_promotionWHERE 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_promotionWHERE 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 = trueAND 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/blank → push_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_determined → source: 'prompt' (허용/거부 모두)denied → source: 'settings' (허용/거부유지 모두)닫기 → source: '' (빈값, 행동 없이 닫은 경우만) |
| 프로모션별 attribute | is_participated_promotion_{term}은 event_properties.${term}으로 동적 생성됨.IAM HTML에서 event_properties로 트리거 이벤트 프로퍼티를 직접 참조하므로 User Update 스텝이나 중간 attribute가 불필요.새 프로모션 시 IAM HTML 변경 불필요. Canvas 복제 + term 필터 변경만 하면 됨. |