/**
* Camp Quest Northwest A/B Testing Module
*
* Enhanced A/B testing infrastructure using Statsig and GA4
* Compatible with Squarespace Code Injection
*
* VERSION: 1.0.0
* LAST UPDATED: 2026-04-18
*
* CONSTITUTION ALIGNMENT:
* - Principle II: Conversion Optimization
* - All pages emit metrics
* - Mobile-first design
*/
(function() {
'use strict';
// ============================================
// CONFIGURATION
// ============================================
var CQAB = window.CQAB || {};
// Statsig configuration
CQAB.config = {
// Your existing client API key (from Code Injection)
statsigApiKey: 'client-v71t0wdZ3erybYH5gaY4zYKBvGyFdl0ZDs2CB3oDy5J',
// GA4 measurement ID
ga4Id: 'G-PCSSKGYTGW',
// UltraCamp domain for attribution
ultracampDomain: 'ultracamp.com',
// Cookie expiration (days)
cookieDays: 30,
// Debug mode (set true to see console logs)
debug: false
};
// ============================================
// UTILITY FUNCTIONS
// ============================================
/**
* Generate or retrieve stable user ID
* Uses cookies first, then sessionStorage, then generates new
*/
CQAB.getUserId = function() {
var userId = CQAB.getCookie('cq_user_id');
if (userId) return userId;
userId = sessionStorage.getItem('cq_user_id');
if (userId) {
CQAB.setCookie('cq_user_id', userId, CQAB.config.cookieDays);
return userId;
}
// Generate new ID
userId = 'cq_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
sessionStorage.setItem('cq_user_id', userId);
CQAB.setCookie('cq_user_id', userId, CQAB.config.cookieDays);
if (CQAB.config.debug) console.log('[CQAB] New user ID:', userId);
return userId;
};
/**
* Get cookie value
*/
CQAB.getCookie = function(name) {
var matches = document.cookie.match(new RegExp(
'(?:^|; )' + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=([^;]*)'
));
return matches ? decodeURIComponent(matches[1]) : null;
};
/**
* Set cookie value
*/
CQAB.setCookie = function(name, value, days) {
var expires = '';
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = '; expires=' + date.toUTCString();
}
document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/; SameSite=Lax';
};
/**
* Get variant for an experiment with persistence
*/
CQAB.getVariant = function(experimentName, defaultVariant) {
defaultVariant = defaultVariant || 'control';
var cookieKey = 'cq_exp_' + experimentName + '_variant';
var storedVariant = CQAB.getCookie(cookieKey);
if (storedVariant) return storedVariant;
// Check sessionStorage as fallback
var sessionVariant = sessionStorage.getItem(cookieKey);
if (sessionVariant) {
CQAB.setCookie(cookieKey, sessionVariant, CQAB.config.cookieDays);
return sessionVariant;
}
// Check Statsig if available
var variant = defaultVariant;
try {
if (window.Statsig && window.Statsig.getExperiment) {
var exp = window.Statsig.getExperiment(experimentName);
if (exp) {
variant = exp.get('variant', defaultVariant);
}
}
} catch (e) {
if (CQAB.config.debug) console.log('[CQAB] Statsig not ready, using default');
}
// Store the variant
sessionStorage.setItem(cookieKey, variant);
CQAB.setCookie(cookieKey, variant, CQAB.config.cookieDays);
if (CQAB.config.debug) console.log('[CQAB] Variant for', experimentName, ':', variant);
return variant;
};
/**
* Track page view with experiment attribution
*/
CQAB.trackPageView = function(experiments) {
experiments = experiments || [];
var pageViewData = {
page: window.location.pathname,
timestamp: new Date().toISOString(),
user_id: CQAB.getUserId()
};
// Add experiment variants
experiments.forEach(function(exp) {
pageViewData[exp.name + '_variant'] = CQAB.getVariant(exp.name, exp.default);
});
// Log to GA4
if (window.gtag) {
window.gtag('event', 'page_view', pageViewData);
}
// Log to Statsig if available
if (window.statsigCore) {
window.statsigCore.logEvent('page_view', pageViewData);
}
if (CQAB.config.debug) console.log('[CQAB] Page view tracked:', pageViewData);
};
/**
* Track conversion event with experiment attribution
*/
CQAB.trackConversion = function(goalName, value, experiments) {
experiments = experiments || [];
value = value || 0;
var conversionData = {
goal: goalName,
value: value,
timestamp: new Date().toISOString(),
user_id: CQAB.getUserId(),
page: window.location.pathname
};
// Add experiment variants
experiments.forEach(function(exp) {
conversionData[exp.name + '_variant'] = CQAB.getVariant(exp.name, exp.default);
});
// Log to GA4
if (window.gtag) {
window.gtag('event', goalName, conversionData);
}
// Log to Statsig if available
if (window.statsigCore) {
window.statsigCore.logEvent('conversion_' + goalName, conversionData);
}
if (CQAB.config.debug) console.log('[CQAB] Conversion tracked:', conversionData);
};
/**
* Track exposure event (when user is assigned to a variant)
*/
CQAB.trackExposure = function(experimentName) {
var variant = CQAB.getVariant(experimentName);
if (window.gtag) {
window.gtag('event', 'exp_exposure', {
experiment: experimentName,
variant: variant,
user_id: CQAB.getUserId()
});
}
if (CQAB.config.debug) console.log('[CQAB] Exposure:', experimentName, variant);
};
/**
* Decorate UltraCamp links with experiment attribution
*/
CQAB.decorateUltracampLinks = function(experiments) {
experiments = experiments || [];
var links = document.querySelectorAll('a[href*="' + CQAB.config.ultracampDomain + '"]');
links.forEach(function(link) {
// Skip if already decorated
if (link.dataset.cqDecorated) return;
link.dataset.cqDecorated = 'true';
// Add experiment params
try {
var url = new URL(link.href);
experiments.forEach(function(exp) {
var variant = CQAB.getVariant(exp.name, exp.default);
url.searchParams.set('exp_' + exp.name, variant);
});
link.href = url.toString();
} catch (e) {
// Invalid URL, skip
return;
}
// Add click listener for conversion tracking
link.addEventListener('click', function() {
CQAB.trackConversion('ultracamp_click', 1, experiments);
}, { once: true });
});
};
/**
* Run an A/B test with redirect (legacy style for /camp pages)
*/
CQAB.runRedirectTest = function(experimentName, variantAPath, variantBPath) {
variantAPath = variantAPath || '/camp-a';
variantBPath = variantBPath || '/camp-b';
var variant = CQAB.getVariant(experimentName, 'A');
var targetPath = (variant === 'B') ? variantBPath : variantAPath;
// Track exposure
CQAB.trackExposure(experimentName);
// Redirect if on base path
if (window.location.pathname === '/camp') {
window.location.replace(targetPath);
}
};
// ============================================
// AUTO-INITIALIZATION
// ============================================
/**
* Initialize when Statsig is ready
*/
CQAB.waitForStatsig = function(callback) {
var maxAttempts = 50;
var attempts = 0;
var check = function() {
attempts++;
if (window.Statsig && window.Statsig.instance) {
callback();
return;
}
if (attempts < maxAttempts) {
setTimeout(check, 50);
}
};
check();
};
/**
* Main initialization
*/
CQAB.init = function() {
if (CQAB.config.debug) console.log('[CQAB] Initializing...');
// Wait for Statsig then track page view
CQAB.waitForStatsig(function() {
// Track page view with known experiments
CQAB.trackPageView([
{ name: 'camp_landing_test_1', default: 'A' }
]);
// Track initial exposure
CQAB.trackExposure('camp_landing_test_1');
// Decorate UltraCamp links
CQAB.decorateUltracampLinks([
{ name: 'camp_landing_test_1', default: 'A' }
]);
});
// Also try immediately in case Statsig is already loaded
if (window.Statsig && window.Statsig.instance) {
CQAB.trackPageView([{ name: 'camp_landing_test_1', default: 'A' }]);
CQAB.trackExposure('camp_landing_test_1');
CQAB.decorateUltracampLinks([{ name: 'camp_landing_test_1', default: 'A' }]);
}
};
// ============================================
// HELPERS FOR SPECIFIC TESTS
// ============================================
/**
* Homepage conversion test
*/
CQAB.homepageTest = {
name: 'homepage_cta_test',
variants: {
control: { cta: 'Register Now', color: 'primary' },
treatment: { cta: 'Save Your Spot', color: 'accent' }
},
track: function() {
CQAB.trackPageView([{ name: this.name, default: 'control' }]);
}
};
/**
* Registration page test
*/
CQAB.registrationTest = {
name: 'registration_flow_test',
variants: {
control: { layout: 'single_page' },
treatment: { layout: 'wizard' }
},
track: function() {
CQAB.trackConversion('registration_start', 1, [{ name: this.name, default: 'control' }]);
}
};
/**
* Donation page test
*/
CQAB.donationTest = {
name: 'donation_amounts_test',
track: function(amount) {
CQAB.trackConversion('donation_made', amount || 0, [{ name: this.name, default: 'control' }]);
}
};
// Expose to global
window.CQAB = CQAB;
// Auto-init on DOM ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', CQAB.init);
} else {
CQAB.init();
}
})();