A/B Test Variant Tracking Bug Fix
Historical record — status as of 2026-09-23. This describes a fix to an earlier landing-page test. The two landing components it names,components/landing-page-client.tsxandcomponents/landing-page-variant2.tsx, were deleted in cleanup PR 3 (docs/MODULUS-CLEANUP-PLAN.md); both had been unreferenced for months.components/variant-persistence.tsxstill exists but nothing mounts it. The live landing experiment today runs throughcomponents/home-landing-router.tsxandhooks/use-landing-conversion-experiment.tson a different PostHog flag — read those, not this, for how it works now.
Problem Summary
Users were being tracked in PostHog for the wrong variant during the sign-in/sign-up flow:- User visits landing page → sees control variant
- User clicks sign in → enters email/code
- During redirect to onboarding, page re-renders
- New variant (test) briefly flashes on screen (< 1 second)
- PostHog captures pageview with new variant instead of control
- Session recording shows user saw control, but PostHog attributes them to test variant
Root Causes
1. Variant Assignment Instability
getBootstrapData()called on every server render- Variant could change between renders (especially after authentication)
- No persistence mechanism to lock variant assignment
2. Pageview Tracking During Redirects
- PostHog pageview tracking fired immediately on page load
- Captured brief variant flashes during authentication redirects
- No delay to filter out redirect flashes
3. Missing Experiment Exposure Tracking
- Only pageviews tracked, not explicit experiment exposure
- No session-based deduplication of exposure events
Solution Implemented
1. Variant Persistence (Server + Client)
Server Side (app/utils/getBootstrapData.js):
- Check for persisted variant cookie before calling PostHog
- If variant exists and is fresh (< 24 hours), use it instead of PostHog assignment
- This prevents variant switching during authentication
components/variant-persistence.tsx):
- New component that persists variant in cookie on first page load
- Sets 24-hour expiration
- Includes timestamp for freshness check
2. Delayed Pageview Tracking
PostHog Provider (app/_providers/posthog-provider.tsx):
- Added 500ms delay for landing page (
/) pageviews - If page unmounts before 500ms (e.g., during redirect), pageview not tracked
- Prevents tracking brief flashes during authentication
3. Explicit Experiment Exposure Tracking
Both Variants (components/landing-page-client.tsx, components/landing-page-variant2.tsx):
- Added
useEffectto track$feature_flag_calledevent on mount - Uses sessionStorage to prevent duplicate tracking
- Tracks which variant user actually saw, not just pageviews
Files Modified
-
/app/utils/getBootstrapData.js- Added variant cookie reading logic
- Override PostHog variant with persisted variant if available
-
/components/variant-persistence.tsx(NEW)- Client component to persist variant in cookie
-
/app/(home)/page.tsx- Added
<VariantPersistence>component to both variant branches
- Added
-
/components/landing-page-variant2.tsx- Added experiment exposure tracking on mount
- SessionStorage-based deduplication
-
/components/landing-page-client.tsx- Added experiment exposure tracking on mount
- SessionStorage-based deduplication
-
/app/_providers/posthog-provider.tsx- Added 500ms delay for landing page pageview tracking
How It Works
First Visit (No Cookie)
- User visits
/→getBootstrapData()called - No persisted variant found → PostHog assigns variant (e.g., “control”)
- Page renders control variant
<VariantPersistence>component sets cookie:lp_experiment_variant={"variant":"control","timestamp":...}- Control variant tracks experiment exposure via
$feature_flag_called - After 500ms (if still on page), pageview tracked
Sign-In Flow (Cookie Exists)
- User clicks sign in → Clerk modal opens
- User enters email/code → Clerk redirects
- During redirect, page re-renders →
getBootstrapData()called again - Cookie found with “control” variant → Uses persisted variant, not new PostHog assignment
- Control variant renders (same as before)
- Page unmounts before 500ms → No pageview tracked (prevents flash tracking)
- User lands on
/onboarding
Result
- User consistently sees control variant throughout session
- PostHog correctly tracks user in control group
- No variant switching during authentication
- No false tracking from redirect flashes
Testing Instructions
Test 1: Variant Persistence
- Open incognito window
- Visit landing page
- Open DevTools → Application → Cookies
- Verify
lp_experiment_variantcookie is set - Note the variant value (e.g., “control”)
- Refresh page multiple times
- Expected: Same variant renders each time
Test 2: Sign-In Flow
- Clear cookies and start fresh
- Visit landing page → note variant shown (e.g., control)
- Click “Sign In” button
- Enter credentials in Clerk modal
- Watch carefully during redirect
- Expected: If brief flash occurs, it should be same variant (control)
- Check PostHog session recording
- Expected: PostHog shows user assigned to correct variant
Test 3: Experiment Exposure Tracking
- Clear cookies and start fresh
- Open DevTools → Console
- Visit landing page
- Look for log:
📊 Experiment exposure tracked: {experimentKey: "landing-page-conversion", variant: "control"} - Refresh page
- Expected: Log appears only once per session (sessionStorage prevents duplicates)
Test 4: Pageview Delay
- Visit landing page
- Immediately navigate away (< 500ms)
- Check PostHog events
- Expected: No
$pageviewevent for landing page - Visit landing page again
- Stay for > 500ms
- Expected:
$pageviewevent appears in PostHog
PostHog Events to Monitor
Correct Tracking (After Fix)
Incorrect Tracking (Before Fix - Bug)
Cookie Schema
lp_experiment_variant
- Path:
/ - Expiration: 24 hours
- SameSite:
Lax - Secure: Inherited from domain settings
Session Storage Schema
experiment_exposure_landing-page-conversion
- Value:
"true" - Purpose: Prevent duplicate exposure tracking within same session
- Cleared: When browser tab/window closes
Rollback Instructions
If this fix causes issues:-
Remove variant persistence:
- Remove lines 36-55 from
/app/utils/getBootstrapData.js - Remove lines 69-72 from same file
- Remove lines 36-55 from
-
Remove pageview delay:
- Revert
/app/_providers/posthog-provider.tsxto always track immediately
- Revert
-
Remove exposure tracking:
- Remove
useEffectblocks from both landing page components
- Remove
-
Remove cookie component:
- Remove
<VariantPersistence>from/app/(home)/page.tsx - Delete
/components/variant-persistence.tsx
- Remove
Future Improvements
- Server-side variant persistence in database for logged-in users
- Middleware-based variant assignment to prevent client-side delays
- A/B test framework to handle multiple experiments consistently
- Automated testing for variant stability across authentication flows
Related Issues
- PostHog A/B test inconsistency
- Variant switching during authentication
- Session recording vs analytics mismatch
- Feature flag evaluation timing
References
- PostHog Feature Flags: https://posthog.com/docs/feature-flags
- PostHog Experiments: https://posthog.com/docs/experiments
- Next.js Server Components: https://nextjs.org/docs/app/building-your-application/rendering/server-components