refactor(analytics): replace PostHog with OpenPanel (#2480)
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"@formkit/auto-animate": "catalog:",
|
||||
"@moeru/eventa": "catalog:",
|
||||
"@moeru/std": "catalog:",
|
||||
"@openpanel/web": "catalog:",
|
||||
"@proj-airi/font-chillroundm": "workspace:^",
|
||||
"@proj-airi/font-cjkfonts-allseto": "workspace:^",
|
||||
"@proj-airi/font-xiaolai": "workspace:^",
|
||||
@@ -40,7 +41,6 @@
|
||||
"nanoid": "catalog:",
|
||||
"nprogress": "catalog:",
|
||||
"pinia": "catalog:",
|
||||
"posthog-js": "catalog:",
|
||||
"uuid": "catalog:",
|
||||
"vaul-vue": "catalog:",
|
||||
"vue": "catalog:",
|
||||
|
||||
@@ -24,10 +24,10 @@ import 'vue-sonner/style.css'
|
||||
import './styles/main.css'
|
||||
import 'uno.css'
|
||||
|
||||
if (isEnvTruthy(import.meta.env.VITE_ENABLE_POSTHOG)) {
|
||||
if (isEnvTruthy(import.meta.env.VITE_ENABLE_ANALYTICS)) {
|
||||
void loadAnalyticsAdapter(async () => {
|
||||
const { createPosthogAdapter } = await import('./modules/analytics-adapters/posthog')
|
||||
return createPosthogAdapter()
|
||||
const { createOpenpanelAdapter } = await import('./modules/analytics-adapters/openpanel')
|
||||
return createOpenpanelAdapter()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { AnalyticsAdapter } from '../analytics'
|
||||
|
||||
import { OpenPanel } from '@openpanel/web'
|
||||
import { OPENPANEL_CONFIG } from '@proj-airi/stage-shared/analytics/openpanel'
|
||||
|
||||
/** Sends auth milestones to the same OpenPanel project as the stage apps. */
|
||||
export function createOpenpanelAdapter(): AnalyticsAdapter {
|
||||
const panel = new OpenPanel({
|
||||
...OPENPANEL_CONFIG,
|
||||
trackScreenViews: true,
|
||||
filter(payload) {
|
||||
// OAuth codes and other query values must not enter analytics.
|
||||
if (payload.type === 'track' && payload.payload.properties) {
|
||||
for (const key of ['__path', '__referrer']) {
|
||||
const value = payload.payload.properties[key]
|
||||
if (typeof value === 'string')
|
||||
payload.payload.properties[key] = value.split(/[?#]/, 1)[0]
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
})
|
||||
panel.setGlobalProperties({ app_surface: 'auth' })
|
||||
|
||||
return {
|
||||
capture(event, properties) {
|
||||
// Auth navigation must proceed even when the analytics endpoint fails.
|
||||
void panel.track(event, properties).catch(() => console.warn('[analytics] Product event delivery failed'))
|
||||
},
|
||||
identify(userId) {
|
||||
panel.identify({ profileId: userId })
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import type { AnalyticsAdapter } from '../analytics'
|
||||
|
||||
import posthog from 'posthog-js'
|
||||
|
||||
import {
|
||||
DEFAULT_POSTHOG_CONFIG,
|
||||
POSTHOG_PROJECT_KEY,
|
||||
} from '@proj-airi/stage-shared/analytics/posthog'
|
||||
|
||||
/** Creates the auth analytics adapter and initializes its provider SDK. */
|
||||
export function createPosthogAdapter(): AnalyticsAdapter {
|
||||
posthog.init(POSTHOG_PROJECT_KEY, { ...DEFAULT_POSTHOG_CONFIG })
|
||||
// The shared project distinguishes auth traffic through this super property.
|
||||
posthog.register({ app_surface: 'auth' })
|
||||
|
||||
return {
|
||||
capture(event, properties, options) {
|
||||
posthog.capture(
|
||||
event,
|
||||
properties,
|
||||
options?.beforeNavigation ? { send_instantly: true, transport: 'sendBeacon' } : undefined,
|
||||
)
|
||||
},
|
||||
identify(userId) {
|
||||
posthog.identify(userId)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ describe('auth analytics', () => {
|
||||
//
|
||||
// The auth SPA emitted `signup_completed` before it knew the Better Auth
|
||||
// user id, while the server emitted the same canonical event with that id.
|
||||
// PostHog therefore counted one email signup as two unrelated persons.
|
||||
// The analytics provider therefore counted one email signup as two unrelated persons.
|
||||
//
|
||||
// The anonymous UI milestone must use its own name. The identified server
|
||||
// event remains the only canonical `signup_completed` business fact.
|
||||
|
||||
@@ -63,7 +63,7 @@ export default defineConfig({
|
||||
chunkFileNames: (chunkInfo) => {
|
||||
const containsAnalyticsModule = chunkInfo.moduleIds.some((moduleId) => {
|
||||
const normalizedModuleId = moduleId.replaceAll('\\', '/').toLowerCase()
|
||||
return normalizedModuleId.includes('analytics') || normalizedModuleId.includes('posthog')
|
||||
return normalizedModuleId.includes('analytics') || normalizedModuleId.includes('openpanel')
|
||||
})
|
||||
|
||||
// Keep analytics as the source-domain name, but explicitly map its
|
||||
|
||||
Reference in New Issue
Block a user