7.7 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 in the code (
funnel_modal_ios__subscriptionnudge) is a placeholder — it has not been submitted through the origin form and is not yet approved. The final string may differ. This must be resolved before shipping, regardless of which pixel option is selected. Android equivalent post-unification isfunnel_browsermodal_android. Origin Proposal form: https://form.asana.com/?k=Wy3aY17vglr2bihpUHoyBA&d=137249556945