posthog-provider.tsx2.3 KBView on GitHub
// app/providers.tsx

import { PostHogProvider as PHProvider } from 'posthog-js/react';
import { useSession } from '@/modules/auth/utils/auth-client';
import { useEffect } from 'react';
import posthog from 'posthog-js';
import { useQuery } from '@tanstack/react-query';
import { useTRPC } from '@/providers/query-provider';
import { setSentryUserContext } from '@/lib/sentry';

export function PostHogProvider({ children }: { children: React.ReactNode }) {
  const { data: session } = useSession();
  const trpc = useTRPC();
  const { data: settingsData } = useQuery({
    ...trpc.settings.get.queryOptions(),
    enabled: !!session?.user,
  });

  useEffect(() => {
    if (!import.meta.env.VITE_PUBLIC_POSTHOG_KEY) {
      console.log('[PostHog] VITE_PUBLIC_POSTHOG_KEY not found, PostHog disabled');
      return;
    }
    try {
      posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY as string, {
        // api_host is a same-origin /ingest reverse proxy (see aws app-stack) so tracker
        // blockers don't drop our events. ui_host keeps toolbar/links pointing at PostHog.
        api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
        ui_host: 'https://us.posthog.com',
        capture_pageview: true,
        session_recording: {
          maskAllInputs: true,
        },
      });
    } catch (error) {
      console.error('Error initializing PostHog:', error);
    }
  }, []);

  useEffect(() => {
    if (!session?.user) {
      setSentryUserContext(null);
      return;
    }
    const props: Record<string, unknown> = {
      email: session.user.email,
      name: session.user.name,
    };
    // Only an authenticated read carries this user's real flags. `settings.get` is a
    // public procedure that answers 200 with all-off defaults when the session cookie
    // hasn't resolved, so reporting on any resolved response would tag entitled users
    // as ai_enabled=false — the same false negative that gated the chat composer.
    if (settingsData?.authenticated) {
      props.ai_enabled = settingsData.settings?.agentExecutionEnabled ?? false;
    }
    posthog.identify(session.user.id, props);
    setSentryUserContext(
      session.user,
      props.ai_enabled === undefined ? undefined : { ai_enabled: props.ai_enabled },
    );
  }, [session, settingsData]);

  return <PHProvider client={posthog}>{children}</PHProvider>;
}