7.5 KiB
Pixel Definition: iOS Day-7 Subscription Promo Half-Sheet
Background
- Project: iOS: Show subscription half-sheet promo to new installers who don't see it during onboarding
- Android counterpart: Grow active subscriptions by increasing paywall impressions with a day 7 promo half-sheet — the iOS implementation follows the same approach and target audience as Android
- Origin request: Request origin for iOS subscription promo half-sheet entry point — origin not yet formally approved; placeholder in code is
funnel_modal_ios__subscriptionnudge. Android equivalent (formally approved, post-unification):funnel_browsermodal_android(origin definition, unify origins task) - We are adding a new half-sheet modal for existing users (7+ days since install) who have never seen any subscription offer. The modal reuses the pre-existing
SubscriptionPromoLaunchViewUI. - Existing subscription promo pixels already cover related audiences:
m_privacy-pro_onboarding_promotion_[impression|tap|dismiss]— users who see the promo during onboardingm_privacy-pro_skipped_onboarding_promotion_[impression|tap|dismiss]— reinstallers who skipped onboarding (7+ days)
Objective
- Instrument the day-7 existing-user promo half-sheet with impression, tap, and dismiss pixels.
- These are permanent pixels (no expiry) — the feature is not an experiment.
- The origin value
funnel_modal_ios__subscriptionnudgeflows downstream automatically tom_privacy-pro_offer_screen_impressionandm_subscribewithout additional work.
Android reference
Android uses shared pixels for both the reinstaller promo and the day-7 promo, with no origin pixel parameter — origin is only embedded in the subscription purchase URL (https://duckduckgo.com/pro?origin=…) for downstream funnel attribution:
| Event | Android pixel string | origin in URL |
|---|---|---|
| Shown (both audiences) | m_odc_s |
funnel_browsermodal_android (unified; was funnel_skippedonboarding_android / funnel_newusermodal_android before unification) |
| CTA tapped (both audiences) | m_odc_ok |
same as above |
| Dismissed (both audiences) | m_onboarding_dax_cta_dismiss |
same as above |
The two audiences are indistinguishable at the pixel level on Android — analysis relies on the origin flowing to downstream purchase pixels. Source: Android PR #8369, BrowserTabViewModel.kt + CtaViewModel.kt.
Android pixel definition / privacy triage tasks cover Phase 1 paywall instrumentation only (m_subscription_paywall_not_seen_*) — the promo modal itself got no separate pixel definition or privacy triage:
- Define pixels to track users who haven't seen the subscription paywall
- Privacy Triage: Android - Added new subscription_promo_shown pixel param
Option A — Recommended: Reuse existing pixels (mirrors Android approach)
Reuse m_privacy-pro_skipped_onboarding_promotion_[impression|tap|dismiss] for the day-7 audience. Audience attribution relies on the origin URL parameter (funnel_modal_ios__subscriptionnudge) flowing to downstream purchase pixels — identical to Android's approach.
No new pixels required. No privacy triage required for new pixels.
| Pixel | Trigger |
|---|---|
m_privacy-pro_skipped_onboarding_promotion_impression |
Day-7 half-sheet shown |
m_privacy-pro_skipped_onboarding_promotion_tap |
User taps CTA |
m_privacy-pro_skipped_onboarding_promotion_dismiss |
User dismisses without tapping CTA |
Trade-off: Cross-audience analysis (reinstallers vs day-7 existing users) is not directly available from pixels alone; it requires joining on origin via downstream m_privacy-pro_offer_screen_impression / m_subscribe pixels.
Option B — Alternative: Separate pixels per audience
Define three new pixels exclusively for the day-7 audience. Provides direct per-audience split in pixel dashboards without filtering by origin. Requires a new privacy triage.
Testing
- Test paths:
- Install app, complete or skip onboarding
- Wait 1 minute (1-min override active — revert to 7 days before shipping)
- Background and re-foreground app → promo half-sheet should appear
- Verify
m_privacy-pro_existing_user_promotion_impressionfires on display - Tap CTA → verify
m_privacy-pro_existing_user_promotion_tapfires and subscription flow opens with the approved origin (placeholder:funnel_modal_ios__subscriptionnudge) - Re-install and dismiss instead → verify
m_privacy-pro_existing_user_promotion_dismissfires
Pixel definitions
m_privacy-pro_existing_user_promotion_impression
- Trigger: The day-7 promo half-sheet is shown to an existing user (7+ days since install) who has never seen any subscription offer.
- Frequency: Once per install (guarded by
daxDialogsSettings.subscriptionPromotionDialogShown). - Parameters:
appVersion— app version (added by default)ru—true/false— whether the user is a returning user (reinstall)free_trial—true/false— whether the user is eligible for a free trial at time of display
- Suffixes:
_ios,_phone/_tablet
m_privacy-pro_existing_user_promotion_tap
- Trigger: User taps the CTA button ("Try It Free" or "Learn More") on the promo modal.
- Frequency: Standard (can fire once per impression, since the modal is shown at most once).
- Parameters: same as impression —
appVersion,ru,free_trial - Suffixes:
_ios,_phone/_tablet
m_privacy-pro_existing_user_promotion_dismiss
- Trigger: User dismisses the promo modal (taps X or swipes down) without tapping the CTA.
- Frequency: Standard.
- Parameters: same as impression —
appVersion,ru,free_trial - Suffixes:
_ios,_phone/_tablet
Behavior rules
- Impression and tap/dismiss are mutually exclusive per install — the modal is shown at most once.
ruandfree_trialare evaluated at time of display, same as in the skipped-onboarding promo.- The dismiss pixel fires on both explicit close (X button) and swipe-to-dismiss; neither path fires the tap pixel.
- If the user taps CTA, tap fires but dismiss does not.
Trade-off: Three new pixels to triage. Structurally identical to m_privacy-pro_skipped_onboarding_promotion_* — no new parameter types are introduced.
Notes and status
- Option A pixels are already defined in
subscription.json5asm_privacy-pro_skipped_onboarding_promotion_[impression|tap|dismiss]; reusing them for this audience requires no code changes to pixel definitions. - If Option B is chosen, new definitions must be added to
subscription.json5and a privacy triage opened.- Privacy triage (for Option B): [Insert Privacy Triage link]
- The iOS origin value needs to be formally submitted and approved via the Origin Proposal form.
- Suggested name:
funnel_modal_ios__subscriptionnudge. - Android equivalent (post-unification):
funnel_browsermodal_android.
- Suggested name: