diff --git a/apps/web-roo-code/src/components/CookieConsentWrapper.tsx b/apps/web-roo-code/src/components/CookieConsentWrapper.tsx index 23b8f5a28f57..6d91d97a9c19 100644 --- a/apps/web-roo-code/src/components/CookieConsentWrapper.tsx +++ b/apps/web-roo-code/src/components/CookieConsentWrapper.tsx @@ -5,7 +5,7 @@ import ReactCookieConsent from "react-cookie-consent" import { Cookie } from "lucide-react" import { getDomain } from "tldts" import { CONSENT_COOKIE_NAME } from "@roo-code/types" -import { dispatchConsentEvent } from "@/lib/analytics/consent-manager" +import { handleConsentAccept, handleConsentReject } from "@/lib/analytics/consent-manager" /** * GDPR-compliant cookie consent banner component @@ -23,11 +23,11 @@ export function CookieConsentWrapper() { }, []) const handleAccept = () => { - dispatchConsentEvent(true) + handleConsentAccept() } const handleDecline = () => { - dispatchConsentEvent(false) + handleConsentReject() } const extraCookieOptions = cookieDomain diff --git a/apps/web-roo-code/src/components/providers/posthog-provider.tsx b/apps/web-roo-code/src/components/providers/posthog-provider.tsx index d172fd8f182b..0d8932d549b2 100644 --- a/apps/web-roo-code/src/components/providers/posthog-provider.tsx +++ b/apps/web-roo-code/src/components/providers/posthog-provider.tsx @@ -3,8 +3,8 @@ import { usePathname, useSearchParams } from "next/navigation" import posthog from "posthog-js" import { PostHogProvider as OriginalPostHogProvider } from "posthog-js/react" -import { useEffect, Suspense, useState } from "react" -import { hasConsent, onConsentChange } from "@/lib/analytics/consent-manager" +import { useEffect, Suspense } from "react" +import { hasConsent } from "@/lib/analytics/consent-manager" function PageViewTracker() { const pathname = usePathname() @@ -28,11 +28,9 @@ function PageViewTracker() { } export function PostHogProvider({ children }: { children: React.ReactNode }) { - const [isInitialized, setIsInitialized] = useState(false) - useEffect(() => { - // Initialize PostHog only on the client side AND when consent is given - if (typeof window !== "undefined") { + // Initialize PostHog immediately on the client side + if (typeof window !== "undefined" && !posthog.__loaded) { const posthogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY const posthogHost = process.env.NEXT_PUBLIC_POSTHOG_HOST @@ -52,48 +50,32 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) { ) } - const initializePosthog = () => { - if (!isInitialized) { - posthog.init(posthogKey, { - api_host: posthogHost || "https://us.i.posthog.com", - capture_pageview: false, - loaded: (posthogInstance) => { - if (process.env.NODE_ENV === "development") { - posthogInstance.debug() - } - }, - respect_dnt: true, // Respect Do Not Track - }) - setIsInitialized(true) - } - } - - // Check initial consent status - if (hasConsent()) { - initializePosthog() - } + // Check if user has already consented to cookies + const userHasConsented = hasConsent() - // Listen for consent changes - const unsubscribe = onConsentChange((consented) => { - if (consented && !isInitialized) { - initializePosthog() - } + // Initialize PostHog with appropriate persistence based on consent + posthog.init(posthogKey, { + api_host: posthogHost || "https://us.i.posthog.com", + capture_pageview: false, // We handle pageview tracking manually + loaded: (posthogInstance) => { + if (process.env.NODE_ENV === "development") { + posthogInstance.debug() + } + }, + save_referrer: true, // Save referrer information + save_campaign_params: true, // Save UTM parameters + respect_dnt: true, // Respect Do Not Track + persistence: userHasConsented ? "localStorage+cookie" : "memory", // Use localStorage if consented, otherwise memory-only + opt_out_capturing_by_default: false, // Start tracking immediately }) - - return () => { - unsubscribe() - } } - }, [isInitialized]) + }, []) - // Only provide PostHog context if it's initialized return ( - {isInitialized && ( - - - - )} + + + {children} ) diff --git a/apps/web-roo-code/src/lib/analytics/consent-manager.ts b/apps/web-roo-code/src/lib/analytics/consent-manager.ts index 10ef71ee702f..a99f6c19f2fc 100644 --- a/apps/web-roo-code/src/lib/analytics/consent-manager.ts +++ b/apps/web-roo-code/src/lib/analytics/consent-manager.ts @@ -5,6 +5,7 @@ import { getCookieConsentValue } from "react-cookie-consent" import { CONSENT_COOKIE_NAME } from "@roo-code/types" +import posthog from "posthog-js" export const CONSENT_EVENT = "cookieConsentChanged" @@ -45,3 +46,27 @@ export function onConsentChange(callback: (consented: boolean) => void): () => v window.addEventListener(CONSENT_EVENT, handler) return () => window.removeEventListener(CONSENT_EVENT, handler) } + +/** + * Handle user accepting cookies + * Opts PostHog back into cookie-based tracking + */ +export function handleConsentAccept(): void { + if (typeof window !== "undefined" && posthog.__loaded) { + // User accepted - ensure localStorage+cookie persistence is enabled + posthog.opt_in_capturing() + posthog.set_config({ + persistence: "localStorage+cookie", + }) + } + dispatchConsentEvent(true) +} + +/** + * Handle user rejecting cookies + * Switches PostHog to cookieless (memory-only) mode + */ +export function handleConsentReject(): void { + // User rejected - stick to cookieless mode + dispatchConsentEvent(false) +}