6.5 KiB
6.5 KiB
iOS: Chat-Path Onboarding — Tracker Blocking Demo
Asana: Ship Review task
Branch stack:demo-tracker-blocking-onboarding→ui-polish→chat-path-dialog-polish→sr-feedback→uti-flow
Due: 2026-05-15
Overview
A/B experiment adding a tracker-blocking demo step to onboarding for users who pick Duck.ai (chat-path). After the Fire Onboarding step, users see:
- "Try visiting a site!" dialog (address bar + toolbar hidden)
- Trackers-blocked dialog after a site loads
- "You've got this!" EOJ completion dialog
- Subscription upsell ("Oh, before I forget...")
Cohorts: Treatment A (address bar top) · Treatment B (address bar bottom) · Control (no change)
Audience: US only · iPhone only · Users who chose Duck.ai in onboarding, in A or B cohort
PR Stack
| PR | Branch | Status |
|---|---|---|
| #4544 | demo-tracker-blocking-onboarding |
Open — needs fixes |
| #4591 | demo-tracker-blocking-onboarding-ui-polish |
Approved — needs rebase |
| #4664 | demo-tracker-blocking-onboarding-chat-path-dialog-polish |
Open — needs fix |
| #4668 | demo-tracker-blocking-onboarding-uti-flow |
Open — needs fix |
| #4855 | demo-tracker-blocking-onboarding-sr-feedback |
Open — needs fixes |
Required Changes
PR #4544 — main chat-path branch
- Danger CI: No
@UserDefaultsWrapperusage remains. - Mock refactor (alessandroboron):
MockDaxDialogsSettings.chatPathPhaseis a plain stored property, directly settable in tests. - Sync restore exclusion: Uncommented
guard case .introDialog(isReturningUser: false) = introSteps.firstinOnboardingIntroViewModel.insertExperimentStepIfNeeded(). Excludes all returning users (including sync-restore) from experiment enrollment. return .treatmentAoverride: Removed hardcoded early return fromresolveDuckAIQueryExperimentCohortID(). Now routes through the feature flagger.- Pixels:
onboardingChatPathTryVisitSiteUniqueandonboardingChatPathTrackersBlockedUniquedefined inPixelEvent.swiftwith matchingonboarding.json5entries. No overlap with PR #4687.
PR #4664 — chat-path dialog polish
- Title scope (alessandroboron): Fixed in commit
c15122a1b0—RebrandedNewTabDaxDialogFactory.createSubsequentDialoguses the correct title per chat-path vs standard path.
PR #4668 — UTI onboarding flow fixes
- Dialog position, dismiss on navigation, UTI bar, completion path — all resolved.
- Hardcoded UTI override:
FeatureFlag.swift.unifiedToggleInputconfirmed correct —Config(source: .remoteReleasable(...)), nodefaultValue: .enabled.
PR #4855 — sr-feedback
- Hide toolbar + address bar:
NewTabPageViewControllernow callschromeDelegate?.setBarsHidden(true/false, animated: false, customAnimationDuration: nil)in the show block,dismiss(), anddismissHostingController. Replaces previoussetNavigationBarHidden+setChatPathVisitSiteControlsLockedpair. - Use delegate: Added
newTabPageControllerCurrentTabIsLoading(_ controller:) -> BooltoNewTabPageControllerDelegate(defaultfalse). Implemented inMainViewControllerascurrentTab?.isLoading == true. All(parent as? MainViewController)?casts removed fromNewTabPageViewController. - Loading guard placement: Folded into the outer
ifcondition via the new delegate method. No orphaned lock possible. - Revert Search Experience screen copy:
UserText.swiftsearchAndDuckAIOptionreverted to"Toggle between\nSearch and Duck.ai". All 26 lproj files updated. - DuckAIQuery toggle copy:
DuckAIQueryExperiment.toggleAILabel="Ask AI".
Privacy Config / Experiment Setup (TBD before shipping)
- Rename experiment in privacy config — create new experiment name, disable old one.
- Set
"targets": [{ "localeLanguage": "en", "localeCountry": "US" }]in the experiment payload. - Inform Pete in O-N Live Onboarding Experiment Details once experiment name is confirmed.
Resolved / Dismissed
- GJ6c — No longer required.
- GJ3 — Hide address bar + toolbar for "Try visiting a site" step (chat-path only).
- GJ2 — X button removed from chat-path dialogs (PR #4664).
- GJ4 — Copy updated to "Next, try visiting a site!" after AI.
- GJ8 — DuckAIQuery experiment toggle shows "Ask AI" (onboarding only; Search Experience screen keeps "Duck.ai").
- "Try fire tabs" flash — Suppressed via
isStillOnboarding()inDaxDialogsfor chat-path users. - GJ7 — Returning users guarded from experiment enrollment.
Key Files
| File | Purpose |
|---|---|
iOS/DuckDuckGo/DaxDialogs.swift |
Core onboarding dialog logic, chat-path phase state machine |
iOS/DuckDuckGo/OnboardingFlow/LinearOnboarding/OnboardingIntroViewModel.swift |
Experiment enrollment, step injection |
iOS/DuckDuckGo/NewTabPageViewController.swift |
Visit-site dialog presentation, bar hiding |
iOS/DuckDuckGo/MainViewController+DuckAIExperiment.swift |
Chat-path completion, EOJ dialog trigger |
iOS/Core/FeatureFlag.swift |
onboardingDuckAIQueryExperiment feature flag + cohorts |
iOS/DuckDuckGo/UserText.swift |
Onboarding copy strings |
iOS/DuckDuckGo/OnboardingFlow/LinearOnboarding/OnboardingView+DuckAIExperimentSearchContent.swift |
DuckAIQuery toggle + experiment UI |
iOS/DuckDuckGo/OnboardingFlow/ContextualOnboarding/Rebranding/RebrandedNewTabDaxDialogFactory.swift |
Chat-path dialog creation |
Copy Changes Summary
| Location | Value | Status |
|---|---|---|
DuckAIQueryExperiment.toggleAILabel (onboarding experiment toggle) |
Ask AI |
Done |
searchAndDuckAIOption (Search Experience screen) |
Toggle between\nSearch and Duck.ai |
Done |
Experiment Config
{
"experimentName": "TBD",
"targets": [{ "localeLanguage": "en", "localeCountry": "US" }],
"cohorts": ["control", "treatmentA", "treatmentB"]
}
Feature flag:
FeatureFlag.onboardingDuckAIQueryExperiment
Cohort type:FeatureFlag.DuckAIQueryExperimentCohort(.control,.treatmentA,.treatmentB)