chore: improve posthog session identificaion

This commit is contained in:
Rotimi Best
2026-05-21 15:08:40 +01:00
parent 9043bede59
commit 9435490c43
5 changed files with 45 additions and 13 deletions
@@ -66,7 +66,9 @@ class AppInitApi extends BaseApi {
onSuccess: (data) => {
this.data = data;
licenseApi.setFeatures(data.licenseFeatures);
setupAnalyticsBasedOnLicense();
setupAnalyticsBasedOnLicense(
data.profile?.id ? { id: data.profile.id, email: data.profile.email, name: data.profile.fullname } : undefined
);
this.setupStores(params);
this.setUserAnalytics();
this.routeUserToNextPage(params);
@@ -26,7 +26,6 @@
onMount(() => {
if (page.url.searchParams.get('tokens') === 'success') {
snackbar.success('snackbar.ai_credits.purchase_success');
void aiCreditsApi.fetchAll();
}
});
</script>
@@ -1,31 +1,31 @@
import { PUBLIC_IS_SELFHOSTED } from '$env/static/public';
import { initPosthog } from '$lib/utils/services/posthog';
import { initPosthog, type PosthogBootstrapUser } from '$lib/utils/services/posthog';
import { initSentry } from '$lib/utils/services/sentry';
import { initUmami } from '$lib/utils/services/umami';
import { licenseApi } from '$features/license/api/license.svelte';
let isInitialized = false;
export function setupAnalytics() {
export function setupAnalytics(user?: PosthogBootstrapUser) {
if (isInitialized) return;
isInitialized = true;
initSentry();
initPosthog();
initPosthog(user);
initUmami();
}
/** Checks if this is cloud deployment and initializes analytics */
export function setupCloudAnalytics() {
export function setupCloudAnalytics(user?: PosthogBootstrapUser) {
if (PUBLIC_IS_SELFHOSTED !== 'true') {
setupAnalytics();
setupAnalytics(user);
}
}
export function setupAnalyticsBasedOnLicense() {
export function setupAnalyticsBasedOnLicense(user?: PosthogBootstrapUser) {
if (licenseApi.hasAccess('no-tracking')) {
return;
}
setupAnalytics();
setupAnalytics(user);
}
@@ -2,7 +2,11 @@ import { dev } from '$app/environment';
import { licenseApi } from '$features/license/api/license.svelte';
import posthog from 'posthog-js';
const hasNoTracking = () => licenseApi.hasAccess('no-tracking');
const hasNoTracking = () => {
const noTracking = licenseApi.hasAccess('no-tracking');
console.log('license_no_tracking', noTracking);
return noTracking;
};
export const capturePosthogEvent = (event: string, properties?: Record<string, unknown>): void => {
if (dev || hasNoTracking()) return;
@@ -16,10 +20,34 @@ export const identifyPosthogUser = (id: string, properties?: Record<string, unkn
posthog.identify(id, properties);
};
export const initPosthog = (): void => {
export type PosthogBootstrapUser = {
id: string;
email?: string | null;
name?: string | null;
};
/**
* When `user` is supplied, PostHog initializes as the identified user from its
* very first event. Without bootstrap the first pageview / autocapture frames /
* session-replay attribute to a fresh anonymous UUID and the later `identify`
* call only aliases — session replays and initial events stay on the anon person.
* The follow-up `setPersonProperties` attaches email/name in the same tick so
* autocapture events fire with the user's properties already on the person.
*/
export const initPosthog = (user?: PosthogBootstrapUser): void => {
if (dev || hasNoTracking()) return;
posthog.init('phc_JfdHOZ6v0cVlGELBYx1Tmoen2nxNOrAzvgvrPA6Ksov', {
api_host: 'https://eu.posthog.com'
api_host: 'https://eu.posthog.com',
...(user && {
bootstrap: { distinctID: user.id, isIdentifiedID: true }
})
});
if (user) {
posthog.setPersonProperties({
...(user.email && { email: user.email }),
...(user.name && { name: user.name })
});
}
};
+4 -1
View File
@@ -28,7 +28,10 @@
loadingIndicator.style.display = 'none';
}
setupCloudAnalytics();
const sessionUser = data?.locals?.user;
setupCloudAnalytics(
sessionUser ? { id: sessionUser.id, email: sessionUser.email, name: sessionUser.name } : undefined
);
if (data?.locals?.user) {
user.set({