Skip to content

Show subscription dialog when users skip onboarding#7929

Merged
nalcalag merged 10 commits intodevelopfrom
feature/noelia/show_subscription_dialog_for_skippers
Mar 12, 2026
Merged

Show subscription dialog when users skip onboarding#7929
nalcalag merged 10 commits intodevelopfrom
feature/noelia/show_subscription_dialog_for_skippers

Conversation

@nalcalag
Copy link
Contributor

@nalcalag nalcalag commented Mar 10, 2026

Task/Issue URL: https://app.asana.com/1/137249556945/project/72649045549333/task/1210557489696946?focus=true

Description

Show subscription dialog 7 days after install if onboarding is skipped

Steps to test this PR

Pre steps

Subscription dialog for users that skip onboarding

  • Fresh install
  • Skip onboarding as a returning user (Skip onboarding as a returning user (I've been here before > Start Browsing)
  • Close the app
  • Change the date in your device for >=7 days after today
  • Open the app and check subscription onboarding dialog appear (probably subscribe copy as you already used a Free Trial in the past)

Free Trial copy

  • On Play Billing Lab app go to Configuration settings and check 'Test free trial or introductory offer'
  • Remember to change date back to today
  • Fresh install
  • Skip onboarding as a returning user (not with dev button)
  • Close the app
  • Change the date in your device for >=7 days after today
  • Open the app and check subscription onboarding dialog appear with Free Trial copy

FF disabled

  • Fresh install
  • Remember to change date back to today
  • Skip onboarding as a returning user (not with dev button)
  • Go to Settings > Feature Flag Inventory
  • Disable privacyProCtaSkippedOnboarding
  • Close the app
  • Change the date in your device for >=7 days after today
  • Open the app and check subscription onboarding dialog doesn't appear

UI changes

Before After
!(Upload before screenshot) (Upload after screenshot)

Note

Medium Risk
Changes onboarding CTA selection and command emission timing, which can affect when promos/omnibar input auto-launch and subscription URLs are triggered. Risk is moderate due to new time-based gating, new feature flags, and updated pixel parameters, but it’s isolated to onboarding/promo flows.

Overview
Adds a new Privacy Pro onboarding promo path for returning users who previously skipped onboarding: after 7 days since install, a DaxPrivacyProCta can be returned from CtaViewModel.refreshCta when privacyProCtaSkippedOnboarding is enabled.

Updates the Privacy Pro CTA model to derive title/CTA copy from onboardingSkipped and free-trial eligibility, avoid auto-marking the CTA as read on show, and include new pixel params (ru, free_trial) for shown/OK events. Privacy Pro launch now builds the origin query parameter dynamically via getPrivacyProOnboardingOrigin().

Prevents Duck.ai’s LaunchInputScreen auto-open on new empty tabs when the skipped-onboarding promo is eligible to be shown, reducing UI conflicts. Feature toggle defaults are adjusted (extendedOnboarding.self and privacyProCta default to true; new privacyProCtaSkippedOnboarding added), and tests are updated/added to cover the new gating and suppression behavior.

Written by Cursor Bugbot for commit 9d4e7cf. This will update automatically on new commits. Configure here.

Copy link
Contributor Author

nalcalag commented Mar 10, 2026

@nalcalag nalcalag marked this pull request as ready for review March 10, 2026 15:13
Copy link
Contributor

@cursor cursor bot left a comment

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 2 potential issues.

Autofix Details

Bugbot Autofix prepared a fix for 1 of the 2 issues found in the latest run.

  • ✅ Fixed: Test doesn't validate the seven-day install check
    • Enabled the privacyProCtaSkippedOnboarding toggle in the less-than-seven-days test so it now exercises the day-threshold path instead of failing early on a disabled feature flag.

Create PR

Or push these changes by commenting:

@cursor push 3c965bb09d
Preview (3c965bb09d)
diff --git a/app/src/test/java/com/duckduckgo/app/cta/ui/OnboardingDaxDialogTests.kt b/app/src/test/java/com/duckduckgo/app/cta/ui/OnboardingDaxDialogTests.kt
--- a/app/src/test/java/com/duckduckgo/app/cta/ui/OnboardingDaxDialogTests.kt
+++ b/app/src/test/java/com/duckduckgo/app/cta/ui/OnboardingDaxDialogTests.kt
@@ -284,6 +284,7 @@
         whenever(appInstallStore.installTimestamp).thenReturn(System.currentTimeMillis() - 3 * 24 * 3600 * 1000L)
         whenever(dismissedCtaDao.exists(DAX_INTRO_PRIVACY_PRO)).thenReturn(false)
         whenever(extendedOnboardingFeatureToggles.privacyProCta()).thenReturn(mockEnabledToggle)
+        whenever(extendedOnboardingFeatureToggles.privacyProCtaSkippedOnboarding()).thenReturn(mockEnabledToggle)
         whenever(mockSubscriptions.isEligible()).thenReturn(true)
 
         val result = testee.refreshCta(

@nalcalag nalcalag force-pushed the feature/noelia/show_subscription_dialog_for_skippers branch from f86e3d8 to 9b38a82 Compare March 11, 2026 11:38
Copy link
Contributor

@cursor cursor bot left a comment

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.

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: markAsReadOnShow=false also changes regular onboarding CTA behavior
    • Made DaxPrivacyProCta.markAsReadOnShow conditional (!onboardingSkipped) so regular onboarding still auto-dismisses on show while skipped-onboarding continues requiring explicit dismissal.

Create PR

Or push these changes by commenting:

@cursor push 82c8655380
Preview (82c8655380)
diff --git a/app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt b/app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt
--- a/app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt
+++ b/app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt
@@ -824,7 +824,7 @@
         onboardingStore = onboardingStore,
         appInstallStore = appInstallStore,
     ) {
-        override val markAsReadOnShow: Boolean = false
+        override val markAsReadOnShow: Boolean = !onboardingSkipped
 
         private fun subscriptionOnboardingPixelParams(): Map<String, String> = mapOf(
             Pixel.PixelParameter.CTA_SHOWN to ctaPixelParam,

Comment on lines +848 to +855
viewModelScope.launch {
// whenever an event fires, so the user switched to a new tab page, launch the input screen
// unless an onboarding promo message is displayed
val hasPendingOnboardingPromo = ctaViewModel.isPromoOnboardingDialogShowing()
if (!hasPendingOnboardingPromo) {
command.value = LaunchInputScreen
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was already reviewed by @joshliebe in a stacked PR. There was a conflict between the onboarding dialog and the duck.ai toggle that was fixed there.

Copy link
Contributor

@lmac012 lmac012 left a comment

Choose a reason for hiding this comment

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

LGTM

nalcalag added 10 commits March 12, 2026 14:55
Task/Issue URL:
https://app.asana.com/1/137249556945/task/1213568547695591

### Description
Avoid launching input screen when onboarding promo dialog is shown

### Steps to test this PR

- [x] Apply patch pinned on
https://app.asana.com/1/137249556945/project/1209991789468715/task/1210448620621729?focus=true
- [x] Fresh install
- [x] Skip onboarding tapping on "I've been here before" > "Start
browsing"
- [x] Check duck ai toggle is enabled
- [x] Close the app and set the date to 7 days from today.
- [x] Open app
- [x] Check duck.ai toggle is not launched and the onboarding dialog
shows correctly

### UI changes
| Before  | After |
| ------ | ----- |
<img width="370" height="820" alt="Screenshot 2026-03-10 at 15 44 35"
src="https://github.com/user-attachments/assets/bca20627-4460-426a-98c9-98fb5d4f6d8c"
/>|<img width="380" height="844" alt="Screenshot 2026-03-10 at 11 21 50"
src="https://github.com/user-attachments/assets/fae4208a-ed57-4a32-96dd-aa1fd93e4d19"
/>|

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UX gating change that only affects when `LaunchInputScreen`
is emitted for new blank tabs; main risk is unintended suppression/extra
IO on tab switches due to the new suspend check.
> 
> **Overview**
> Prevents Duck.ai’s input screen from auto-launching on a new blank tab
when the Privacy Pro skipped-onboarding promo dialog is eligible to be
shown.
> 
> `BrowserTabViewModel` now checks
`CtaViewModel.isPromoOnboardingDialogShowing()` before issuing
`Command.LaunchInputScreen`, and tests add coverage to ensure the
command is suppressed under that promo-onboarding condition.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8a0cd34. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@nalcalag nalcalag force-pushed the feature/noelia/show_subscription_dialog_for_skippers branch from 9b38a82 to 9d4e7cf Compare March 12, 2026 15:05
@nalcalag nalcalag merged commit f212143 into develop Mar 12, 2026
10 checks passed
@nalcalag nalcalag deleted the feature/noelia/show_subscription_dialog_for_skippers branch March 12, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants