Add hero CTA A/B test (hero_cta: control vs free_emphasis)

Sticky 50/50 variant assignment via gw_ab_hero cookie, server-rendered
so no flicker. Tracks exposures, CTA clicks, and booking conversions
to ab_events (table self-creates on first POST). Bot UAs are dropped;
exposures/clicks dedupe per session.

- ?ab=control / ?ab=free_emphasis forces and persists a variant
- /owner/experiments shows per-variant CVR and relative lift
- AB only runs on the marketing surface

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 08:14:18 +12:00
parent a7f8a619b1
commit 171b193498
14 changed files with 534 additions and 8 deletions
+3
View File
@@ -4,12 +4,14 @@
import Icon from '$lib/components/Icon.svelte';
import { reveal } from '$lib/actions/reveal';
import type { BookingContent } from '$lib/types';
import { trackAb, type AbContext } from '$lib/ab';
type SuccessModalComponentType = typeof import('$lib/components/SuccessModal.svelte').default;
type ErrorModalComponentType = typeof import('$lib/components/ErrorModal.svelte').default;
export let booking: BookingContent;
export let pagePath = '';
export let ab: AbContext | undefined = undefined;
$: isCompactContactPage = pagePath === '/contact-us';
const defaultServices = ['Tiny Gang Pack Walks', 'Solo Walks', 'Puppy Visits', 'Other Services'];
@@ -285,6 +287,7 @@
}
submitted = true;
if (ab) trackAb({ ...ab, event_type: 'conversion', meta: { surface: 'booking_submit' } });
} catch (err: unknown) {
submitErrorDetail = err instanceof Error ? err.message : String(err);
showErrorModal = true;