# iOS: Chat-Path Onboarding — Tracker Blocking Demo > **Asana:** [Ship Review task](https://app.asana.com/1/137249556945/task/1214147157456478) > **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: 1. "Try visiting a site!" dialog (address bar + toolbar hidden) 2. Trackers-blocked dialog after a site loads 3. "You've got this!" EOJ completion dialog 4. 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](https://github.com/duckduckgo/apple-browsers/pull/4544) | `demo-tracker-blocking-onboarding` | Open — needs fixes | | [#4591](https://github.com/duckduckgo/apple-browsers/pull/4591) | `demo-tracker-blocking-onboarding-ui-polish` | Approved — needs rebase | | [#4664](https://github.com/duckduckgo/apple-browsers/pull/4664) | `demo-tracker-blocking-onboarding-chat-path-dialog-polish` | Open — needs fix | | [#4668](https://github.com/duckduckgo/apple-browsers/pull/4668) | `demo-tracker-blocking-onboarding-uti-flow` | Open — needs fix | | [#4855](https://github.com/duckduckgo/apple-browsers/pull/4855) | `demo-tracker-blocking-onboarding-sr-feedback` | Open — needs fixes | --- ## Required Changes ### PR #4544 — main chat-path branch - [x] **Danger CI**: No `@UserDefaultsWrapper` usage remains. - [x] **Mock refactor** (alessandroboron): `MockDaxDialogsSettings.chatPathPhase` is a plain stored property, directly settable in tests. - [x] **Sync restore exclusion**: Uncommented `guard case .introDialog(isReturningUser: false) = introSteps.first` in `OnboardingIntroViewModel.insertExperimentStepIfNeeded()`. Excludes all returning users (including sync-restore) from experiment enrollment. - [x] **`return .treatmentA` override**: Removed hardcoded early return from `resolveDuckAIQueryExperimentCohortID()`. Now routes through the feature flagger. - [x] **Pixels**: `onboardingChatPathTryVisitSiteUnique` and `onboardingChatPathTrackersBlockedUnique` defined in `PixelEvent.swift` with matching `onboarding.json5` entries. No overlap with PR #4687. ### PR #4664 — chat-path dialog polish - [x] **Title scope** (alessandroboron): Fixed in commit `c15122a1b0` — `RebrandedNewTabDaxDialogFactory.createSubsequentDialog` uses the correct title per chat-path vs standard path. ### PR #4668 — UTI onboarding flow fixes - [x] Dialog position, dismiss on navigation, UTI bar, completion path — all resolved. - [x] **Hardcoded UTI override**: `FeatureFlag.swift` `.unifiedToggleInput` confirmed correct — `Config(source: .remoteReleasable(...))`, no `defaultValue: .enabled`. ### PR #4855 — sr-feedback - [x] **Hide toolbar + address bar**: `NewTabPageViewController` now calls `chromeDelegate?.setBarsHidden(true/false, animated: false, customAnimationDuration: nil)` in the show block, `dismiss()`, and `dismissHostingController`. Replaces previous `setNavigationBarHidden` + `setChatPathVisitSiteControlsLocked` pair. - [x] **Use delegate**: Added `newTabPageControllerCurrentTabIsLoading(_ controller:) -> Bool` to `NewTabPageControllerDelegate` (default `false`). Implemented in `MainViewController` as `currentTab?.isLoading == true`. All `(parent as? MainViewController)?` casts removed from `NewTabPageViewController`. - [x] **Loading guard placement**: Folded into the outer `if` condition via the new delegate method. No orphaned lock possible. - [x] **Revert Search Experience screen copy**: `UserText.swift` `searchAndDuckAIOption` reverted to `"Toggle between\nSearch and Duck.ai"`. All 26 lproj files updated. - [x] **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](https://app.asana.com/1/137249556945/task/1214601039604921) 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()` in `DaxDialogs` for 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 ```json { "experimentName": "TBD", "targets": [{ "localeLanguage": "en", "localeCountry": "US" }], "cohorts": ["control", "treatmentA", "treatmentB"] } ``` > Feature flag: `FeatureFlag.onboardingDuckAIQueryExperiment` > Cohort type: `FeatureFlag.DuckAIQueryExperimentCohort` (`.control`, `.treatmentA`, `.treatmentB`)