diff --git a/src/services/analytics/gtm.ts b/src/services/analytics/gtm.ts index 6520a1b9ed..06cd3c3553 100644 --- a/src/services/analytics/gtm.ts +++ b/src/services/analytics/gtm.ts @@ -20,6 +20,8 @@ import { } from '@/config/constants' import type { AnalyticsEvent, EventLabel, SafeAppEvent } from './types' import { EventType } from './types' +import { getAbTest } from '../tracking/abTesting' +import type { AbTest } from '../tracking/abTesting' type GTMEnvironment = 'LIVE' | 'LATEST' | 'DEVELOPMENT' type GTMEnvironmentArgs = Required> @@ -85,6 +87,7 @@ export const gtmClear = (): void => { type GtmEvent = { event: EventType chainId: string + abTest?: AbTest } type ActionGtmEvent = GtmEvent & { @@ -118,6 +121,12 @@ export const gtmTrack = (eventData: AnalyticsEvent): void => { gtmEvent.eventLabel = eventData.label } + const abTest = getAbTest() + + if (abTest) { + gtmEvent.abTest = abTest + } + gtmSend(gtmEvent) } diff --git a/src/services/tracking/abTesting.ts b/src/services/tracking/abTesting.ts new file mode 100644 index 0000000000..d761a5e69e --- /dev/null +++ b/src/services/tracking/abTesting.ts @@ -0,0 +1,11 @@ +export const enum AbTest {} + +let _abTest: AbTest | null = null + +export const setAbTest = (abTest: AbTest): void => { + _abTest = abTest +} + +export const getAbTest = (): AbTest | null => { + return _abTest +} diff --git a/src/services/tracking/useABTesting.ts b/src/services/tracking/useABTesting.ts new file mode 100644 index 0000000000..90e0de9074 --- /dev/null +++ b/src/services/tracking/useABTesting.ts @@ -0,0 +1,30 @@ +import { useEffect, useMemo } from 'react' + +import useLocalStorage from '@/services/local-storage/useLocalStorage' +import { setAbTest } from './abTesting' +import type { AbTest } from './abTesting' + +const useABTesting = (abTest: AbTest): boolean => { + // Fallback AB test value if no `localStorage` exists + const coinToss = useMemo(() => { + return Math.random() >= 0.5 + }, []) + + const [isB = coinToss, setIsB] = useLocalStorage(`AB_${abTest}`) + + // Save fallback value to `localStorage` if no cache exists + useEffect(() => { + setIsB((prev) => prev ?? coinToss) + }, [coinToss, isB, setIsB]) + + // Store AB test value in GTM + useEffect(() => { + if (isB) { + setAbTest(abTest) + } + }, [abTest, isB]) + + return isB +} + +export default useABTesting