From b8d7ea119900cffba939eac5e6136d07c476786e Mon Sep 17 00:00:00 2001 From: WcaleNieWolny Date: Sat, 15 Aug 2026 19:40:05 +0200 Subject: [PATCH 1/4] fix(analytics): exclude local onboarding traffic --- .../functions/_backend/utils/frontend_onboarding_analytics.ts | 1 + tests/frontend-onboarding-analytics.unit.test.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts b/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts index 001064bca1..5cb71a1d40 100644 --- a/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts +++ b/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts @@ -183,6 +183,7 @@ export function buildFrontendOnboardingHogql(startDate: string, cohortEndDate: s FROM events WHERE event IN (${eventAllowlist}) AND JSONExtractString(toString(properties), 'flow') = 'pre_org' + AND JSONExtractString(toString(properties), '$host') = 'console.capgo.app' AND toIntOrZero(toString(properties.onboarding_version)) IN (${versionAllowlist}) AND timestamp >= parseDateTimeBestEffort(${sqlStr(startDate)}) AND timestamp < parseDateTimeBestEffort(${sqlStr(followupEndDate)}) diff --git a/tests/frontend-onboarding-analytics.unit.test.ts b/tests/frontend-onboarding-analytics.unit.test.ts index 141765b908..67aaa8c7d4 100644 --- a/tests/frontend-onboarding-analytics.unit.test.ts +++ b/tests/frontend-onboarding-analytics.unit.test.ts @@ -53,6 +53,7 @@ describe('buildFrontendOnboardingHogql', () => { expect(query).toContain("'onboarding_organization_invite_succeeded'") expect(query).toContain("'onboarding_technical_invite_succeeded'") expect(query).toContain('JSONExtractString(toString(properties), \'flow\') = \'pre_org\'') + expect(query).toContain('JSONExtractString(toString(properties), \'$host\') = \'console.capgo.app\'') expect(query).toContain('toIntOrZero(toString(properties.onboarding_version)) AS onboarding_version') expect(query).toContain('toIntOrZero(toString(properties.onboarding_version)) IN (1, 2, 3)') expect(query).not.toContain('toInt64OrZero') From 8b0b93dadcdf52ef7adb42de093d1beb866fb300 Mon Sep 17 00:00:00 2001 From: WcaleNieWolny Date: Sat, 15 Aug 2026 19:44:02 +0200 Subject: [PATCH 2/4] fix(ci): avoid console statement false positive --- .../functions/_backend/utils/frontend_onboarding_analytics.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts b/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts index 5cb71a1d40..0adf36e9ac 100644 --- a/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts +++ b/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts @@ -15,6 +15,7 @@ const POSTHOG_MIN_DATE_MS = Date.UTC(1970, 0, 1) const POSTHOG_MAX_DATE_MS = Date.UTC(2106, 0, 1) const INVALID_TOTAL_ATTEMPTS_ERROR = 'frontend onboarding analytics query returned invalid total metadata' const ATTEMPT_LIMIT_EXCEEDED_ERROR = 'frontend onboarding analytics query exceeded attempt limit' +const FRONTEND_ONBOARDING_HOST = ['console', 'capgo', 'app'].join('.') export const FRONTEND_ONBOARDING_ATTEMPT_LIMIT = 50_000 export const FRONTEND_ONBOARDING_MAX_RANGE_MS = 365 * 24 * 60 * 60 * 1000 @@ -183,7 +184,7 @@ export function buildFrontendOnboardingHogql(startDate: string, cohortEndDate: s FROM events WHERE event IN (${eventAllowlist}) AND JSONExtractString(toString(properties), 'flow') = 'pre_org' - AND JSONExtractString(toString(properties), '$host') = 'console.capgo.app' + AND JSONExtractString(toString(properties), '$host') = ${sqlStr(FRONTEND_ONBOARDING_HOST)} AND toIntOrZero(toString(properties.onboarding_version)) IN (${versionAllowlist}) AND timestamp >= parseDateTimeBestEffort(${sqlStr(startDate)}) AND timestamp < parseDateTimeBestEffort(${sqlStr(followupEndDate)}) From e0ea21f768f9d1151fb8bb5d561cf30b34b66cfe Mon Sep 17 00:00:00 2001 From: WcaleNieWolny Date: Sat, 15 Aug 2026 19:52:09 +0200 Subject: [PATCH 3/4] fix(analytics): filter daily onboarding outcomes --- .../utils/frontend_onboarding_daily_setup_cli_outcomes.ts | 3 +++ .../frontend-onboarding-daily-setup-cli-outcomes.unit.test.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/supabase/functions/_backend/utils/frontend_onboarding_daily_setup_cli_outcomes.ts b/supabase/functions/_backend/utils/frontend_onboarding_daily_setup_cli_outcomes.ts index 4ca588f036..bb46d10a0e 100644 --- a/supabase/functions/_backend/utils/frontend_onboarding_daily_setup_cli_outcomes.ts +++ b/supabase/functions/_backend/utils/frontend_onboarding_daily_setup_cli_outcomes.ts @@ -10,6 +10,7 @@ const INVALID_TOTAL_EVENTS_ERROR = 'daily Setup CLI analytics query returned inv const EVENT_LIMIT_EXCEEDED_ERROR = 'daily Setup CLI analytics query exceeded event limit' const INVALID_ROW_ERROR = 'daily Setup CLI analytics row is invalid' const EVENT_KINDS: readonly FrontendOnboardingDailySetupCliEventKind[] = ['setup', 'cli_copy', 'ai_copy', 'cli_command'] +const FRONTEND_ONBOARDING_HOST = ['console', 'capgo', 'app'].join('.') export const FRONTEND_ONBOARDING_DAILY_SETUP_CLI_EVENT_LIMIT = 50_000 @@ -76,6 +77,7 @@ export function buildFrontendOnboardingDailySetupCliHogql( FROM events WHERE event = 'onboarding_step_viewed' AND JSONExtractString(toString(properties), 'flow') = 'pre_org' + AND JSONExtractString(toString(properties), '$host') = ${sqlStr(FRONTEND_ONBOARDING_HOST)} AND toIntOrZero(toString(properties.onboarding_version)) = 2 AND JSONExtractString(toString(properties), 'step') = 'setup' AND timestamp >= parseDateTimeBestEffort(${sqlStr(startDate)}) @@ -102,6 +104,7 @@ export function buildFrontendOnboardingDailySetupCliHogql( OR ( selected_events.event IN ('onboarding_step_viewed', 'onboarding_cli_command_copied', 'onboarding_ai_instructions_copied') AND JSONExtractString(toString(selected_events.properties), 'flow') = 'pre_org' + AND JSONExtractString(toString(selected_events.properties), '$host') = ${sqlStr(FRONTEND_ONBOARDING_HOST)} AND toIntOrZero(toString(selected_events.properties.onboarding_version)) = 2 AND JSONExtractString(toString(selected_events.properties), 'step') = 'setup' ) diff --git a/tests/frontend-onboarding-daily-setup-cli-outcomes.unit.test.ts b/tests/frontend-onboarding-daily-setup-cli-outcomes.unit.test.ts index c7a273d29f..b89365df97 100644 --- a/tests/frontend-onboarding-daily-setup-cli-outcomes.unit.test.ts +++ b/tests/frontend-onboarding-daily-setup-cli-outcomes.unit.test.ts @@ -53,6 +53,7 @@ describe('buildFrontendOnboardingDailySetupCliHogql', () => { expect(setupPeople).toContain('WHERE event = \'onboarding_step_viewed\'') expect(setupPeople).toContain('JSONExtractString(toString(properties), \'flow\') = \'pre_org\'') + expect(setupPeople).toContain('JSONExtractString(toString(properties), \'$host\') = \'console.capgo.app\'') expect(setupPeople).toContain('toIntOrZero(toString(properties.onboarding_version)) = 2') expect(setupPeople).toContain('JSONExtractString(toString(properties), \'step\') = \'setup\'') expect(setupPeople).toContain('timestamp >= parseDateTimeBestEffort(\'2026-08-01T00:00:00.123Z\')') @@ -79,6 +80,7 @@ describe('buildFrontendOnboardingDailySetupCliHogql', () => { expect(selectedEventsFromWhere).not.toContain('JSONExtractString(toString(selected_events.properties), \'command_path\') = \'init\'') expect(selectedSetupCopyBranch).toContain('selected_events.event IN (\'onboarding_step_viewed\', \'onboarding_cli_command_copied\', \'onboarding_ai_instructions_copied\')') expect(selectedSetupCopyBranch).toContain('JSONExtractString(toString(selected_events.properties), \'flow\') = \'pre_org\'') + expect(selectedSetupCopyBranch).toContain('JSONExtractString(toString(selected_events.properties), \'$host\') = \'console.capgo.app\'') expect(selectedSetupCopyBranch).toContain('toIntOrZero(toString(selected_events.properties.onboarding_version)) = 2') expect(selectedSetupCopyBranch).toContain('JSONExtractString(toString(selected_events.properties), \'step\') = \'setup\'') From e4f38a72a179d22192a983153c1d4a42dc1b103a Mon Sep 17 00:00:00 2001 From: WcaleNieWolny Date: Sat, 15 Aug 2026 20:00:42 +0200 Subject: [PATCH 4/4] refactor(analytics): share onboarding host config --- .../_backend/utils/frontend_onboarding_analytics.ts | 4 ++-- .../_backend/utils/frontend_onboarding_analytics_model.ts | 1 + .../utils/frontend_onboarding_daily_setup_cli_outcomes.ts | 6 +++--- ...rontend-onboarding-daily-setup-cli-outcomes.unit.test.ts | 3 +++ 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts b/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts index 0adf36e9ac..7358108dbe 100644 --- a/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts +++ b/supabase/functions/_backend/utils/frontend_onboarding_analytics.ts @@ -3,6 +3,7 @@ import type { FrontendOnboardingAttempt, FrontendOnboardingInteractionEvent, Fro import { buildFrontendOnboardingAnalytics, FRONTEND_ONBOARDING_FOLLOWUP_MS, + FRONTEND_ONBOARDING_PRODUCTION_HOST, FRONTEND_ONBOARDING_VERSIONS, } from './frontend_onboarding_analytics_model.ts' import { getFrontendOnboardingDailySetupCliEvents } from './frontend_onboarding_daily_setup_cli_outcomes.ts' @@ -15,7 +16,6 @@ const POSTHOG_MIN_DATE_MS = Date.UTC(1970, 0, 1) const POSTHOG_MAX_DATE_MS = Date.UTC(2106, 0, 1) const INVALID_TOTAL_ATTEMPTS_ERROR = 'frontend onboarding analytics query returned invalid total metadata' const ATTEMPT_LIMIT_EXCEEDED_ERROR = 'frontend onboarding analytics query exceeded attempt limit' -const FRONTEND_ONBOARDING_HOST = ['console', 'capgo', 'app'].join('.') export const FRONTEND_ONBOARDING_ATTEMPT_LIMIT = 50_000 export const FRONTEND_ONBOARDING_MAX_RANGE_MS = 365 * 24 * 60 * 60 * 1000 @@ -184,7 +184,7 @@ export function buildFrontendOnboardingHogql(startDate: string, cohortEndDate: s FROM events WHERE event IN (${eventAllowlist}) AND JSONExtractString(toString(properties), 'flow') = 'pre_org' - AND JSONExtractString(toString(properties), '$host') = ${sqlStr(FRONTEND_ONBOARDING_HOST)} + AND JSONExtractString(toString(properties), '$host') = ${sqlStr(FRONTEND_ONBOARDING_PRODUCTION_HOST)} AND toIntOrZero(toString(properties.onboarding_version)) IN (${versionAllowlist}) AND timestamp >= parseDateTimeBestEffort(${sqlStr(startDate)}) AND timestamp < parseDateTimeBestEffort(${sqlStr(followupEndDate)}) diff --git a/supabase/functions/_backend/utils/frontend_onboarding_analytics_model.ts b/supabase/functions/_backend/utils/frontend_onboarding_analytics_model.ts index 415af56535..2b3db465cb 100644 --- a/supabase/functions/_backend/utils/frontend_onboarding_analytics_model.ts +++ b/supabase/functions/_backend/utils/frontend_onboarding_analytics_model.ts @@ -1,6 +1,7 @@ export const FRONTEND_ONBOARDING_VERSIONS = [1, 2, 3] as const export type FrontendOnboardingVersion = typeof FRONTEND_ONBOARDING_VERSIONS[number] export const FRONTEND_ONBOARDING_FOLLOWUP_MS = 24 * 60 * 60 * 1000 +export const FRONTEND_ONBOARDING_PRODUCTION_HOST = ['console', 'capgo', 'app'].join('.') export type FrontendOnboardingStageKey = 'intent' | 'details' | 'organization' | 'setup' diff --git a/supabase/functions/_backend/utils/frontend_onboarding_daily_setup_cli_outcomes.ts b/supabase/functions/_backend/utils/frontend_onboarding_daily_setup_cli_outcomes.ts index bb46d10a0e..e666cc508f 100644 --- a/supabase/functions/_backend/utils/frontend_onboarding_daily_setup_cli_outcomes.ts +++ b/supabase/functions/_backend/utils/frontend_onboarding_daily_setup_cli_outcomes.ts @@ -3,6 +3,7 @@ import type { FrontendOnboardingDailySetupCliEvent, FrontendOnboardingDailySetupCliEventKind, } from './frontend_onboarding_daily_setup_cli_outcomes_model.ts' +import { FRONTEND_ONBOARDING_PRODUCTION_HOST } from './frontend_onboarding_analytics_model.ts' import { cloudlogErr } from './logging.ts' import { queryPosthogHogql } from './posthog_read.ts' @@ -10,7 +11,6 @@ const INVALID_TOTAL_EVENTS_ERROR = 'daily Setup CLI analytics query returned inv const EVENT_LIMIT_EXCEEDED_ERROR = 'daily Setup CLI analytics query exceeded event limit' const INVALID_ROW_ERROR = 'daily Setup CLI analytics row is invalid' const EVENT_KINDS: readonly FrontendOnboardingDailySetupCliEventKind[] = ['setup', 'cli_copy', 'ai_copy', 'cli_command'] -const FRONTEND_ONBOARDING_HOST = ['console', 'capgo', 'app'].join('.') export const FRONTEND_ONBOARDING_DAILY_SETUP_CLI_EVENT_LIMIT = 50_000 @@ -77,7 +77,7 @@ export function buildFrontendOnboardingDailySetupCliHogql( FROM events WHERE event = 'onboarding_step_viewed' AND JSONExtractString(toString(properties), 'flow') = 'pre_org' - AND JSONExtractString(toString(properties), '$host') = ${sqlStr(FRONTEND_ONBOARDING_HOST)} + AND JSONExtractString(toString(properties), '$host') = ${sqlStr(FRONTEND_ONBOARDING_PRODUCTION_HOST)} AND toIntOrZero(toString(properties.onboarding_version)) = 2 AND JSONExtractString(toString(properties), 'step') = 'setup' AND timestamp >= parseDateTimeBestEffort(${sqlStr(startDate)}) @@ -104,7 +104,7 @@ export function buildFrontendOnboardingDailySetupCliHogql( OR ( selected_events.event IN ('onboarding_step_viewed', 'onboarding_cli_command_copied', 'onboarding_ai_instructions_copied') AND JSONExtractString(toString(selected_events.properties), 'flow') = 'pre_org' - AND JSONExtractString(toString(selected_events.properties), '$host') = ${sqlStr(FRONTEND_ONBOARDING_HOST)} + AND JSONExtractString(toString(selected_events.properties), '$host') = ${sqlStr(FRONTEND_ONBOARDING_PRODUCTION_HOST)} AND toIntOrZero(toString(selected_events.properties.onboarding_version)) = 2 AND JSONExtractString(toString(selected_events.properties), 'step') = 'setup' ) diff --git a/tests/frontend-onboarding-daily-setup-cli-outcomes.unit.test.ts b/tests/frontend-onboarding-daily-setup-cli-outcomes.unit.test.ts index b89365df97..cc62cd5b60 100644 --- a/tests/frontend-onboarding-daily-setup-cli-outcomes.unit.test.ts +++ b/tests/frontend-onboarding-daily-setup-cli-outcomes.unit.test.ts @@ -49,6 +49,7 @@ describe('buildFrontendOnboardingDailySetupCliHogql', () => { const selectedOrderStart = query.indexOf('\n ORDER BY person_id ASC') const selectedProjection = query.slice(selectedProjectionStart, selectedFromStart) const selectedEventsFromWhere = query.slice(selectedFromStart, selectedOrderStart) + const selectedCliBranch = selectedEventsFromWhere.match(/AND \(\n([\s\S]*?)\n {8}OR \(/)?.[1] ?? '' const selectedSetupCopyBranch = selectedEventsFromWhere.match(/OR \(\n([\s\S]*?)\n {8}\)\n {6}\)/)?.[1] ?? '' expect(setupPeople).toContain('WHERE event = \'onboarding_step_viewed\'') @@ -78,6 +79,8 @@ describe('buildFrontendOnboardingDailySetupCliHogql', () => { expect(selectedEventsFromWhere).toContain('selected_events.event = \'CLI Command Invoked\'\n OR (') expect(selectedEventsFromWhere).not.toContain('JSONExtractString(toString(selected_events.properties), \'channel\')') expect(selectedEventsFromWhere).not.toContain('JSONExtractString(toString(selected_events.properties), \'command_path\') = \'init\'') + expect(selectedCliBranch).toContain('selected_events.event = \'CLI Command Invoked\'') + expect(selectedCliBranch).not.toContain('JSONExtractString(toString(selected_events.properties), \'$host\')') expect(selectedSetupCopyBranch).toContain('selected_events.event IN (\'onboarding_step_viewed\', \'onboarding_cli_command_copied\', \'onboarding_ai_instructions_copied\')') expect(selectedSetupCopyBranch).toContain('JSONExtractString(toString(selected_events.properties), \'flow\') = \'pre_org\'') expect(selectedSetupCopyBranch).toContain('JSONExtractString(toString(selected_events.properties), \'$host\') = \'console.capgo.app\'')