From 4a1bf954ce8dd8b536fd316535c6551e499ad37a Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 24 Aug 2026 13:57:56 -0700 Subject: [PATCH 1/3] fix(consent): enforce consent-aware analytics --- apps/sim/app/(auth)/signup/signup-form.tsx | 5 + .../(landing)/components/footer/footer.tsx | 49 +++- .../landing-shell/landing-shell.tsx | 3 +- .../consent-preferences-link.tsx | 17 +- .../cookie-policy/cookie-policy-content.tsx | 47 ++-- .../demo-scheduler/demo-scheduler.tsx | 48 ++-- .../hubspot-page-view-tracker.test.tsx | 50 ++++ .../(landing)/hubspot-page-view-tracker.tsx | 27 +- .../(landing)/landing-consent-tracking.tsx | 18 ++ apps/sim/app/(landing)/layout.tsx | 29 +- .../(landing)/x-page-view-tracker.test.tsx | 46 +++ .../sim/app/(landing)/x-page-view-tracker.tsx | 30 +- .../sim/app/_shell/consent/consent-banner.tsx | 10 +- .../consent-preferences-trigger.test.tsx | 45 +++ .../consent/consent-preferences-trigger.tsx | 25 ++ .../_shell/consent/consent-provider.test.tsx | 69 ++--- .../app/_shell/consent/consent-provider.tsx | 58 ++-- .../app/_shell/consent/consent-runtime.tsx | 16 -- .../consent/consent-store-provider.test.tsx | 9 +- .../_shell/consent/consent-store-provider.tsx | 18 +- ...oogle-analytics-page-view-tracker.test.tsx | 64 +++++ .../google-analytics-page-view-tracker.tsx | 28 ++ .../providers/posthog-provider.test.tsx | 141 ++++++++++ .../app/_shell/providers/posthog-provider.tsx | 262 ++++++++++-------- apps/sim/app/layout.tsx | 75 +---- .../components/cookie-preferences.test.tsx | 4 - .../general/components/cookie-preferences.tsx | 13 +- apps/sim/lib/analytics/google.ts | 26 ++ apps/sim/lib/consent/constants.ts | 11 - apps/sim/lib/consent/scripts.test.ts | 76 +++++ apps/sim/lib/consent/scripts.ts | 66 +++++ apps/sim/lib/consent/tracking-consent.tsx | 48 ++++ apps/sim/lib/core/security/csp.ts | 1 - apps/sim/lib/posthog/client-disabled.test.ts | 19 +- apps/sim/lib/posthog/client.test.ts | 34 +-- apps/sim/lib/posthog/client.ts | 51 ++-- apps/sim/lib/posthog/exception-filter.test.ts | 36 ++- apps/sim/lib/posthog/exception-filter.ts | 36 +++ apps/sim/package.json | 3 +- bun.lock | 16 +- 40 files changed, 1107 insertions(+), 522 deletions(-) create mode 100644 apps/sim/app/(landing)/hubspot-page-view-tracker.test.tsx create mode 100644 apps/sim/app/(landing)/landing-consent-tracking.tsx create mode 100644 apps/sim/app/(landing)/x-page-view-tracker.test.tsx create mode 100644 apps/sim/app/_shell/consent/consent-preferences-trigger.test.tsx create mode 100644 apps/sim/app/_shell/consent/consent-preferences-trigger.tsx delete mode 100644 apps/sim/app/_shell/consent/consent-runtime.tsx create mode 100644 apps/sim/app/_shell/consent/google-analytics-page-view-tracker.test.tsx create mode 100644 apps/sim/app/_shell/consent/google-analytics-page-view-tracker.tsx create mode 100644 apps/sim/app/_shell/providers/posthog-provider.test.tsx create mode 100644 apps/sim/lib/analytics/google.ts create mode 100644 apps/sim/lib/consent/scripts.test.ts create mode 100644 apps/sim/lib/consent/scripts.ts create mode 100644 apps/sim/lib/consent/tracking-consent.tsx diff --git a/apps/sim/app/(auth)/signup/signup-form.tsx b/apps/sim/app/(auth)/signup/signup-form.tsx index 94c4b74dfee..61ad48a8328 100644 --- a/apps/sim/app/(auth)/signup/signup-form.tsx +++ b/apps/sim/app/(auth)/signup/signup-form.tsx @@ -5,7 +5,9 @@ import { Turnstile, type TurnstileInstance } from '@marsidev/react-turnstile' import { createLogger } from '@sim/logger' import { useRouter, useSearchParams } from 'next/navigation' import { usePostHog } from 'posthog-js/react' +import { trackGoogleEvent } from '@/lib/analytics/google' import { client, useSession } from '@/lib/auth/auth-client' +import { useTrackingConsent } from '@/lib/consent/tracking-consent' import { getEnv, isFalsy } from '@/lib/core/config/env' import { isSsoEnabled } from '@/lib/core/config/env-flags' import { validateCallbackUrl } from '@/lib/core/security/input-validation' @@ -107,6 +109,7 @@ function SignupFormContent({ const searchParams = useSearchParams() const { refetch: refetchSession } = useSession() const posthog = usePostHog() + const { measurement } = useTrackingConsent() const [isLoading, setIsLoading] = useState(false) useEffect(() => { @@ -344,6 +347,8 @@ function SignupFormContent({ return } + if (measurement) trackGoogleEvent('sign_up', { method: 'email' }) + try { await refetchSession() logger.info('Session refreshed after successful signup') diff --git a/apps/sim/app/(landing)/components/footer/footer.tsx b/apps/sim/app/(landing)/components/footer/footer.tsx index 1fedf3b0226..5c74a5a7e8f 100644 --- a/apps/sim/app/(landing)/components/footer/footer.tsx +++ b/apps/sim/app/(landing)/components/footer/footer.tsx @@ -1,4 +1,5 @@ import Link from 'next/link' +import { ConsentPreferencesTrigger } from '@/app/_shell/consent/consent-preferences-trigger' import { ALL_COMPETITORS } from '@/app/(landing)/comparisons/utils' import { SimWordmark } from '@/app/(landing)/components/navbar/components/sim-wordmark' import { MODEL_PROVIDERS_WITH_CATALOGS } from '@/app/(landing)/models/utils' @@ -19,14 +20,25 @@ import { MODEL_PROVIDERS_WITH_CATALOGS } from '@/app/(landing)/models/utils' */ const LINK_CLASS = - 'text-sm text-[var(--text-muted)] transition-colors hover:text-[var(--text-primary)]' + 'text-left text-sm text-[var(--text-muted)] transition-colors hover:text-[var(--text-primary)]' -interface FooterItem { +interface FooterLinkItem { label: string href: string external?: boolean } +interface FooterConsentItem { + label: string + consentPreferences: true +} + +type FooterItem = FooterLinkItem | FooterConsentItem + +interface FooterProps { + showConsentPreferences?: boolean +} + /** * Platform modules link to their local landing pages (internal link equity * stays on the ranking pages); docs-only surfaces (MCP, API, Self Hosting) @@ -108,27 +120,37 @@ const SOCIAL_LINKS: FooterItem[] = [ const LEGAL_LINKS: FooterItem[] = [ { label: 'Terms of Service', href: '/terms' }, { label: 'Privacy Policy', href: '/privacy' }, + { label: 'Cookie Policy', href: '/cookie-policy' }, ] +const CONSENT_PREFERENCES_LINK: FooterConsentItem = { + label: 'Cookie preferences', + consentPreferences: true, +} + function FooterColumn({ title, items }: { title: string; items: FooterItem[] }) { return (

{title}

- {items.map(({ label, href, external }) => - external ? ( + {items.map((item) => + 'consentPreferences' in item ? ( + + {item.label} + + ) : item.external ? ( - {label} + {item.label} ) : ( - - {label} + + {item.label} ) )} @@ -137,7 +159,7 @@ function FooterColumn({ title, items }: { title: string; items: FooterItem[] }) ) } -export function Footer() { +export function Footer({ showConsentPreferences = false }: FooterProps) { return (