Skip to content

[Segmented Onboarding] Experiment setup and metrics - #9711

Open
LukasPaczos wants to merge 1 commit into
fix/lpaczos/count-prompts-toward-search-metricfrom
feature/lpaczos/segmented-onboarding/experiment-and-metrics
Open

[Segmented Onboarding] Experiment setup and metrics#9711
LukasPaczos wants to merge 1 commit into
fix/lpaczos/count-prompts-toward-search-metricfrom
feature/lpaczos/segmented-onboarding/experiment-and-metrics

Conversation

@LukasPaczos

@LukasPaczos LukasPaczos commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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

Description

Steps to test this PR

logs

  • Filter logcat by message~:"onboardingFlowByDownloadReasonExperiment".

regression

  • Clear downloads dir:
adb shell rm -rf /sdcard/Download/DuckDuckGo
  • Clean install.
  • Verify onboarding launches and no onboardingFlowByDownloadReasonExperiment pixels fire.

control

  • Create privacy-config/privacy-config-internal/local-config-patches/review_patch.json:
[
  {
    "op": "add",
    "path": "/features/segmentedOnboarding",
    "value": {
      "state": "enabled",
      "features": {
        "onboardingFlowByDownloadReasonExperiment": {
          "state": "enabled",
          "cohorts": [
            {
              "name": "control",
              "weight": 1
            },
            {
              "name": "treatment",
              "weight": 0
            }
          ]
        }
      }
    }
  },
  {
    "op": "replace",
    "path": "/features/onboardingPrompts/features/addToDockAndWidgetExperimentJul25/state",
    "value": "disabled"
  },
  {
    "op": "add",
    "path": "/features/onboardingPrompts/hash",
    "value": "patched"
  },
  {
    "op": "replace",
    "path": "/version",
    "value": "90000000000001"
  }
]
  • Create privacy-config/privacy-config-internal/local.properties:
config_patches=privacy-config/privacy-config-internal/local-config-patches/review_patch.json
  • Apply below diff:
diff --git a/privacy-config/privacy-config-impl/src/main/res/raw/privacy_config.json b/privacy-config/privacy-config-impl/src/main/res/raw/privacy_config.json
index b75a2db48f..e2514ade54 100644
--- a/privacy-config/privacy-config-impl/src/main/res/raw/privacy_config.json
+++ b/privacy-config/privacy-config-impl/src/main/res/raw/privacy_config.json
@@ -954,3 +954,3 @@
                 "addToDockAndWidgetExperimentJul25": {
-                    "state": "enabled",
+                    "state": "disabled",
                     "cohorts": [
@@ -975,2 +975,20 @@
             }
+        },
+        "segmentedOnboarding": {
+            "state": "enabled",
+            "features": {
+                "onboardingFlowByDownloadReasonExperiment": {
+                    "state": "enabled",
+                    "cohorts": [
+                        {
+                            "name": "control",
+                            "weight": 1
+                        },
+                        {
+                            "name": "treatment",
+                            "weight": 0
+                        }
+                    ]
+                }
+            }
         }
  • Clear downloads dir:
adb shell rm -rf /sdcard/Download/DuckDuckGo
  • Clean install.
  • Verify the default onboarding flow runs, no download-choice screen.
  • Verify experiment_enroll_onboardingFlowByDownloadReasonExperiment_control pixel was sent.
  • Walk the onboarding till the end.
  • Verify pixel with metric=onboarding_completed was sent.

treatment

  • Update privacy_config.json and review_patch.json:
    • control to 0
    • treatment to 1
  • Clear downloads dir:
adb shell rm -rf /sdcard/Download/DuckDuckGo
  • Clean install.
  • Verify experiment_enroll_onboardingFlowByDownloadReasonExperiment_treatment pixel was sent.
  • Pick a download reason.
  • Verify pixel with metric=download_reason_selected_<reason> was sent
  • Walk the onboarding till the end.
  • Verify pixel with metric=onboarding_completed was sent.
  • Increment the date on the device by 5-6 days.
  • Go back to the app and send a new chat prompt.
  • Verify metric pixels were sent:
    • metric=duck_ai_new_chat
    • metric=duck_ai_prompt_sent
    • metric=search
    • metric=download_reason_search_retention_<reason>

