From 87605bdb30b946b995e9a42b747d8bc443ae0bd1 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 13 Aug 2026 16:54:53 -0300 Subject: [PATCH 1/2] fix(onboarding): let segment overrides match the entry decision The entry decision identifies with an empty identifier and no traits, so no trait-based segment override on onboarding_quickstart_flow could ever match it. That is why the flagsmith_team override never applied, and the team never saw the variant it targets. Pass the signed-in user's email as a transient trait so overrides that match on email can apply. Email is the only trait available before the organisation exists, so overrides on plan or organisation still cannot match. Bucketing is unaffected: the percentage split is keyed on the identifier the API assigns, not on traits. Co-Authored-By: Claude Opus 5 (1M context) --- frontend/common/utils/onboardingEntry.ts | 8 ++++++-- frontend/web/components/App.js | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/frontend/common/utils/onboardingEntry.ts b/frontend/common/utils/onboardingEntry.ts index df45626196e1..4cc2af116d47 100644 --- a/frontend/common/utils/onboardingEntry.ts +++ b/frontend/common/utils/onboardingEntry.ts @@ -20,9 +20,13 @@ export type OnboardingEntryDecision = { * the logged-in user, and the routing it should have driven has happened. * Call `persistOnboardingEntry` with an accepted decision. */ -export async function decideOnboardingEntry(): Promise { +export async function decideOnboardingEntry( + email?: string, +): Promise { + // No trait means no segment override can match, and email is the only trait + // we have before the organisation exists. // @ts-expect-error transient is missing from the SDK's identify type - await flagsmith.identify('', {}, true) + await flagsmith.identify('', email ? { email } : {}, true) const flag = flagsmith.getExperimentFlag('onboarding_quickstart_flow') const identifier = flagsmith.getContext().identity?.identifier const variant: OnboardingVariant = diff --git a/frontend/web/components/App.js b/frontend/web/components/App.js index 4faaf15696a6..e1d3adb9ad1f 100644 --- a/frontend/web/components/App.js +++ b/frontend/web/components/App.js @@ -151,7 +151,9 @@ const App = class extends Component { // instead of blocking the redirect. Promise.race([ AccountStore.getUser()?.isGettingStarted - ? decideOnboardingEntry().catch(() => null) + ? decideOnboardingEntry(AccountStore.getUser()?.email).catch( + () => null, + ) : Promise.resolve(null), new Promise((resolve) => setTimeout(() => resolve(null), 2000)), ]).then((decision) => { From 2b78a288f91dfe4a6ebb8b855a8fb68c37d1b6ae Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Fri, 14 Aug 2026 10:16:53 -0300 Subject: [PATCH 2/2] docs(onboarding): say why the entry decision passes the email trait Co-Authored-By: Claude Opus 5 (1M context) --- frontend/common/utils/onboardingEntry.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/common/utils/onboardingEntry.ts b/frontend/common/utils/onboardingEntry.ts index 4cc2af116d47..fcb6ed90c453 100644 --- a/frontend/common/utils/onboardingEntry.ts +++ b/frontend/common/utils/onboardingEntry.ts @@ -23,8 +23,8 @@ export type OnboardingEntryDecision = { export async function decideOnboardingEntry( email?: string, ): Promise { - // No trait means no segment override can match, and email is the only trait - // we have before the organisation exists. + // Only used to match segment overrides, not for bucketing. An override on + // another trait needs that trait passed here too. // @ts-expect-error transient is missing from the SDK's identify type await flagsmith.identify('', email ? { email } : {}, true) const flag = flagsmith.getExperimentFlag('onboarding_quickstart_flow')