From 103c6731f91206f8ab7f6a0e4e0c51ce354aa7d4 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Wed, 8 Jul 2026 16:23:41 +0600 Subject: [PATCH] [2026-07-08] eagle: work/projects/ios-subscription-day7-promo-pixels.md work/projects/ios-subscription-day7-promo-privacy-triage.md --- .../ios-subscription-day7-promo-pixels.md | 79 ++++++++++++++++++ ...-subscription-day7-promo-privacy-triage.md | 82 +++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 work/projects/ios-subscription-day7-promo-pixels.md create mode 100644 work/projects/ios-subscription-day7-promo-privacy-triage.md diff --git a/work/projects/ios-subscription-day7-promo-pixels.md b/work/projects/ios-subscription-day7-promo-pixels.md new file mode 100644 index 00000000..a853ff8a --- /dev/null +++ b/work/projects/ios-subscription-day7-promo-pixels.md @@ -0,0 +1,79 @@ +# Pixel Definitions: iOS Day-7 Subscription Promo + +Defined in: `iOS/PixelDefinitions/pixels/definitions/subscription.json5` +Fired from: `SubscriptionPromoExistingUserCoordinator` +Android equivalents: `m_privacy-pro_skipped_onboarding_promotion_*` (same modal, different audience) + +--- + +## Pixels + +### `m_privacy-pro_existing_user_promotion_impression` + +| Field | Value | +|---|---| +| Trigger | The day-7 promo half-sheet is shown to an existing user (7+ days since install) who has never seen any subscription offer | +| Fired from | `SubscriptionPromoExistingUserCoordinator.markLaunchPromptPresented()` | +| Frequency | Once per install (guarded by `subscriptionPromotionDialogShown`) | + +**Parameters** + +| Key | Type | Description | +|---|---|---| +| `appVersion` | string | App version (added by default) | +| `ru` | boolean | Whether the user is a returning user (reinstall) | +| `free_trial` | boolean | Whether the user is eligible for a free trial | + +**Suffixes:** `_ios`, `_phone` / `_tablet` + +--- + +### `m_privacy-pro_existing_user_promotion_tap` + +| Field | Value | +|---|---| +| Trigger | User taps the CTA button ("Try It Free" or "Learn More") on the promo modal | +| Fired from | `SubscriptionPromoExistingUserCoordinator.handleCTAAction()` | + +**Parameters** — same as impression: `appVersion`, `ru`, `free_trial` + +**Suffixes:** `_ios`, `_phone` / `_tablet` + +--- + +### `m_privacy-pro_existing_user_promotion_dismiss` + +| Field | Value | +|---|---| +| Trigger | User dismisses the promo modal (taps close or swipes down) | +| Fired from | `SubscriptionPromoExistingUserCoordinator.handleDismissAction()` | + +**Parameters** — same as impression: `appVersion`, `ru`, `free_trial` + +**Suffixes:** `_ios`, `_phone` / `_tablet` + +--- + +## Funnel Origin + +When the user taps the CTA, the subscription flow is opened with origin `funnel_modal_ios__subscriptionnudge`. + +This origin flows through to two downstream pixels automatically: +- `m_privacy-pro_offer_screen_impression` (param: `origin`) +- `m_subscribe` (param: `origin`) — the subscription purchase success pixel + +Origin defined in: `iOS/DuckDuckGo/Subscription/SubscriptionFunnelOrigin.swift` +Origin request subtask: https://app.asana.com/1/137249556945/task/1214800683792174 +Android equivalent origin: `funnel_modal_android__subscriptionnudge` + +--- + +## Relation to Existing Promo Pixels + +All three subscription promo half-sheets use the same parameter shape (`ru`, `free_trial`) to allow cross-audience comparison: + +| Pixel prefix | Audience | Origin | +|---|---|---| +| `m_privacy-pro_onboarding_promotion_*` | Users who see the promo during onboarding | `funnel_onboarding_ios` | +| `m_privacy-pro_skipped_onboarding_promotion_*` | Reinstallers who skipped onboarding, 7+ days | `funnel_modal_ios__skippedonboardingupsell` | +| `m_privacy-pro_existing_user_promotion_*` | Normal installers who never saw a subscription offer, 7+ days | `funnel_modal_ios__subscriptionnudge` | diff --git a/work/projects/ios-subscription-day7-promo-privacy-triage.md b/work/projects/ios-subscription-day7-promo-privacy-triage.md new file mode 100644 index 00000000..cdc06928 --- /dev/null +++ b/work/projects/ios-subscription-day7-promo-privacy-triage.md @@ -0,0 +1,82 @@ +# Privacy Triage: iOS Day-7 Subscription Promo Pixels + +Status: **DRAFT** — to be reviewed and submitted before ship review +Asana project task: https://app.asana.com/1/137249556945/project/1202406491309510/task/1214798984829406 + +--- + +## What pixels are being added? + +Three new pixels fired from `SubscriptionPromoExistingUserCoordinator`: + +| Pixel name | When fired | +|---|---| +| `m_privacy-pro_existing_user_promotion_impression` | The day-7 promo half-sheet is displayed | +| `m_privacy-pro_existing_user_promotion_tap` | User taps the CTA ("Try It Free" / "Learn More") | +| `m_privacy-pro_existing_user_promotion_dismiss` | User dismisses the promo modal | + +--- + +## Parameters sent with each pixel + +| Parameter key | Type | Value | Description | +|---|---|---|---| +| `appVersion` | string | e.g. `7.215.0` | App version, added automatically | +| `ru` | boolean | `true` / `false` | Whether the user is a returning user (reinstall detected via variant `"ru"`) | +| `free_trial` | boolean | `true` / `false` | Whether the user is eligible for a free trial at time of display | + +No user identifiers, no browsing data, no PII. + +--- + +## Privacy Assessment + +### Is any new data collected about the user? + +No new data is collected from the user. The parameters (`ru`, `free_trial`) are: +- `ru` — derived from the install variant flag already stored locally; same parameter used by `m_privacy-pro_onboarding_promotion_impression` and `m_privacy-pro_skipped_onboarding_promotion_impression` +- `free_trial` — derived from App Store product availability check already performed by `SubscriptionManager`; same parameter used by the existing promo pixels above + +### Does this introduce any new data collection mechanism? + +No. These pixels follow the identical pattern of the pre-existing `m_privacy-pro_skipped_onboarding_promotion_*` pixels, which have already passed privacy triage. + +### Is the data linked to a user or device? + +No. Pixels are sent anonymously via the standard pixel infrastructure. No user ID, device ID, or ATB is included. + +### What is the purpose of the data? + +Measure the effectiveness of the day-7 promo half-sheet: +- **Impression** — how many eligible users see the promo +- **Tap** — conversion rate from impression to CTA click +- **Dismiss** — dismissal rate + +This data will be used to evaluate whether the feature achieves the goal of 10 trial starts/day and to decide whether to keep the feature on. + +### How long is the data retained? + +Standard pixel retention policy applies. Pixels are not stored on device after firing. + +### Are there any additional risks? + +The `ru` parameter could theoretically indicate a user is a reinstaller, but: +- This information is already sent in the existing promo pixels +- It is aggregated data with no user-level linkage +- It is used only to segment promo performance by user cohort + +--- + +## Comparison to existing approved pixels + +These pixels are structurally identical to `m_privacy-pro_skipped_onboarding_promotion_*`, which were already approved. The only differences are: +1. Different pixel name (different audience segment) +2. Different origin value (`funnel_modal_ios__subscriptionnudge` vs `funnel_modal_ios__skippedonboardingupsell`) + +--- + +## Open questions for privacy reviewer + +- [ ] Is the `ru` (returning user) parameter still acceptable given no new data is collected? +- [ ] Is there any concern with the `free_trial` parameter being sent on dismiss (user never tapped CTA)? +- [ ] Are there any additional parameters the privacy team would like to see for monitoring purposes?