mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 04:15:04 +03:00
feat(growth): add in-memory first-touch attribution store (GROWTH-656)
Replaces the supabase-telemetry-data session cookie with a module-scoped in-memory store so no non-essential device storage occurs before affirmative consent in GDPR regions.
This commit is contained in:
1 parent
14b2af415f
commit
aa2114fda0
2 files changed
+81
No files matched your search
@@ -0,0 +1,28 @@
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { setFirstTouchData } from '../telemetry-first-touch-store'
|
||||
import { getSharedTelemetryData } from '../telemetry-utils'
|
||||
|
||||
interface UseFirstTouchStoreProps {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures first-touch attribution data (e.g. `document.referrer`, UTM params)
|
||||
* into an in-memory store on the initial page load — before consent is granted.
|
||||
*
|
||||
* The data is read once by PageTelemetry after consent and then cleared.
|
||||
* Using in-memory storage (instead of a cookie) ensures no non-essential
|
||||
* device storage before affirmative consent in GDPR regions.
|
||||
*/
|
||||
export function useFirstTouchStore({ enabled }: UseFirstTouchStoreProps) {
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return
|
||||
if (!enabled) return
|
||||
|
||||
const telemetryData = getSharedTelemetryData(window.location.pathname)
|
||||
setFirstTouchData(telemetryData)
|
||||
}, [enabled])
|
||||
}
|
||||
|
||||
export default useFirstTouchStore
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* In-memory store for first-touch attribution data.
|
||||
*
|
||||
* Replaces the previous `supabase-telemetry-data` session cookie so that
|
||||
* no non-essential device storage happens before affirmative consent in
|
||||
* GDPR regions (ePrivacy Directive compliance).
|
||||
*
|
||||
* The data is captured on the very first page load (before consent) and
|
||||
* held in a module-scoped variable. When consent is granted, PageTelemetry
|
||||
* reads it once for the initial pageview event and then clears it.
|
||||
*
|
||||
* Trade-off: data is lost on a hard reload (Cmd+R) before consent, which
|
||||
* is an accepted edge case (see GROWTH-656).
|
||||
*
|
||||
* Module-scope is safe here because both the writer (useFirstTouchStore)
|
||||
* and reader (PageTelemetry) live in the same client-side bundle — the
|
||||
* same pattern used by posthogClient and consentState.
|
||||
*/
|
||||
|
||||
import type { getSharedTelemetryData } from './telemetry-utils'
|
||||
|
||||
export type SharedTelemetryData = ReturnType<typeof getSharedTelemetryData>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Module-scoped singleton (survives SPA navigations, lost on hard reload)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
let firstTouchData: SharedTelemetryData | null = null
|
||||
|
||||
/**
|
||||
* Store the first-touch attribution data captured on initial page load.
|
||||
* Only writes once — subsequent calls are no-ops if data already exists.
|
||||
*/
|
||||
export function setFirstTouchData(data: SharedTelemetryData): void {
|
||||
if (firstTouchData !== null) return
|
||||
firstTouchData = data
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the stored first-touch attribution data.
|
||||
* Returns null if no data has been captured (e.g. after a hard reload).
|
||||
*/
|
||||
export function getFirstTouchData(): SharedTelemetryData | null {
|
||||
return firstTouchData
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the stored first-touch attribution data.
|
||||
* Called after the initial pageview event is sent, or when the user opts out.
|
||||
*/
|
||||
export function clearFirstTouchData(): void {
|
||||
firstTouchData = null
|
||||
}
|
||||
Reference in new issue
Block a user