@zoyth/simple-site-framework 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +572 -0
- package/bin/create-simple-site.js +390 -0
- package/bin/simple-site.js +664 -0
- package/dist/client.js +135 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +107 -0
- package/dist/client.mjs.map +1 -0
- package/dist/components/index.d.mts +3936 -0
- package/dist/components/index.d.ts +3936 -0
- package/dist/components/index.js +38265 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +38173 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/config/index.d.mts +298 -0
- package/dist/config/index.d.ts +298 -0
- package/dist/config/index.js +19 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/index.mjs +1 -0
- package/dist/config/index.mjs.map +1 -0
- package/dist/index.d.mts +2184 -0
- package/dist/index.d.ts +2184 -0
- package/dist/index.js +1713 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1605 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/i18n/index.js +665 -0
- package/dist/lib/i18n/index.js.map +1 -0
- package/dist/lib/i18n/index.mjs +621 -0
- package/dist/lib/i18n/index.mjs.map +1 -0
- package/docs/DOCUMENTATION-STRUCTURE.md +1156 -0
- package/docs/EXPORTS.md +125 -0
- package/docs/PERFORMANCE.md +757 -0
- package/docs/POLICY-PAGES.md +867 -0
- package/docs/ROADMAP.md +334 -0
- package/docs/SEO.md +455 -0
- package/docs/SITEMAP.md +708 -0
- package/docs/STRUCTURED-DATA.md +671 -0
- package/docs/accessibility/common-patterns.md +529 -0
- package/docs/accessibility/keyboard-navigation.md +263 -0
- package/docs/accessibility/overview.md +122 -0
- package/docs/accessibility/screen-readers.md +311 -0
- package/docs/accessibility/wcag-compliance.md +159 -0
- package/docs/api/README.md +164 -0
- package/docs/api/components/Accessibility.md +356 -0
- package/docs/api/components/Button.md +240 -0
- package/docs/api/components/HeroSection.md +306 -0
- package/docs/architecture/decisions.md +449 -0
- package/docs/components/AnalyticsTracker.md +58 -0
- package/docs/components/AnimatedCounter.md +48 -0
- package/docs/components/AnimatedSection.md +56 -0
- package/docs/components/BlogCard.md +42 -0
- package/docs/components/Checkbox.md +56 -0
- package/docs/components/CodeBlock.md +52 -0
- package/docs/components/ComparisonTable.md +40 -0
- package/docs/components/ComponentDemo.md +38 -0
- package/docs/components/CountdownTimer.md +51 -0
- package/docs/components/ExitIntentModal.md +56 -0
- package/docs/components/FAQAccordion.md +66 -0
- package/docs/components/FeaturesGrid.md +55 -0
- package/docs/components/FileUpload.md +54 -0
- package/docs/components/I18nMetaTags.md +55 -0
- package/docs/components/Icon.md +53 -0
- package/docs/components/LazySection.md +46 -0
- package/docs/components/LiveProof.md +53 -0
- package/docs/components/LoadingSpinner.md +46 -0
- package/docs/components/MultiStepForm.md +48 -0
- package/docs/components/PolicyLayout.md +55 -0
- package/docs/components/PricingTable.md +49 -0
- package/docs/components/Radio.md +59 -0
- package/docs/components/SEOMetaTags.md +58 -0
- package/docs/components/ScriptInjector.md +50 -0
- package/docs/components/Select.md +72 -0
- package/docs/components/Skeleton.md +47 -0
- package/docs/components/StatsSection.md +48 -0
- package/docs/components/StickyBar.md +62 -0
- package/docs/components/StructuredData.md +99 -0
- package/docs/components/StyleGuide.md +46 -0
- package/docs/components/TableOfContents.md +47 -0
- package/docs/components/TestimonialCarousel.md +42 -0
- package/docs/components/Timeline.md +51 -0
- package/docs/components/Toast.md +59 -0
- package/docs/components/TrackedLink.md +62 -0
- package/docs/components/TrustBadges.md +44 -0
- package/docs/components/conversion/MobileCTA.md +363 -0
- package/docs/components/forms/ContactForm.md +75 -0
- package/docs/components/forms/FormField.md +74 -0
- package/docs/components/layout/Footer.md +601 -0
- package/docs/components/layout/Header.md +549 -0
- package/docs/components/layout/LanguageSelector.md +54 -0
- package/docs/components/layout/LanguageSwitcher.md +24 -0
- package/docs/components/overview.md +447 -0
- package/docs/components/sections/AboutSection.md +48 -0
- package/docs/components/sections/CTASection.md +596 -0
- package/docs/components/sections/CaseStudySection.md +47 -0
- package/docs/components/sections/ContactSection.md +599 -0
- package/docs/components/sections/FeatureSection.md +44 -0
- package/docs/components/sections/HeroSection.md +404 -0
- package/docs/components/sections/LogosSection.md +47 -0
- package/docs/components/sections/PersonalTaxesSection.md +23 -0
- package/docs/components/sections/RecruitingSection.md +23 -0
- package/docs/components/sections/SecurePortalSection.md +23 -0
- package/docs/components/sections/ServicePageLayout.md +52 -0
- package/docs/components/sections/ServicesSection.md +49 -0
- package/docs/components/sections/TestimonialSection.md +44 -0
- package/docs/components/sections/WhyChooseUsSection.md +54 -0
- package/docs/components/ui/Breadcrumb.md +70 -0
- package/docs/components/ui/Button.md +514 -0
- package/docs/components/ui/Card.md +501 -0
- package/docs/components/ui/Input.md +54 -0
- package/docs/components/ui/MobileLinks.md +43 -0
- package/docs/components/ui/Modal.md +60 -0
- package/docs/components/ui/Tabs.md +62 -0
- package/docs/components/ui/Textarea.md +52 -0
- package/docs/core-concepts/configuration-driven.md +552 -0
- package/docs/core-concepts/overview.md +351 -0
- package/docs/features/accessibility/README.md +73 -0
- package/docs/features/accessibility/aria-support.md +177 -0
- package/docs/features/accessibility/color-contrast.md +155 -0
- package/docs/features/accessibility/focus-management.md +187 -0
- package/docs/features/accessibility/testing.md +196 -0
- package/docs/features/analytics/README.md +51 -0
- package/docs/features/analytics/ab-testing.md +171 -0
- package/docs/features/analytics/conversion-tracking.md +207 -0
- package/docs/features/analytics/custom-events.md +219 -0
- package/docs/features/analytics/privacy.md +198 -0
- package/docs/features/analytics/setup.md +114 -0
- package/docs/features/analytics/tracking-events.md +224 -0
- package/docs/features/i18n/README.md +51 -0
- package/docs/features/i18n/best-practices.md +273 -0
- package/docs/features/i18n/configuration.md +84 -0
- package/docs/features/i18n/formatting.md +133 -0
- package/docs/features/i18n/locale-detection.md +122 -0
- package/docs/features/i18n/routing.md +99 -0
- package/docs/features/i18n/rtl-support.md +191 -0
- package/docs/features/i18n/translations.md +129 -0
- package/docs/features/internationalization.md +595 -0
- package/docs/features/performance/README.md +77 -0
- package/docs/features/performance/bundle-size.md +134 -0
- package/docs/features/performance/caching.md +131 -0
- package/docs/features/performance/code-splitting.md +121 -0
- package/docs/features/performance/image-optimization.md +110 -0
- package/docs/features/performance/lazy-loading.md +92 -0
- package/docs/features/performance/monitoring.md +148 -0
- package/docs/features/seo/README.md +51 -0
- package/docs/features/seo/best-practices.md +184 -0
- package/docs/features/seo/canonical-urls.md +182 -0
- package/docs/features/seo/meta-tags.md +126 -0
- package/docs/features/seo/open-graph.md +166 -0
- package/docs/features/seo/robots-txt.md +146 -0
- package/docs/features/seo/sitemaps.md +162 -0
- package/docs/features/seo/structured-data.md +166 -0
- package/docs/getting-started/installation.md +292 -0
- package/docs/getting-started/introduction.md +195 -0
- package/docs/getting-started/quick-start.md +460 -0
- package/docs/guides/analytics-setup.md +616 -0
- package/docs/i18n/CONFIGURATION.md +353 -0
- package/docs/i18n/EXAMPLES.md +402 -0
- package/docs/i18n/MIGRATION.md +260 -0
- package/docs/i18n/SEO.md +392 -0
- package/docs/i18n/STATIC-GENERATION-FIX.md +71 -0
- package/docs/migration/changelog.md +136 -0
- package/docs/migration/overview.md +233 -0
- package/docs/recipes/adding-animations.md +475 -0
- package/docs/recipes/forms-with-validation.md +393 -0
- package/package.json +152 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# A/B Testing
|
|
2
|
+
|
|
3
|
+
Run experiments to optimize conversions and user engagement.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The framework provides a client-side A/B testing system that:
|
|
8
|
+
|
|
9
|
+
- Assigns users to variants deterministically
|
|
10
|
+
- Persists assignments across sessions
|
|
11
|
+
- Integrates with analytics tracking
|
|
12
|
+
- Supports weighted variant distribution
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
'use client';
|
|
18
|
+
import { getABTestVariant, trackABTestEvent } from '@zoyth/simple-site-framework/client';
|
|
19
|
+
|
|
20
|
+
const variant = getABTestVariant({
|
|
21
|
+
testId: 'hero-cta',
|
|
22
|
+
variants: { A: { weight: 50 }, B: { weight: 50 } },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const ctaText = variant === 'A' ? 'Start Free Trial' : 'Get Started Free';
|
|
26
|
+
|
|
27
|
+
<button onClick={() => trackABTestEvent('hero-cta', variant, 'click')}>
|
|
28
|
+
{ctaText}
|
|
29
|
+
</button>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Setting Up a Test
|
|
33
|
+
|
|
34
|
+
### 1. Define the Test
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
const test = {
|
|
38
|
+
testId: 'pricing-layout',
|
|
39
|
+
variants: {
|
|
40
|
+
control: { weight: 50 },
|
|
41
|
+
cards: { weight: 50 },
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Get Variant Assignment
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const variant = getABTestVariant(test);
|
|
50
|
+
// Returns 'control' or 'cards'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Render Based on Variant
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
{variant === 'control' ? (
|
|
57
|
+
<PricingTable layout="table" />
|
|
58
|
+
) : (
|
|
59
|
+
<PricingTable layout="cards" />
|
|
60
|
+
)}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 4. Track Conversions
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
function handlePurchase() {
|
|
67
|
+
trackABTestEvent('pricing-layout', variant, 'purchase');
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Variant Assignment
|
|
72
|
+
|
|
73
|
+
### How It Works
|
|
74
|
+
|
|
75
|
+
1. User visits page with A/B test
|
|
76
|
+
2. Framework generates or retrieves user ID
|
|
77
|
+
3. User ID + test ID produces deterministic hash
|
|
78
|
+
4. Hash maps to variant based on weights
|
|
79
|
+
5. Assignment persists via cookie/localStorage
|
|
80
|
+
|
|
81
|
+
### Weighted Distribution
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// Equal split
|
|
85
|
+
variants: { A: { weight: 50 }, B: { weight: 50 } }
|
|
86
|
+
|
|
87
|
+
// 80/20 split
|
|
88
|
+
variants: { control: { weight: 80 }, experiment: { weight: 20 } }
|
|
89
|
+
|
|
90
|
+
// Three-way split
|
|
91
|
+
variants: { A: { weight: 33 }, B: { weight: 33 }, C: { weight: 34 } }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Weights don't need to sum to 100 - they're relative proportions.
|
|
95
|
+
|
|
96
|
+
## Tracking Test Events
|
|
97
|
+
|
|
98
|
+
### trackABTestEvent
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { trackABTestEvent } from '@zoyth/simple-site-framework/client';
|
|
102
|
+
|
|
103
|
+
// Track exposure (user saw the variant)
|
|
104
|
+
trackABTestEvent('test-id', variant, 'exposure');
|
|
105
|
+
|
|
106
|
+
// Track interaction
|
|
107
|
+
trackABTestEvent('test-id', variant, 'click');
|
|
108
|
+
|
|
109
|
+
// Track conversion
|
|
110
|
+
trackABTestEvent('test-id', variant, 'conversion');
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Custom Event Data
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
trackABTestEvent('test-id', variant, 'purchase', {
|
|
117
|
+
value: 49.99,
|
|
118
|
+
currency: 'USD',
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Multi-Page Tests
|
|
123
|
+
|
|
124
|
+
For tests spanning multiple pages, variant persists automatically:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Page 1: Assign variant
|
|
128
|
+
const variant = getABTestVariant({
|
|
129
|
+
testId: 'onboarding-flow',
|
|
130
|
+
variants: { A: { weight: 50 }, B: { weight: 50 } },
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Page 2: Same variant returned
|
|
134
|
+
const variant = getABTestVariant({
|
|
135
|
+
testId: 'onboarding-flow',
|
|
136
|
+
variants: { A: { weight: 50 }, B: { weight: 50 } },
|
|
137
|
+
});
|
|
138
|
+
// Same user always gets the same variant
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Analyzing Results
|
|
142
|
+
|
|
143
|
+
### In Google Analytics 4
|
|
144
|
+
|
|
145
|
+
1. Navigate to Explore > Free Form
|
|
146
|
+
2. Add dimension: Custom Event Parameter > `ab_test_id`
|
|
147
|
+
3. Add dimension: Custom Event Parameter > `ab_variant`
|
|
148
|
+
4. Add metric: Event count, Conversions
|
|
149
|
+
5. Compare variant performance
|
|
150
|
+
|
|
151
|
+
### Statistical Significance
|
|
152
|
+
|
|
153
|
+
- Run tests for at least 2 weeks
|
|
154
|
+
- Aim for 1,000+ visitors per variant
|
|
155
|
+
- Use a significance calculator before concluding
|
|
156
|
+
- Don't stop tests early on promising results
|
|
157
|
+
|
|
158
|
+
## Best Practices
|
|
159
|
+
|
|
160
|
+
- Test one variable at a time
|
|
161
|
+
- Define success metrics before starting
|
|
162
|
+
- Run tests long enough for statistical significance
|
|
163
|
+
- Document all active tests
|
|
164
|
+
- Clean up completed tests
|
|
165
|
+
- Don't nest A/B tests unless variants are independent
|
|
166
|
+
|
|
167
|
+
## See Also
|
|
168
|
+
|
|
169
|
+
- [Tracking Events](./tracking-events.md)
|
|
170
|
+
- [Conversion Tracking](./conversion-tracking.md)
|
|
171
|
+
- [A/B Testing Guide](../../guides/ab-testing.md)
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Conversion Tracking
|
|
2
|
+
|
|
3
|
+
Track goals and measure conversion rates.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Conversion tracking measures when users complete desired actions:
|
|
8
|
+
|
|
9
|
+
- Form submissions
|
|
10
|
+
- CTA clicks
|
|
11
|
+
- Sign-ups
|
|
12
|
+
- Purchases
|
|
13
|
+
- Downloads
|
|
14
|
+
- Phone calls
|
|
15
|
+
|
|
16
|
+
## Tracking Conversions
|
|
17
|
+
|
|
18
|
+
### trackConversion
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
'use client';
|
|
22
|
+
import { trackConversion } from '@zoyth/simple-site-framework/client';
|
|
23
|
+
|
|
24
|
+
function handleSignup() {
|
|
25
|
+
trackConversion('signup_complete', {
|
|
26
|
+
method: 'email',
|
|
27
|
+
source: 'hero_cta',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### trackCTAClick
|
|
33
|
+
|
|
34
|
+
Shorthand for CTA conversion tracking:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { trackCTAClick } from '@zoyth/simple-site-framework/client';
|
|
38
|
+
|
|
39
|
+
<button onClick={() => trackCTAClick('get-started', 'pricing-page')}>
|
|
40
|
+
Get Started
|
|
41
|
+
</button>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Common Conversion Types
|
|
45
|
+
|
|
46
|
+
### Form Submission
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
function handleFormSubmit(formData) {
|
|
50
|
+
trackConversion('form_submit', {
|
|
51
|
+
form_name: 'contact',
|
|
52
|
+
form_location: 'contact_page',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Lead Generation
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
trackConversion('lead_generated', {
|
|
61
|
+
lead_type: 'demo_request',
|
|
62
|
+
source: 'landing_page',
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Purchase
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
trackConversion('purchase', {
|
|
70
|
+
transaction_id: 'T12345',
|
|
71
|
+
value: 99.99,
|
|
72
|
+
currency: 'USD',
|
|
73
|
+
items: ['pro_plan'],
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Download
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
trackConversion('file_download', {
|
|
81
|
+
file_name: 'whitepaper.pdf',
|
|
82
|
+
file_type: 'pdf',
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Phone Call
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
<TrackedLink
|
|
90
|
+
href="tel:+15551234567"
|
|
91
|
+
eventName="phone_call"
|
|
92
|
+
eventData={{ location: 'header' }}
|
|
93
|
+
>
|
|
94
|
+
Call Us
|
|
95
|
+
</TrackedLink>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Conversion Funnels
|
|
99
|
+
|
|
100
|
+
Track multi-step conversion paths:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// Step 1: View pricing
|
|
104
|
+
trackEvent('funnel_step', {
|
|
105
|
+
funnel: 'signup',
|
|
106
|
+
step: 1,
|
|
107
|
+
step_name: 'view_pricing',
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Step 2: Select plan
|
|
111
|
+
trackEvent('funnel_step', {
|
|
112
|
+
funnel: 'signup',
|
|
113
|
+
step: 2,
|
|
114
|
+
step_name: 'select_plan',
|
|
115
|
+
plan: 'pro',
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Step 3: Complete signup
|
|
119
|
+
trackConversion('signup_complete', {
|
|
120
|
+
funnel: 'signup',
|
|
121
|
+
step: 3,
|
|
122
|
+
plan: 'pro',
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## GTM Conversion Setup
|
|
127
|
+
|
|
128
|
+
### Google Ads Conversions
|
|
129
|
+
|
|
130
|
+
1. In GTM, create Conversion Linker tag
|
|
131
|
+
2. Create Google Ads Conversion Tracking tag
|
|
132
|
+
3. Set trigger to fire on your conversion event
|
|
133
|
+
4. Add conversion ID and label from Google Ads
|
|
134
|
+
|
|
135
|
+
### GA4 Conversions
|
|
136
|
+
|
|
137
|
+
1. In GA4, go to Configure > Events
|
|
138
|
+
2. Find your conversion event
|
|
139
|
+
3. Toggle "Mark as conversion"
|
|
140
|
+
|
|
141
|
+
## Conversion Attribution
|
|
142
|
+
|
|
143
|
+
### First Click
|
|
144
|
+
|
|
145
|
+
Attribute to first touchpoint:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
trackConversion('signup', {
|
|
149
|
+
first_touch_source: sessionStorage.getItem('first_source'),
|
|
150
|
+
first_touch_medium: sessionStorage.getItem('first_medium'),
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Last Click
|
|
155
|
+
|
|
156
|
+
Attribute to most recent touchpoint:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
trackConversion('signup', {
|
|
160
|
+
utm_source: searchParams.get('utm_source'),
|
|
161
|
+
utm_medium: searchParams.get('utm_medium'),
|
|
162
|
+
utm_campaign: searchParams.get('utm_campaign'),
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Conversion Components
|
|
167
|
+
|
|
168
|
+
### MobileCTA
|
|
169
|
+
|
|
170
|
+
Sticky mobile CTA with built-in conversion tracking:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { MobileCTA } from '@zoyth/simple-site-framework/components';
|
|
174
|
+
|
|
175
|
+
<MobileCTA
|
|
176
|
+
text="Get Started"
|
|
177
|
+
href="/signup"
|
|
178
|
+
trackingId="mobile-cta-signup"
|
|
179
|
+
/>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### ExitIntentModal
|
|
183
|
+
|
|
184
|
+
Track exit-intent conversions:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { ExitIntentModal } from '@zoyth/simple-site-framework/components';
|
|
188
|
+
|
|
189
|
+
<ExitIntentModal
|
|
190
|
+
onConversion={() => trackConversion('exit_intent_signup')}
|
|
191
|
+
/>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Best Practices
|
|
195
|
+
|
|
196
|
+
- Define conversions before building pages
|
|
197
|
+
- Track micro-conversions (newsletter signup) and macro-conversions (purchase)
|
|
198
|
+
- Include attribution data with conversions
|
|
199
|
+
- Test conversion tracking in staging before production
|
|
200
|
+
- Monitor conversion rates over time for regressions
|
|
201
|
+
|
|
202
|
+
## See Also
|
|
203
|
+
|
|
204
|
+
- [Tracking Events](./tracking-events.md)
|
|
205
|
+
- [A/B Testing](./ab-testing.md)
|
|
206
|
+
- [MobileCTA Component](../../components/conversion/MobileCTA.md)
|
|
207
|
+
- [ExitIntentModal Component](../../components/ExitIntentModal.md)
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Custom Events
|
|
2
|
+
|
|
3
|
+
Define and track application-specific events.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Beyond built-in tracking helpers, you can define custom events tailored to your application's needs.
|
|
8
|
+
|
|
9
|
+
## Creating Custom Events
|
|
10
|
+
|
|
11
|
+
### Basic Custom Event
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
'use client';
|
|
15
|
+
import { trackEvent } from '@zoyth/simple-site-framework/client';
|
|
16
|
+
|
|
17
|
+
trackEvent('feature_used', {
|
|
18
|
+
feature_name: 'dark_mode',
|
|
19
|
+
action: 'toggle_on',
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Typed Custom Events
|
|
24
|
+
|
|
25
|
+
Define types for consistency:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
type AppEvent =
|
|
29
|
+
| { name: 'feature_used'; data: { feature_name: string; action: string } }
|
|
30
|
+
| { name: 'content_viewed'; data: { content_id: string; content_type: string } }
|
|
31
|
+
| { name: 'search_performed'; data: { query: string; results_count: number } };
|
|
32
|
+
|
|
33
|
+
function trackAppEvent(event: AppEvent) {
|
|
34
|
+
trackEvent(event.name, event.data);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Usage
|
|
38
|
+
trackAppEvent({
|
|
39
|
+
name: 'search_performed',
|
|
40
|
+
data: { query: 'pricing', results_count: 5 },
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Event Naming Conventions
|
|
45
|
+
|
|
46
|
+
### Recommended Format
|
|
47
|
+
|
|
48
|
+
Use `object_action` pattern in snake_case:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// ✅ Good
|
|
52
|
+
'button_click'
|
|
53
|
+
'form_submit'
|
|
54
|
+
'video_play'
|
|
55
|
+
'page_scroll'
|
|
56
|
+
'menu_open'
|
|
57
|
+
'search_complete'
|
|
58
|
+
|
|
59
|
+
// ❌ Bad
|
|
60
|
+
'clickButton' // camelCase
|
|
61
|
+
'FORM_SUBMIT' // UPPER_CASE
|
|
62
|
+
'user clicked btn' // spaces
|
|
63
|
+
'click' // too vague
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Category Prefixes
|
|
67
|
+
|
|
68
|
+
Group related events:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// Navigation
|
|
72
|
+
'nav_menu_open'
|
|
73
|
+
'nav_link_click'
|
|
74
|
+
'nav_search_used'
|
|
75
|
+
|
|
76
|
+
// Content
|
|
77
|
+
'content_viewed'
|
|
78
|
+
'content_shared'
|
|
79
|
+
'content_bookmarked'
|
|
80
|
+
|
|
81
|
+
// Commerce
|
|
82
|
+
'product_viewed'
|
|
83
|
+
'cart_updated'
|
|
84
|
+
'checkout_started'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Event Properties
|
|
88
|
+
|
|
89
|
+
### Standard Properties
|
|
90
|
+
|
|
91
|
+
Include consistent context:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
trackEvent('button_click', {
|
|
95
|
+
// What
|
|
96
|
+
element_id: 'hero-cta',
|
|
97
|
+
element_text: 'Get Started',
|
|
98
|
+
|
|
99
|
+
// Where
|
|
100
|
+
page_path: '/pricing',
|
|
101
|
+
page_section: 'hero',
|
|
102
|
+
|
|
103
|
+
// Context
|
|
104
|
+
locale: 'en',
|
|
105
|
+
viewport: 'desktop',
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Dynamic Properties
|
|
110
|
+
|
|
111
|
+
Capture runtime context:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
function trackInteraction(elementId: string, action: string) {
|
|
115
|
+
trackEvent(`${elementId}_${action}`, {
|
|
116
|
+
timestamp: Date.now(),
|
|
117
|
+
page_path: window.location.pathname,
|
|
118
|
+
referrer: document.referrer,
|
|
119
|
+
screen_width: window.innerWidth,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Custom Event Patterns
|
|
125
|
+
|
|
126
|
+
### Feature Usage Tracking
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
function trackFeatureUsage(feature: string) {
|
|
130
|
+
trackEvent('feature_used', {
|
|
131
|
+
feature,
|
|
132
|
+
session_id: getSessionId(),
|
|
133
|
+
usage_count: incrementUsageCount(feature),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Error Tracking
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
function trackError(error: Error, context: string) {
|
|
142
|
+
trackEvent('app_error', {
|
|
143
|
+
error_message: error.message,
|
|
144
|
+
error_type: error.name,
|
|
145
|
+
context,
|
|
146
|
+
page_path: window.location.pathname,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### User Engagement
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
function trackEngagement(type: string, duration?: number) {
|
|
155
|
+
trackEvent('user_engagement', {
|
|
156
|
+
engagement_type: type,
|
|
157
|
+
engagement_duration: duration,
|
|
158
|
+
page_path: window.location.pathname,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Track time on page
|
|
163
|
+
trackEngagement('time_on_page', 45);
|
|
164
|
+
|
|
165
|
+
// Track interaction
|
|
166
|
+
trackEngagement('comment_posted');
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Search Tracking
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
function trackSearch(query: string, results: number) {
|
|
173
|
+
trackEvent('search', {
|
|
174
|
+
search_term: query,
|
|
175
|
+
results_count: results,
|
|
176
|
+
search_type: 'site_search',
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function trackSearchClick(query: string, position: number) {
|
|
181
|
+
trackEvent('search_result_click', {
|
|
182
|
+
search_term: query,
|
|
183
|
+
click_position: position,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## GTM Integration
|
|
189
|
+
|
|
190
|
+
Custom events push to GTM dataLayer:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Framework automatically pushes to dataLayer
|
|
194
|
+
trackEvent('custom_event', { key: 'value' });
|
|
195
|
+
|
|
196
|
+
// Equivalent to:
|
|
197
|
+
window.dataLayer.push({
|
|
198
|
+
event: 'custom_event',
|
|
199
|
+
key: 'value',
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
In GTM, create triggers based on custom event names to fire tags.
|
|
204
|
+
|
|
205
|
+
## Best Practices
|
|
206
|
+
|
|
207
|
+
- Document your event taxonomy
|
|
208
|
+
- Use consistent naming conventions across the team
|
|
209
|
+
- Include enough context to make events actionable
|
|
210
|
+
- Avoid tracking PII (emails, names, phone numbers)
|
|
211
|
+
- Don't over-track - focus on events that inform decisions
|
|
212
|
+
- Test events in GTM Preview mode before deploying
|
|
213
|
+
- Review and prune unused events periodically
|
|
214
|
+
|
|
215
|
+
## See Also
|
|
216
|
+
|
|
217
|
+
- [Tracking Events](./tracking-events.md)
|
|
218
|
+
- [Conversion Tracking](./conversion-tracking.md)
|
|
219
|
+
- [Privacy](./privacy.md)
|