# 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](https://app.asana.com/1/137249556945/project/1202406491309510/task/1214798984829406) - **Android counterpart:** [Grow active subscriptions by increasing paywall impressions with a day 7 promo half-sheet](https://app.asana.com/1/137249556945/project/72649045549333/task/1210994036696114) — the iOS implementation follows the same approach and target audience as Android - **Origin request:** [Request origin for iOS subscription promo half-sheet entry point](https://app.asana.com/1/137249556945/task/1214800683792174) — **origin not yet formally approved**; placeholder in code is `funnel_modal_ios__subscriptionnudge`. Android equivalent (formally approved, post-unification): `funnel_browsermodal_android` ([origin definition](https://app.asana.com/1/137249556945/task/1214454966691411), [unify origins task](https://app.asana.com/1/137249556945/task/1214440762354001)) - 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 `SubscriptionPromoLaunchView` UI. - Existing subscription promo pixels already cover related audiences: - `m_privacy-pro_onboarding_promotion_[impression|tap|dismiss]` — users who see the promo during onboarding - `m_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__subscriptionnudge` flows downstream automatically to `m_privacy-pro_offer_screen_impression` and `m_subscribe` without 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](https://github.com/duckduckgo/Android/pull/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](https://app.asana.com/1/137249556945/task/1213904100962479) - [Privacy Triage: Android - Added new subscription_promo_shown pixel param](https://app.asana.com/1/137249556945/task/1214025242626360) --- ## 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_impression` fires on display - Tap CTA → verify `m_privacy-pro_existing_user_promotion_tap` fires 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_dismiss` fires ### 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. - `ru` and `free_trial` are 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.json5` as `m_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.json5` and 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](https://form.asana.com/?k=Wy3aY17vglr2bihpUHoyBA&d=137249556945). - Suggested name: `funnel_modal_ios__subscriptionnudge`. - Android equivalent (post-unification): `funnel_browsermodal_android`.