Skip to content

Commit eb68c65

Browse files
authored
web: Attempt at compliant, cookie-less anonymous tracking for the website (#8957)
1 parent 416fa57 commit eb68c65

File tree

3 files changed

+52
-45
lines changed

3 files changed

+52
-45
lines changed

apps/web-roo-code/src/components/CookieConsentWrapper.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import ReactCookieConsent from "react-cookie-consent"
55
import { Cookie } from "lucide-react"
66
import { getDomain } from "tldts"
77
import { CONSENT_COOKIE_NAME } from "@roo-code/types"
8-
import { dispatchConsentEvent } from "@/lib/analytics/consent-manager"
8+
import { handleConsentAccept, handleConsentReject } from "@/lib/analytics/consent-manager"
99

1010
/**
1111
* GDPR-compliant cookie consent banner component
@@ -23,11 +23,11 @@ export function CookieConsentWrapper() {
2323
}, [])
2424

2525
const handleAccept = () => {
26-
dispatchConsentEvent(true)
26+
handleConsentAccept()
2727
}
2828

2929
const handleDecline = () => {
30-
dispatchConsentEvent(false)
30+
handleConsentReject()
3131
}
3232

3333
const extraCookieOptions = cookieDomain

apps/web-roo-code/src/components/providers/posthog-provider.tsx

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import { usePathname, useSearchParams } from "next/navigation"
44
import posthog from "posthog-js"
55
import { PostHogProvider as OriginalPostHogProvider } from "posthog-js/react"
6-
import { useEffect, Suspense, useState } from "react"
7-
import { hasConsent, onConsentChange } from "@/lib/analytics/consent-manager"
6+
import { useEffect, Suspense } from "react"
7+
import { hasConsent } from "@/lib/analytics/consent-manager"
88

99
function PageViewTracker() {
1010
const pathname = usePathname()
@@ -28,11 +28,9 @@ function PageViewTracker() {
2828
}
2929

3030
export function PostHogProvider({ children }: { children: React.ReactNode }) {
31-
const [isInitialized, setIsInitialized] = useState(false)
32-
3331
useEffect(() => {
34-
// Initialize PostHog only on the client side AND when consent is given
35-
if (typeof window !== "undefined") {
32+
// Initialize PostHog immediately on the client side
33+
if (typeof window !== "undefined" && !posthog.__loaded) {
3634
const posthogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY
3735
const posthogHost = process.env.NEXT_PUBLIC_POSTHOG_HOST
3836

@@ -52,48 +50,32 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
5250
)
5351
}
5452

55-
const initializePosthog = () => {
56-
if (!isInitialized) {
57-
posthog.init(posthogKey, {
58-
api_host: posthogHost || "https://us.i.posthog.com",
59-
capture_pageview: false,
60-
loaded: (posthogInstance) => {
61-
if (process.env.NODE_ENV === "development") {
62-
posthogInstance.debug()
63-
}
64-
},
65-
respect_dnt: true, // Respect Do Not Track
66-
})
67-
setIsInitialized(true)
68-
}
69-
}
70-
71-
// Check initial consent status
72-
if (hasConsent()) {
73-
initializePosthog()
74-
}
53+
// Check if user has already consented to cookies
54+
const userHasConsented = hasConsent()
7555

76-
// Listen for consent changes
77-
const unsubscribe = onConsentChange((consented) => {
78-
if (consented && !isInitialized) {
79-
initializePosthog()
80-
}
56+
// Initialize PostHog with appropriate persistence based on consent
57+
posthog.init(posthogKey, {
58+
api_host: posthogHost || "https://us.i.posthog.com",
59+
capture_pageview: false, // We handle pageview tracking manually
60+
loaded: (posthogInstance) => {
61+
if (process.env.NODE_ENV === "development") {
62+
posthogInstance.debug()
63+
}
64+
},
65+
save_referrer: true, // Save referrer information
66+
save_campaign_params: true, // Save UTM parameters
67+
respect_dnt: true, // Respect Do Not Track
68+
persistence: userHasConsented ? "localStorage+cookie" : "memory", // Use localStorage if consented, otherwise memory-only
69+
opt_out_capturing_by_default: false, // Start tracking immediately
8170
})
82-
83-
return () => {
84-
unsubscribe()
85-
}
8671
}
87-
}, [isInitialized])
72+
}, [])
8873

89-
// Only provide PostHog context if it's initialized
9074
return (
9175
<OriginalPostHogProvider client={posthog}>
92-
{isInitialized && (
93-
<Suspense fallback={null}>
94-
<PageViewTracker />
95-
</Suspense>
96-
)}
76+
<Suspense fallback={null}>
77+
<PageViewTracker />
78+
</Suspense>
9779
{children}
9880
</OriginalPostHogProvider>
9981
)

apps/web-roo-code/src/lib/analytics/consent-manager.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { getCookieConsentValue } from "react-cookie-consent"
77
import { CONSENT_COOKIE_NAME } from "@roo-code/types"
8+
import posthog from "posthog-js"
89

910
export const CONSENT_EVENT = "cookieConsentChanged"
1011

@@ -45,3 +46,27 @@ export function onConsentChange(callback: (consented: boolean) => void): () => v
4546
window.addEventListener(CONSENT_EVENT, handler)
4647
return () => window.removeEventListener(CONSENT_EVENT, handler)
4748
}
49+
50+
/**
51+
* Handle user accepting cookies
52+
* Opts PostHog back into cookie-based tracking
53+
*/
54+
export function handleConsentAccept(): void {
55+
if (typeof window !== "undefined" && posthog.__loaded) {
56+
// User accepted - ensure localStorage+cookie persistence is enabled
57+
posthog.opt_in_capturing()
58+
posthog.set_config({
59+
persistence: "localStorage+cookie",
60+
})
61+
}
62+
dispatchConsentEvent(true)
63+
}
64+
65+
/**
66+
* Handle user rejecting cookies
67+
* Switches PostHog to cookieless (memory-only) mode
68+
*/
69+
export function handleConsentReject(): void {
70+
// User rejected - stick to cookieless mode
71+
dispatchConsentEvent(false)
72+
}

0 commit comments

Comments
 (0)