Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/web-roo-code/src/components/CookieConsentWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -23,11 +23,11 @@ export function CookieConsentWrapper() {
}, [])

const handleAccept = () => {
dispatchConsentEvent(true)
handleConsentAccept()
}

const handleDecline = () => {
dispatchConsentEvent(false)
handleConsentReject()
}

const extraCookieOptions = cookieDomain
Expand Down
66 changes: 24 additions & 42 deletions apps/web-roo-code/src/components/providers/posthog-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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

Expand All @@ -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 (
<OriginalPostHogProvider client={posthog}>
{isInitialized && (
<Suspense fallback={null}>
<PageViewTracker />
</Suspense>
)}
<Suspense fallback={null}>
<PageViewTracker />
</Suspense>
{children}
</OriginalPostHogProvider>
)
Expand Down
25 changes: 25 additions & 0 deletions apps/web-roo-code/src/lib/analytics/consent-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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)
}