returning user

  • Do not change the config, do not clear the downloads folder.
  • Clean install the app.
  • Verify onboarding launches and no onboardingFlowByDownloadReasonExperiment pixels fire.

clean up

  • Delete privacy-config/privacy-config-internal/local-config-patches/review_patch.json and revert changes in privacy-config/privacy-config-internal/local.properties.

Note

Medium Risk
Touches new-user onboarding branching, experiment enrollment gates, and a breaking analytics param rename (variant_download_reason); incorrect persistence or enrollment could skew experiment data or CTA behavior on segmented paths.

Overview
Adds native experiment support for onboardingFlowByDownloadReasonExperiment (control/treatment) with metrics for completion, per-reason selection, and D5–7 search retention by download-reason segment.

Telemetry rename: onboarding pixels now use shared param onboardingDownloadReasonVariant (variant_download_reason) instead of onboardingSegmentedVariant (variant_segmented).

State model: replaces SegmentedOnboardingPath with DownloadReasonSelection persisted in OnboardingStore; download reason is written before the download-choice clicked pixel and cleared when a new linear onboarding run starts so attribution and retention metrics don’t leak from abandoned runs.

Enrollment: SegmentedOnboardingExperimentManager actually enrolls via SegmentedOnboardingFeatureToggles, with prerequisites (brand design update, config-driven dialogs, no conflicting experiments, non-reinstall). Metrics fire on established stage, reason confirmation, and ATB search/Duck.ai retention refreshes.

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

@LukasPaczos
LukasPaczos force-pushed the feature/lpaczos/segmented-onboarding/experiment-and-metrics branch from d7ac72f to a348288 Compare September 4, 2026 09:09
@LukasPaczos
LukasPaczos force-pushed the feature/lpaczos/segmented-onboarding/experiment-and-metrics branch 3 times, most recently from b2aab91 to 6bdf2ef Compare September 4, 2026 13:13
@LukasPaczos
LukasPaczos marked this pull request as ready for review September 4, 2026 13:45
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

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

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

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 6bdf2ef. Configure here.

@LukasPaczos
LukasPaczos force-pushed the feature/lpaczos/segmented-onboarding/experiment-and-metrics branch 3 times, most recently from 902d575 to d8139bf Compare September 4, 2026 13:52
@LukasPaczos
LukasPaczos force-pushed the feature/lpaczos/segmented-onboarding/experiment-and-metrics branch from d8139bf to 58a7ef0 Compare September 4, 2026 14:10
/**
* The branch the user picked on the download reason step. Only enumerates a subset of paths that can have side effects on contextual CTAs.
*/
enum class SegmentedOnboardingPath {

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.

It's a bit confusing that we deleted this enum and we now use the DownloadReasonSelection instad. Not a blocker for this PR, just trying to understand the reason behind.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Both of these enums represent the same information in the end. I initially introduced SegmentedOnboardingPath because it only handled a subset of paths, but ended up just folding them together now to avoid unnecessary mapping.

onboardingBrandDesignUpdateToggles.configDrivenDialogs().isEnabled() &&
onboardingBrandDesignUpdateToggles.brandDesignUpdate().isEnabled() &&
onboardingBrandDesignUpdateToggles.configDrivenDialogs().isEnabled() &&
!onboardingPromptsToggles.addToDockAndWidgetExperimentJul25().isEnabled() &&

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.

Nit: Do we need all these checks?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In theory, yes. In practice we're unlikely to collide with things like the widget/dock experiment, but I guess it doesn't hurt to have the check in place.

type = MetricType.NORMAL,
value = "",
toggle = toggles.onboardingFlowByDownloadReasonExperiment(),
conversionWindow = listOf(ConversionWindow(lowerWindow = 0, upperWindow = 0)),

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.

In the previous experiment we also measured the onboarding completion on d0-14, to get a "total" completion rate, not just the one on d0. Should we add it here as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

d0-14 is not part of the experiment design in this case, wasn't on iOS either.

@catalinradoiu catalinradoiu 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.

Looks good and works as expected 👍

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.

2 participants