Skip to content

Add origin to Duck.ai and Pro subscription-funnel pixels - #9381

Open
YoussefKeyrouz wants to merge 1 commit into
developfrom
feature/youssef/funnel_pixels
Open

Add origin to Duck.ai and Pro subscription-funnel pixels#9381
YoussefKeyrouz wants to merge 1 commit into
developfrom
feature/youssef/funnel_pixels

Conversation

@YoussefKeyrouz

@YoussefKeyrouz YoussefKeyrouz commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Task/Issue URL: https://app.asana.com/1/137249556945/task/1217126669949056?focus=true
Tech Design URL (if applicable):
API Proposals URL(s) (if applicable):

Description

Adds an origin parameter to the native subscription-funnel entry points so the dashboard can join impression -> click -> offer/purchase per entry point. Impression = a _shown pixel; click = origin on the existing upsell/CTA pixel (iOS-aligned).

New impression pixels (_shown):

  • m_aichat_unified_input_model_picker_shown: model picker opened
  • m_aichat_unified_input_reasoning_effort_picker_shown: reasoning picker opened
  • m_aichat_unified_input_free_label_shown: Free upgrade pill shown

origin added to existing pixels:

  • m_aichat_unified_input_subscription_upsell_triggered: gated model / reasoning tap
  • m_aichat_unified_input_chat_header_upgrade_tapped: Free pill tap
  • m_privacy-pro_offer_screen_impression: offer page shown
  • m_privacy-pro_app-settings_get_click: Settings "Get Subscription" tap
  • m_privacy-pro_terms-conditions_subscribe_click: Subscribe CTA on the offer page

Origins: funnel_{duckai,addressbar}_android__modelpicker, ...__reasoningdropdown, funnel_duckai_android__switchmodel, funnel_duckai_android__freelabel, funnel_appsettings_android.

Registry: widened the purchase wide-event context.name pattern to accept the __entrypoint origin shape; added a count_short suffix to the dictionary.

Steps to test this PR

Setup
Internal build. Filter logcat by “pixel sent".
Account: Free tier, subscription-eligible .

Model & reasoning pickers

  • Duck.ai tab: open model picker -> model_picker_shown; tap a gated model -> subscription_upsell_triggered + offer_screen_impression. Origin funnel_duckai_android__modelpicker
  • Address bar: same but from the browser address bar. Origin funnel_addressbar_android__modelpicker
  • Reasoning picker (both surfaces): open -> reasoning_effort_picker_shown; tap a gated mode -> subscription_upsell_triggered. Origin ...__reasoningdropdown
  • Switch model (FE recovery mode. This is accessed by logging into a PRO account, starting a chat, then removing the subscription and trying to resume that chat, you will get a message to swtich the mode): impression + click has …__switchmodel instead of modelpicker

Free label

  • Free tier, open Duck.ai -> "Free" pill appears on top -> free_label_shown;
  • Tap Upgrade -> chat_header_upgrade_tapped. Origin ...__freelabel

App-settings / offer page

  • Main Settings screen, subscription row (shown to non-subscribers), tap "Subscribe to DuckDuckGo" (may read "Try Free Trial" / a Black Friday offer) -> app-settings_get_click -> offer page -> offer_screen_impression. Origin funnel_appsettings_android
  • On the offer page tap Subscribe -> terms-conditions_subscribe_click with the launch origin

Regression

  • Tapping a free/accessible model or reasoning mode fires only the existing selection pixel; no funnel click/origin

UI changes

None, telemetry only.


Note

Low Risk
Telemetry-only changes with no user-facing behavior; origin validation on paywall pixels reduces risk of malformed URL parameters.

Overview
Adds origin on native subscription-funnel entry points so analytics can join impression → click → offer/purchase per entry point (aligned with iOS).

New impression pixels fire when UI surfaces appear: model picker, reasoning effort picker, and the upgradeable Free pill in the Duck.ai omnibar (free_label_shown). Existing click pixels now include origin for gated model/reasoning upsells, chat-header upgrade taps, offer-screen impressions, Settings Get Subscription, and offer-page Subscribe CTA.

Origin strings use funnel_{addressbar|duckai}_android__{modelpicker|reasoningdropdown|switchmodel|freelabel} plus funnel_appsettings_android. Picker surfaces were renamed from nativeinput/reasoningpicker to addressbar/reasoningdropdown; model-recovery uses switchmodel.

Registry: widened wide_subscription-purchase context.name to allow __entrypoint suffixes; added count_short suffix; new subscription pixels use regex-validated origins on paywall events (invalid/blank origins dropped).

Runtime: omnibar fires free-label impression once per show cycle; webview seeds launch origin for subscribe-click attribution; upgrade offer URLs count as offer pages when opened with a funnel origin.

Reviewed by Cursor Bugbot for commit ba188e2. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Privacy Review task: https://app.asana.com/0/69071770703008/1217134106515700

@YoussefKeyrouz
YoussefKeyrouz force-pushed the feature/youssef/funnel_pixels branch from f16eabf to ba188e2 Compare August 4, 2026 18:49

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ba188e2. Configure here.

val upgradeUri = subscriptionsUrlProvider.upgradeToProUrl.toUri()
subscriptions.isSubscriptionUrl(uri) ||
(origin != null && uri.host == upgradeUri.host && uri.path == upgradeUri.path)
}.getOrDefault(false)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upgrade funnel missing subscribe click

Medium Severity

isOfferPageUrl now counts Plus→Pro /plans launches as offer impressions when an origin is present, so Duck.ai upgrade funnels (gated Pro model/reasoning → LaunchUpgrade) send offer_screen_impression with that origin. The upgrade page CTA is handled by subscriptionChangeSelected, which never calls reportOfferSubscribeClick, so those impressions have no matching terms-conditions_subscribe_click and the impression→click join breaks for upgrade origins.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ba188e2. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant