Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
75d90c3
Refactor TOS feature flag setup into helper method
razvanlitianu Dec 18, 2025
d61bcfc
Fix default browser onboarding telemetry recording
razvanlitianu Dec 18, 2025
d2fae19
Record dismiss_pressed when default browser popup is dismissed
razvanlitianu Dec 18, 2025
cdbf039
Revert changes to LaunchScreenViewModelTests.swift
razvanlitianu Dec 18, 2025
fa068e1
Add issue #31366 and PR #31375 links to onboarding metrics
razvanlitianu Dec 18, 2025
74d8a41
Add issue #31366 to data_reviews for go_to_settings_pressed metric
razvanlitianu Dec 18, 2025
639217e
Add telemetry recording for OnboardingInstructionPopupViewController
razvanlitianu Dec 18, 2025
715d1a3
Remove unused hasDefaultBrowserCard function
razvanlitianu Dec 18, 2025
5dad279
Add telemetry recording for OnboardingInstructionPopupViewController
razvanlitianu Dec 18, 2025
78e5801
Remove dismiss_pressed check and hasDefaultBrowserCard function
razvanlitianu Dec 19, 2025
f43eedb
Remove dismiss_pressed check and hasDefaultBrowserCard function
razvanlitianu Dec 19, 2025
6b30929
Keep only latest links in go_to_settings_pressed and dismiss_pressed …
razvanlitianu Dec 19, 2025
bcfc498
Restore TelemetryWrapper usage in DefaultBrowserOnboardingViewController
razvanlitianu Dec 19, 2025
e1ef36d
Fix SwiftLint: align TelemetryWrapper.recordEvent parameters vertically
razvanlitianu Dec 19, 2025
158a59b
Make telemetry utility non-optional in OnboardingService and add unit…
razvanlitianu Dec 19, 2025
6d1768d
Revert formatting changes and preserve original line positions
razvanlitianu Dec 19, 2025
6657271
Restore multi-line format for goToSettingsDefaultBrowserOnboarding te…
razvanlitianu Dec 19, 2025
2bb1b0a
Fix memory leak in LaunchCoordinator by making qrCodeNavigationHandle…
razvanlitianu Dec 19, 2025
69b5f05
Restore previously deleted bugs and data_reviews links in onboarding …
razvanlitianu Dec 19, 2025
a31aa67
Merge remote-tracking branch 'origin/main' into rlitianu/fix-default-…
razvanlitianu Dec 19, 2025
70c9525
Remove unused default_browser_card dismiss_pressed and go_to_settings…
razvanlitianu Dec 22, 2025
7df9f89
Update default browser onboarding telemetry to use event metrics with…
razvanlitianu Dec 22, 2025
57c6363
Apply changes for benchmark PR
tomerqodo Jan 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ public class OnboardingBottomSheetViewController: UIViewController,
/// The last calculated height for the bottom sheet custom detent.
private var lastCalculatedHeight: CGFloat = 0
private var child: UIViewController?
/// Closure called when the bottom sheet is dismissed via the close button
public var onDismiss: (() -> Void)?

