From a771ab7259f363c2c1329f355340ec6297a3ca38 Mon Sep 17 00:00:00 2001 From: kumarabhirup Date: Thu, 5 Mar 2026 10:47:36 -0800 Subject: [PATCH] fix: unify PostHog distinctId across client and server Client-side posthog-js was using a random anonymous ID (reset every page load) while server-side posthog-node used a deterministic SHA256(hostname:username) hash. Bootstrap the client with the server's anonymous ID so both sides share the same per-machine-per-user identity. --- apps/web/app/components/posthog-provider.tsx | 10 +++++++--- apps/web/app/layout.tsx | 3 ++- apps/web/lib/telemetry.ts | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/web/app/components/posthog-provider.tsx b/apps/web/app/components/posthog-provider.tsx index 7e144c52563..1ed68bf5629 100644 --- a/apps/web/app/components/posthog-provider.tsx +++ b/apps/web/app/components/posthog-provider.tsx @@ -9,11 +9,15 @@ const POSTHOG_HOST = "https://us.i.posthog.com"; let initialized = false; -function initPostHog() { +function initPostHog(anonymousId: string) { if (initialized || !POSTHOG_KEY || typeof window === "undefined") return; posthog.init(POSTHOG_KEY, { api_host: POSTHOG_HOST, + bootstrap: { + distinctID: anonymousId, + isIdentifiedID: false, + }, capture_pageview: false, capture_pageleave: true, persistence: "memory", @@ -24,12 +28,12 @@ function initPostHog() { initialized = true; } -export function PostHogPageviewTracker() { +export function PostHogPageviewTracker({ anonymousId }: { anonymousId: string }) { const pathname = usePathname(); const searchParams = useSearchParams(); useEffect(() => { - initPostHog(); + initPostHog(anonymousId); }, []); useEffect(() => { diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 894fbbede58..8028f7852d3 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata, Viewport } from "next"; import { Suspense } from "react"; +import { getAnonymousId } from "@/lib/telemetry"; import { PostHogPageviewTracker } from "./components/posthog-provider"; import "./globals.css"; @@ -42,7 +43,7 @@ export default function RootLayout({ - + {children} diff --git a/apps/web/lib/telemetry.ts b/apps/web/lib/telemetry.ts index 76f758012e4..0323a5b1adc 100644 --- a/apps/web/lib/telemetry.ts +++ b/apps/web/lib/telemetry.ts @@ -7,7 +7,7 @@ const POSTHOG_HOST = "https://us.i.posthog.com"; let client: PostHog | null = null; -function getAnonymousId(): string { +export function getAnonymousId(): string { try { const raw = `${os.hostname()}:${os.userInfo().username}`; return createHash("sha256").update(raw).digest("hex").slice(0, 16);