private lazy var closeButton: UIButton = .build {
$0.addAction(UIAction(handler: { [weak self] _ in
self?.onDismiss?()
self?.dismiss(animated: true)
}), for: .touchUpInside)
if #available(iOS 26, *) {
Expand Down
34 changes: 20 additions & 14 deletions firefox-ios/Client/Coordinators/Launch/LaunchCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ final class LaunchCoordinator: BaseCoordinator,
let windowUUID: WindowUUID
let themeManager: ThemeManager = AppContainer.shared.resolve()
weak var parentCoordinator: LaunchCoordinatorDelegate?
private var onboardingService: OnboardingService?

init(router: Router,
windowUUID: WindowUUID,
Expand Down Expand Up @@ -236,17 +237,6 @@ final class LaunchCoordinator: BaseCoordinator,
router.present(viewController, animated: false)
}

private lazy var onboardingService: OnboardingService = {
OnboardingService(
windowUUID: windowUUID,
profile: profile,
themeManager: themeManager,
delegate: self,
navigationDelegate: self,
qrCodeNavigationHandler: self
)
}()

// MARK: - Intro
@MainActor
private func presentModernIntroOnboarding(with manager: IntroScreenManagerProtocol,
Expand All @@ -264,11 +254,23 @@ final class LaunchCoordinator: BaseCoordinator,
onboardingVariant: manager.onboardingVariant
)

// Create onboardingService and store it directly - don't create local variable
self.onboardingService = OnboardingService(
windowUUID: windowUUID,
profile: profile,
themeManager: themeManager,
delegate: self,
navigationDelegate: self,
qrCodeNavigationHandler: self
)
self.onboardingService?.telemetryUtility = telemetryUtility

let flowViewModel = OnboardingFlowViewModel<OnboardingKitCardInfoModel>(
onboardingCards: onboardingModel.cards,
skipText: .Onboarding.LaterAction,
onActionTap: { @MainActor [weak self] action, cardName, completion in
self?.onboardingService.handleAction(
guard let onboardingService = self?.onboardingService else { return }
onboardingService.handleAction(
action,
from: cardName,
cards: onboardingModel.cards,
Expand All @@ -277,7 +279,8 @@ final class LaunchCoordinator: BaseCoordinator,
)
},
onMultipleChoiceActionTap: { [weak self] action, cardName in
self?.onboardingService.handleMultipleChoiceAction(
guard let onboardingService = self?.onboardingService else { return }
onboardingService.handleMultipleChoiceAction(
action,
from: cardName
)
Expand All @@ -286,6 +289,7 @@ final class LaunchCoordinator: BaseCoordinator,
guard let self = self else { return }
manager.didSeeIntroScreen()
SearchBarLocationSaver().saveUserSearchBarLocation(profile: profile)
self.onboardingService = nil
parentCoordinator?.didFinishLaunch(from: self)
}
)
Expand All @@ -309,7 +313,9 @@ final class LaunchCoordinator: BaseCoordinator,
)
}

flowViewModel.onDismiss = { cardName in
flowViewModel.onDismiss = { [weak self] cardName in
guard let self = self else { return }
self.onboardingService = nil
telemetryUtility.sendDismissOnboardingTelemetry(from: cardName)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@ final class OnboardingTelemetryUtility: OnboardingTelemetryProtocol {
gleanWrapper.recordEvent(for: GleanMetrics.Onboarding.closeTap, extras: extras)
}

func sendGoToSettingsButtonTappedTelemetry() {
let extras = GleanMetrics.OnboardingDefaultBrowserSheet.GoToSettingsButtonTappedExtra(
onboardingVariant: onboardingVariant.rawValue
)
gleanWrapper.recordEvent(for: GleanMetrics.OnboardingDefaultBrowserSheet.goToSettingsButtonTapped, extras: extras)
}

func sendDismissButtonTappedTelemetry() {
let extras = GleanMetrics.OnboardingDefaultBrowserSheet.DismissButtonTappedExtra(
onboardingVariant: onboardingVariant.rawValue
)
gleanWrapper.recordEvent(for: GleanMetrics.OnboardingDefaultBrowserSheet.dismissButtonTapped, extras: extras)
}

private struct BaseExtras {
let cardType: String
let flowType: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,20 @@ extension OnboardingCardDelegate where Self: OnboardingViewControllerProtocol,
let instructionsVC = OnboardingInstructionPopupViewController(
viewModel: popupViewModel,
windowUUID: windowUUID,
buttonTappedFinishFlow: {
self.advance(
buttonTappedFinishFlow: { [weak self] in
self?.advance(
numberOfPages: 1,
from: name,
completionIfLastCard: completionIfLastCard
)
self?.viewModel.telemetryUtility.sendGoToSettingsButtonTappedTelemetry()
}
)

let bottomSheetVC = OnboardingBottomSheetViewController(windowUUID: windowUUID)
bottomSheetVC.onDismiss = { [weak self] in
self?.viewModel.telemetryUtility.sendDismissButtonTappedTelemetry()
}
bottomSheetVC.configure(
closeButtonModel: CloseButtonViewModel(
a11yLabel: .CloseButtonTitle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class OnboardingService: FeatureFlaggable {
// MARK: - Properties
private weak var delegate: OnboardingServiceDelegate?
private weak var navigationDelegate: OnboardingNavigationDelegate?
private let qrCodeNavigationHandler: QRCodeNavigationHandler?
private weak var qrCodeNavigationHandler: QRCodeNavigationHandler?
private var hasRegisteredForDefaultBrowserNotification = false
private var userDefaults: UserDefaultsInterface
private var windowUUID: WindowUUID
Expand All @@ -28,6 +28,7 @@ final class OnboardingService: FeatureFlaggable {
private let defaultApplicationHelper: ApplicationHelper
private let notificationCenter: NotificationProtocol
private let searchBarLocationSaver: SearchBarLocationSaverProtocol
weak var telemetryUtility: OnboardingTelemetryProtocol?

init(
userDefaults: UserDefaultsInterface = UserDefaults.standard,
Expand Down Expand Up @@ -198,6 +199,7 @@ final class OnboardingService: FeatureFlaggable {
activityEventHelper.chosenOptions.insert(.setAsDefaultBrowser)
activityEventHelper.updateOnboardingUserActivationEvent()
registerForNotification()
telemetryUtility?.sendGoToSettingsButtonTappedTelemetry()
defaultApplicationHelper.openSettings()
}

Expand All @@ -213,6 +215,7 @@ final class OnboardingService: FeatureFlaggable {
}

private func handleOpenIosFxSettings(from cardName: String) {
telemetryUtility?.sendGoToSettingsButtonTappedTelemetry()
defaultApplicationHelper.openSettings()
}

Expand Down Expand Up @@ -339,7 +342,10 @@ final class OnboardingService: FeatureFlaggable {
let instructionsVC = OnboardingInstructionPopupViewController(
viewModel: popupViewModel,
windowUUID: windowUUID,
buttonTappedFinishFlow: completion
buttonTappedFinishFlow: { [weak self] in
self?.telemetryUtility?.sendGoToSettingsButtonTappedTelemetry()
completion()
}
Copy link

Choose a reason for hiding this comment

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

Missing dismiss telemetry in OnboardingService popup

Medium Severity

The createDefaultBrowserPopupViewController method in OnboardingService does not set the bottomSheetVC.onDismiss callback to record dismiss telemetry. In contrast, OnboardingCardDelegate.presentDefaultBrowserPopup properly sets bottomSheetVC.onDismiss to call sendDismissButtonTappedTelemetry(). This means dismiss button taps in the modern onboarding flow (which uses OnboardingService) won't be recorded, defeating part of the PR's purpose to add telemetry for dismiss actions.

Fix in Cursor Fix in Web

)

let bottomSheetVC = OnboardingBottomSheetViewController(windowUUID: windowUUID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ protocol OnboardingTelemetryProtocol: AnyObject {
with action: OnboardingMultipleChoiceAction
)
func sendDismissOnboardingTelemetry(from cardName: String)
func sendGoToSettingsButtonTappedTelemetry()
func sendDismissButtonTappedTelemetry()
}
Original file line number Diff line number Diff line change
Expand Up @@ -328,12 +328,14 @@ extension IntroViewController: OnboardingCardDelegate {
introViewModel.chosenOptions.insert(.setAsDefaultBrowser)
introViewModel.updateOnboardingUserActivationEvent()
registerForNotification()
viewModel.telemetryUtility.sendGoToSettingsButtonTappedTelemetry()
DefaultApplicationHelper().openSettings()
case .openInstructionsPopup:
/// Setting default browser card action opens an instruction pop up instead of
/// setting a default browser action. TBD if the above code even still fires.
introViewModel.chosenOptions.insert(.setAsDefaultBrowser)
introViewModel.updateOnboardingUserActivationEvent()
registerForNotification()
presentDefaultBrowserPopup(
windowUUID: windowUUID,
from: cardName,
Expand All @@ -344,6 +346,7 @@ extension IntroViewController: OnboardingCardDelegate {
from: cardName,
selector: #selector(dismissPrivacyPolicyViewController))
case .openIosFxSettings:
viewModel.telemetryUtility.sendGoToSettingsButtonTappedTelemetry()
DefaultApplicationHelper().openSettings()
advance(numberOfPages: 1, from: cardName) {
self.showNextPageCompletionForLastCard()
Expand Down
61 changes: 0 additions & 61 deletions firefox-ios/Client/Glean/probes/metrics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -332,35 +332,6 @@ context_menu:

# Default browser card metrics
default_browser_card:
dismiss_pressed:
type: counter
description: |
Counts the number of times default browser card is dismissed.
bugs:
- https://github.com/mozilla-mobile/firefox-ios/issues/7151
data_reviews:
- https://github.com/mozilla-mobile/firefox-ios/pull/7245
- https://github.com/mozilla-mobile/firefox-ios/pull/9673
- https://github.com/mozilla-mobile/firefox-ios/pull/12334
- https://github.com/mozilla-mobile/firefox-ios/pull/14102
notification_emails:
- fx-ios-data-stewards@mozilla.com
expires: "2026-06-01"
go_to_settings_pressed:
type: counter
description: |
Counts the number of times the Go To Settings button on
default browser card is clicked.
bugs:
- https://github.com/mozilla-mobile/firefox-ios/issues/7151
data_reviews:
- https://github.com/mozilla-mobile/firefox-ios/pull/7245
- https://github.com/mozilla-mobile/firefox-ios/pull/9673
- https://github.com/mozilla-mobile/firefox-ios/pull/12334
- https://github.com/mozilla-mobile/firefox-ios/pull/14102
notification_emails:
- fx-ios-data-stewards@mozilla.com
expires: "2026-06-01"
evergreen_impression:
type: event
description: |
Expand All @@ -374,38 +345,6 @@ default_browser_card:
- fx-ios-data-stewards@mozilla.com
expires: "2026-06-01"

# Default browser onboarding metrics
default_browser_onboarding:
dismiss_pressed:
type: counter
description: |
Counts the number of times default browser onboarding is dismissed.
bugs:
- https://github.com/mozilla-mobile/firefox-ios/issues/7870
data_reviews:
- https://github.com/mozilla-mobile/firefox-ios/pull/7245
- https://github.com/mozilla-mobile/firefox-ios/pull/9673
- https://github.com/mozilla-mobile/firefox-ios/pull/12334
- https://github.com/mozilla-mobile/firefox-ios/pull/14102
notification_emails:
- fx-ios-data-stewards@mozilla.com
expires: "2026-06-01"
go_to_settings_pressed:
type: counter
description: |
Counts the number of times the Go To Settings button on
default browser onboarding is clicked.
bugs:
- https://github.com/mozilla-mobile/firefox-ios/issues/7870
data_reviews:
- https://github.com/mozilla-mobile/firefox-ios/pull/7245
- https://github.com/mozilla-mobile/firefox-ios/pull/9673
- https://github.com/mozilla-mobile/firefox-ios/pull/12334
- https://github.com/mozilla-mobile/firefox-ios/pull/14102
notification_emails:
- fx-ios-data-stewards@mozilla.com
expires: "2026-06-01"

app:
default_browser:
type: boolean
Expand Down
47 changes: 47 additions & 0 deletions firefox-ios/Client/Glean/probes/onboarding.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,50 @@ onboarding:
- fx-ios-data-stewards@mozilla.com
expires: "2026-01-01"

# Default Browser Sheet
onboarding.default_browser_sheet:
go_to_settings_button_tapped:
type: event
description: |
Records when the Go To Settings button on default browser onboarding
is clicked. This applies to both legacy and modern onboarding flows.
extra_keys:
onboarding_variant:
type: string
description: |
The onboarding variant (modern, legacy, or japan).
bugs:
- https://github.com/mozilla-mobile/firefox-ios/issues/7870
- https://github.com/mozilla-mobile/firefox-ios/issues/31366
data_reviews:
- https://github.com/mozilla-mobile/firefox-ios/pull/7245
- https://github.com/mozilla-mobile/firefox-ios/pull/9673
- https://github.com/mozilla-mobile/firefox-ios/pull/12334
- https://github.com/mozilla-mobile/firefox-ios/pull/14102
- https://github.com/mozilla-mobile/firefox-ios/pull/31375
notification_emails:
- fx-ios-data-stewards@mozilla.com
expires: "2026-06-01"
dismiss_button_tapped:
type: event
description: |
Records when default browser onboarding is dismissed.
This applies to both legacy and modern onboarding flows.
extra_keys:
onboarding_variant:
type: string
description: |
The onboarding variant (modern, legacy, or japan).
bugs:
- https://github.com/mozilla-mobile/firefox-ios/issues/7870
- https://github.com/mozilla-mobile/firefox-ios/issues/31366
data_reviews:
- https://github.com/mozilla-mobile/firefox-ios/pull/7245
- https://github.com/mozilla-mobile/firefox-ios/pull/9673
- https://github.com/mozilla-mobile/firefox-ios/pull/12334
- https://github.com/mozilla-mobile/firefox-ios/pull/14102
- https://github.com/mozilla-mobile/firefox-ios/pull/31375
notification_emails:
- fx-ios-data-stewards@mozilla.com
expires: "2026-06-01"

20 changes: 10 additions & 10 deletions firefox-ios/Client/Telemetry/TelemetryWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,6 @@ extension TelemetryWrapper {
case onboarding = "onboarding"
case upgradeOnboarding = "upgrade-onboarding"
// MARK: New Upgrade screen
case dismissDefaultBrowserCard = "default-browser-card"
case goToSettingsDefaultBrowserCard = "default-browser-card-go-to-settings"
case dismissDefaultBrowserOnboarding = "default-browser-onboarding"
case goToSettingsDefaultBrowserOnboarding = "default-browser-onboarding-go-to-settings"
case homeTabBannerEvergreen = "home-tab-banner-evergreen"
Expand Down Expand Up @@ -1119,22 +1117,24 @@ extension TelemetryWrapper {
extras: extras)
}
// MARK: Default Browser
case (.action, .tap, .dismissDefaultBrowserCard, _, _):
GleanMetrics.DefaultBrowserCard.dismissPressed.add()
case (.action, .tap, .goToSettingsDefaultBrowserCard, _, _):
GleanMetrics.DefaultBrowserCard.goToSettingsPressed.add()
case (.action, .open, .asDefaultBrowser, _, _):
GleanMetrics.App.openedAsDefaultBrowser.add()
case(.action, .tap, .engagementNotification, _, _):
GleanMetrics.Onboarding.engagementNotificationTapped.record()
case(.action, .cancel, .engagementNotification, _, _):
GleanMetrics.Onboarding.engagementNotificationCancel.record()
case (.action, .tap, .dismissDefaultBrowserOnboarding, _, _):
GleanMetrics.DefaultBrowserOnboarding.dismissPressed.add()
case (.action, .tap, .goToSettingsDefaultBrowserOnboarding, _, _):
GleanMetrics.DefaultBrowserOnboarding.goToSettingsPressed.add()
case (.information, .view, .homeTabBannerEvergreen, _, _):
GleanMetrics.DefaultBrowserCard.evergreenImpression.record()
case (.action, .tap, .dismissDefaultBrowserOnboarding, _, _):
let extras = GleanMetrics.OnboardingDefaultBrowserSheet.DismissButtonTappedExtra(
onboardingVariant: "legacy"
)
GleanMetrics.OnboardingDefaultBrowserSheet.dismissButtonTapped.record(extras)
case (.action, .tap, .goToSettingsDefaultBrowserOnboarding, _, _):
let extras = GleanMetrics.OnboardingDefaultBrowserSheet.GoToSettingsButtonTappedExtra(
onboardingVariant: "legacy"
)
GleanMetrics.OnboardingDefaultBrowserSheet.goToSettingsButtonTapped.record(extras)
// MARK: Downloads
case(.action, .tap, .downloadNowButton, _, _):
GleanMetrics.Downloads.downloadNowButtonTapped.record()
Expand Down
Loading