@keak/sdk 2.1.2 → 2.1.4

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/dist/index.js CHANGED
@@ -1616,138 +1616,15 @@ var KeakToolbar$1 = /*#__PURE__*/Object.freeze({
1616
1616
  KeakToolbar: KeakToolbar
1617
1617
  });
1618
1618
 
1619
- const Conversion = ({ children, type = 'custom', category, label, value, metadata = {}, disabled = false }) => {
1620
- // In production, render children without tracking
1621
- const isProduction = typeof process !== 'undefined' && process.env.NODE_ENV === 'production';
1622
- const elementRef = useRef(null);
1623
- const conversionId = useRef(`conv_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`);
1624
- useEffect(() => {
1625
- // Skip tracking in production
1626
- if (isProduction || disabled)
1627
- return;
1628
- // Track conversion element exposure (event tracking is disabled in SDK, this is a no-op)
1629
- keak.track('conversion_exposure', {
1630
- conversionId: conversionId.current,
1631
- type,
1632
- category,
1633
- label,
1634
- metadata: {
1635
- ...metadata,
1636
- timestamp: new Date().toISOString(),
1637
- url: window.location.href,
1638
- referrer: document.referrer
1639
- }
1640
- });
1641
- }, [isProduction, type, category, label, metadata, disabled]);
1642
- const handleClick = (event) => {
1643
- if (disabled || isProduction)
1644
- return;
1645
- // Extract additional context from the clicked element
1646
- event.currentTarget;
1647
- const clickedElement = event.target;
1648
- // Determine the actual clicked element type and content
1649
- let elementType = type;
1650
- let elementText = '';
1651
- let elementTag = '';
1652
- let href = '';
1653
- if (clickedElement) {
1654
- elementTag = clickedElement.tagName.toLowerCase();
1655
- elementText = clickedElement.textContent?.trim() || clickedElement.getAttribute('value') || clickedElement.getAttribute('alt') || '';
1656
- // Auto-detect element type if not specified
1657
- if (type === 'custom') {
1658
- if (elementTag === 'button' || clickedElement.getAttribute('role') === 'button') {
1659
- elementType = 'button';
1660
- }
1661
- else if (elementTag === 'a') {
1662
- elementType = 'link';
1663
- href = clickedElement.getAttribute('href') || '';
1664
- }
1665
- else if (elementTag === 'input' && (clickedElement.getAttribute('type') === 'submit' || clickedElement.getAttribute('type') === 'button')) {
1666
- elementType = 'button';
1667
- }
1668
- }
1669
- // Auto-detect category based on text content if not specified
1670
- if (!category && elementText) {
1671
- const text = elementText.toLowerCase();
1672
- if (/buy|purchase|checkout|order|cart/.test(text)) {
1673
- category = 'purchase';
1674
- }
1675
- else if (/sign.?up|register|join/.test(text)) {
1676
- category = 'signup';
1677
- }
1678
- else if (/download|get.?app/.test(text)) {
1679
- category = 'download';
1680
- }
1681
- else if (/demo|trial|preview/.test(text)) {
1682
- category = 'demo';
1683
- }
1684
- else if (/contact|call|phone/.test(text)) {
1685
- category = 'contact';
1686
- }
1687
- else if (/learn.?more|read.?more/.test(text)) {
1688
- category = 'engagement';
1689
- }
1690
- }
1691
- }
1692
- // Track the conversion with variant snapshot
1693
- const conversionName = `${category || 'uncategorized'}_${elementType}`;
1694
- const conversionValue = value || 1;
1695
- const additionalData = {
1696
- conversionId: conversionId.current,
1697
- type: elementType,
1698
- category: category || 'uncategorized',
1699
- label: label || elementText || 'unlabeled',
1700
- elementDetails: {
1701
- tag: elementTag,
1702
- text: elementText,
1703
- href,
1704
- className: clickedElement.className,
1705
- id: clickedElement.id
1706
- },
1707
- ...metadata,
1708
- viewport: {
1709
- width: window.innerWidth,
1710
- height: window.innerHeight
1711
- },
1712
- scroll: {
1713
- x: window.scrollX,
1714
- y: window.scrollY
1715
- },
1716
- referrer: document.referrer
1717
- };
1718
- // Use the new snapshot-based conversion tracking
1719
- keak.trackConversion(conversionName, conversionValue, additionalData);
1720
- // Optional: Add visual feedback for debugging in development
1721
- if (process.env.NODE_ENV === 'development') {
1722
- console.log('🎯 Conversion snapshot tracked:', {
1723
- id: conversionId.current,
1724
- conversionName,
1725
- conversionValue,
1726
- type: elementType,
1727
- category: category || 'uncategorized',
1728
- label: label || elementText || 'unlabeled',
1729
- element: elementTag,
1730
- snapshotApproach: true
1731
- });
1732
- // Show brief visual feedback
1733
- const element = elementRef.current;
1734
- if (element) {
1735
- const originalTransition = element.style.transition;
1736
- element.style.transition = 'all 0.2s ease';
1737
- element.style.transform = 'scale(0.98)';
1738
- setTimeout(() => {
1739
- element.style.transform = 'scale(1)';
1740
- setTimeout(() => {
1741
- element.style.transition = originalTransition;
1742
- }, 200);
1743
- }, 100);
1744
- }
1745
- }
1746
- };
1747
- return (jsx("div", { ref: elementRef, onClick: handleClick, style: {
1619
+ /**
1620
+ * Conversion component - renders children without tracking
1621
+ * Tracking is handled by the embedded script, not the SDK
1622
+ */
1623
+ const Conversion = ({ children, type = 'custom', category, disabled = false }) => {
1624
+ return (jsx("div", { style: {
1748
1625
  display: 'contents', // This makes the wrapper invisible to CSS layout
1749
1626
  pointerEvents: disabled ? 'none' : 'auto'
1750
- }, "data-keak-conversion-id": conversionId.current, "data-keak-conversion-type": type, "data-keak-conversion-category": category, children: children }));
1627
+ }, "data-keak-conversion-type": type, "data-keak-conversion-category": category, children: children }));
1751
1628
  };
1752
1629
 
1753
1630
  function sourcePathInjectionRuntime(sourceMapping) {
@@ -2198,23 +2075,18 @@ let toolbarInitialized = false;
2198
2075
  class KeakSDK {
2199
2076
  constructor(config) {
2200
2077
  this.assignments = {};
2201
- this.eventQueue = [];
2202
2078
  this.initialized = false;
2203
2079
  this.liveExperiments = new Map();
2204
- this.impressions = new Map(); // experimentId -> variantName -> count
2205
2080
  this.config = config;
2206
2081
  this.userId = config.userId || this.generateUserId();
2207
2082
  this.sessionId = config.sessionId || this.generateSessionId();
2208
2083
  this.deviceId = this.generateDeviceId();
2209
- this.loadImpressions();
2210
2084
  }
2211
2085
  async init() {
2212
2086
  try {
2213
2087
  // Use empty assignments - no backend integration
2214
2088
  this.assignments = {};
2215
2089
  this.initialized = true;
2216
- // Setup automatic event tracking
2217
- this.setupAutoTracking();
2218
2090
  if (this.config.debug) {
2219
2091
  console.log('Keak SDK initialized successfully', {
2220
2092
  assignments: this.assignments,
@@ -2227,99 +2099,6 @@ class KeakSDK {
2227
2099
  this.initialized = true; // Continue with empty assignments
2228
2100
  }
2229
2101
  }
2230
- getVariant(experimentKey, availableVariants) {
2231
- // Use local assignment only
2232
- if (availableVariants && availableVariants.length > 0) {
2233
- const localAssignment = this.assignVariant(experimentKey, availableVariants);
2234
- return localAssignment;
2235
- }
2236
- // Fallback to control
2237
- return 'control';
2238
- }
2239
- trackEvent(eventName, properties = {}) {
2240
- // Event tracking disabled - dashboard only receives impression data
2241
- if (this.config.debug) {
2242
- console.log(`🔇 [Keak SDK] Event tracking disabled: ${eventName}`, properties);
2243
- }
2244
- }
2245
- trackClick(elementId, text) {
2246
- // Click tracking disabled - dashboard only receives impression data
2247
- if (this.config.debug) {
2248
- console.log(`🔇 [Keak SDK] Click tracking disabled: ${elementId}`, text);
2249
- }
2250
- }
2251
- trackConversion(conversionName, value, additionalData) {
2252
- const snapshot = this.takeVariantSnapshot(conversionName, value, additionalData);
2253
- if (this.config.debug) {
2254
- console.log(`🎯 [Keak SDK] Conversion tracked: ${conversionName}`, {
2255
- value,
2256
- snapshot: snapshot.activeVariants,
2257
- totalExperiments: Object.keys(snapshot.activeVariants).length
2258
- });
2259
- }
2260
- }
2261
- // Take a snapshot of all currently active variants when conversion happens
2262
- takeVariantSnapshot(conversionName, value, additionalData) {
2263
- const activeVariants = {};
2264
- const experimentMetadata = {};
2265
- // Capture all live experiments and their current variant assignments
2266
- this.liveExperiments.forEach((experiment, experimentId) => {
2267
- const currentVariant = this.getVariant(experimentId, experiment.variants?.map((v) => v.name));
2268
- activeVariants[experimentId] = currentVariant;
2269
- experimentMetadata[experimentId] = {
2270
- name: experiment.name,
2271
- totalVariants: experiment.totalVariants,
2272
- variants: experiment.variants,
2273
- pageUrl: experiment.pageUrl
2274
- };
2275
- });
2276
- // Capture visitor metadata at conversion time
2277
- const visitorMetadata = this.captureVisitorMetadata();
2278
- const snapshot = {
2279
- conversionId: `conv_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2280
- conversionName,
2281
- conversionValue: value,
2282
- userId: this.userId,
2283
- sessionId: this.sessionId,
2284
- timestamp: new Date().toISOString(),
2285
- activeVariants,
2286
- experimentMetadata,
2287
- pageUrl: window.location.href,
2288
- visitorMetadata, // NEW: Include visitor metadata
2289
- additionalData: additionalData || {}
2290
- };
2291
- // Store conversion locally as backup
2292
- this.storeConversionLocally(snapshot);
2293
- return snapshot;
2294
- }
2295
- // Store conversion snapshot locally
2296
- storeConversionLocally(snapshot) {
2297
- try {
2298
- const stored = localStorage.getItem('keak_conversions') || '[]';
2299
- const conversions = JSON.parse(stored);
2300
- conversions.push(snapshot);
2301
- // Keep only last 100 conversions to prevent storage bloat
2302
- if (conversions.length > 100) {
2303
- conversions.splice(0, conversions.length - 100);
2304
- }
2305
- localStorage.setItem('keak_conversions', JSON.stringify(conversions));
2306
- }
2307
- catch (error) {
2308
- if (this.config.debug) {
2309
- console.warn('Failed to store conversion locally:', error);
2310
- }
2311
- }
2312
- }
2313
- setupAutoTracking() {
2314
- // Auto-tracking disabled
2315
- if (this.config.debug) {
2316
- console.log('🔇 [Keak SDK] Auto-tracking disabled');
2317
- }
2318
- }
2319
- flushEvents() {
2320
- // No event queue to flush - events are disabled
2321
- this.eventQueue = [];
2322
- }
2323
2102
  generateUserId() {
2324
2103
  // Try to get existing user ID from localStorage
2325
2104
  const existing = localStorage.getItem('keak_user_id');
@@ -2342,194 +2121,16 @@ class KeakSDK {
2342
2121
  localStorage.setItem('keak_device_id', deviceId.toString());
2343
2122
  return deviceId.toString();
2344
2123
  }
2345
- // Capture visitor metadata at the moment of event
2346
- captureVisitorMetadata() {
2347
- const ua = navigator.userAgent;
2348
- const platform = navigator.platform;
2349
- // Detect OS
2350
- let os = 'Unknown';
2351
- if (/iPhone/.test(ua))
2352
- os = 'iPhone';
2353
- else if (/iPad/.test(ua))
2354
- os = 'iPad';
2355
- else if (/Android/.test(ua))
2356
- os = 'Android';
2357
- else if (platform.includes('Win'))
2358
- os = 'Windows';
2359
- else if (platform.includes('Mac'))
2360
- os = 'macOS';
2361
- else if (platform.includes('Linux'))
2362
- os = 'Linux';
2363
- else
2364
- os = platform || 'Unknown';
2365
- // Detect browser
2366
- let browser = 'Unknown';
2367
- if (ua.includes('Edg/'))
2368
- browser = 'Edge';
2369
- else if (ua.includes('Chrome') && !ua.includes('Edg'))
2370
- browser = 'Chrome';
2371
- else if (ua.includes('Safari') && !ua.includes('Chrome'))
2372
- browser = 'Safari';
2373
- else if (ua.includes('Firefox'))
2374
- browser = 'Firefox';
2375
- // Get location from localStorage cache (updated by MetricsPanel)
2376
- let country = 'Unknown';
2377
- let ipAddress = 'Unknown';
2378
- try {
2379
- const locationCache = localStorage.getItem('keak_location_cache');
2380
- if (locationCache) {
2381
- const location = JSON.parse(locationCache);
2382
- country = location.country || 'Unknown';
2383
- ipAddress = location.ipAddress || 'Unknown';
2384
- }
2385
- }
2386
- catch (error) {
2387
- // Ignore parsing errors
2388
- }
2389
- return {
2390
- location: {
2391
- country,
2392
- ipAddress
2393
- },
2394
- device: {
2395
- os,
2396
- browser,
2397
- screenSize: `${window.screen.width} × ${window.screen.height}`,
2398
- viewport: `${window.innerWidth} × ${window.innerHeight}`,
2399
- userAgent: ua
2400
- },
2401
- session: {
2402
- userId: this.userId,
2403
- deviceId: this.deviceId,
2404
- sessionId: this.sessionId,
2405
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'Unknown',
2406
- language: navigator.language || 'Unknown'
2407
- }
2408
- };
2409
- }
2410
- // Simple hash function for deterministic randomization
2411
- simpleHash(str) {
2412
- let hash = 0;
2413
- for (let i = 0; i < str.length; i++) {
2414
- hash = ((hash << 5) - hash + str.charCodeAt(i)) & 0xffffffff;
2415
- }
2416
- return Math.abs(hash);
2417
- }
2418
- // Get or create variant assignment for user
2419
- assignVariant(experimentId, variants) {
2420
- const storageKey = `keak_assignment_${experimentId}`;
2421
- const stored = localStorage.getItem(storageKey);
2422
- if (stored && variants.includes(stored)) {
2423
- return stored;
2424
- }
2425
- // Deterministic randomization based on userId + experimentId
2426
- const hash = this.simpleHash(`${this.userId}_${experimentId}`);
2427
- const selectedVariant = variants[hash % variants.length];
2428
- try {
2429
- localStorage.setItem(storageKey, selectedVariant);
2430
- }
2431
- catch (error) {
2432
- if (this.config.debug) {
2433
- console.warn('Failed to store variant assignment:', error);
2434
- }
2435
- }
2436
- if (this.config.debug) {
2437
- console.log(`🎯 [Keak SDK] Assigned variant "${selectedVariant}" for experiment "${experimentId}" to user ${this.userId}`);
2438
- }
2439
- return selectedVariant;
2440
- }
2441
- // Impression tracking methods
2442
- loadImpressions() {
2443
- try {
2444
- const stored = localStorage.getItem('keak_impressions');
2445
- if (stored) {
2446
- const data = JSON.parse(stored);
2447
- this.impressions = new Map(Object.entries(data).map(([experimentId, variants]) => [
2448
- experimentId,
2449
- new Map(Object.entries(variants))
2450
- ]));
2451
- }
2452
- }
2453
- catch (error) {
2454
- if (this.config.debug) {
2455
- console.warn('Failed to load impressions from localStorage:', error);
2456
- }
2457
- }
2458
- }
2459
- saveImpressions() {
2460
- try {
2461
- const data = {};
2462
- this.impressions.forEach((variants, experimentId) => {
2463
- data[experimentId] = Object.fromEntries(variants);
2464
- });
2465
- localStorage.setItem('keak_impressions', JSON.stringify(data));
2466
- }
2467
- catch (error) {
2468
- if (this.config.debug) {
2469
- console.warn('Failed to save impressions to localStorage:', error);
2470
- }
2471
- }
2472
- }
2473
- trackImpression(experimentId, variantName) {
2474
- if (!this.impressions.has(experimentId)) {
2475
- this.impressions.set(experimentId, new Map());
2476
- }
2477
- const variants = this.impressions.get(experimentId);
2478
- const currentCount = variants.get(variantName) || 0;
2479
- variants.set(variantName, currentCount + 1);
2480
- this.saveImpressions();
2481
- // Store impression with visitor metadata
2482
- this.storeImpressionWithMetadata(experimentId, variantName);
2483
- }
2484
- storeImpressionWithMetadata(experimentId, variantName) {
2485
- try {
2486
- const visitorMetadata = this.captureVisitorMetadata();
2487
- const impressionEvent = {
2488
- experimentId,
2489
- variantName,
2490
- timestamp: new Date().toISOString(),
2491
- pageUrl: window.location.href,
2492
- visitorMetadata
2493
- };
2494
- // Store in separate detailed impressions log
2495
- const stored = localStorage.getItem('keak_impressions_detailed') || '[]';
2496
- const impressions = JSON.parse(stored);
2497
- impressions.push(impressionEvent);
2498
- // Keep only last 1000 impressions to prevent storage bloat
2499
- if (impressions.length > 1000) {
2500
- impressions.splice(0, impressions.length - 1000);
2501
- }
2502
- localStorage.setItem('keak_impressions_detailed', JSON.stringify(impressions));
2503
- }
2504
- catch (error) {
2505
- if (this.config.debug) {
2506
- console.warn('Failed to store impression metadata:', error);
2507
- }
2508
- }
2509
- }
2510
- getImpressions(experimentId) {
2511
- const variants = this.impressions.get(experimentId);
2512
- return variants ? Object.fromEntries(variants) : {};
2513
- }
2514
- getAllImpressions() {
2515
- const data = {};
2516
- this.impressions.forEach((variants, experimentId) => {
2517
- data[experimentId] = Object.fromEntries(variants);
2518
- });
2519
- return data;
2520
- }
2521
2124
  // Register live experiment
2522
2125
  registerLiveExperiment(experimentData) {
2523
- const impressions = this.getImpressions(experimentData.experimentId);
2524
2126
  this.liveExperiments.set(experimentData.experimentId, {
2525
2127
  ...experimentData,
2526
2128
  isActive: true,
2527
2129
  registeredAt: new Date().toISOString(),
2528
- currentVariant: this.assignments[experimentData.experimentId] || experimentData.variants[0]?.name || 'control',
2529
- impressions: impressions
2130
+ currentVariant: this.assignments[experimentData.experimentId] || experimentData.variants[0]?.name || 'control'
2530
2131
  });
2531
2132
  if (this.config.debug) {
2532
- console.log('📋 [Keak SDK] Live experiment registered:', experimentData.experimentId, 'Impressions:', impressions);
2133
+ console.log('📋 [Keak SDK] Live experiment registered:', experimentData.experimentId);
2533
2134
  }
2534
2135
  }
2535
2136
  // Get all live experiments for management panel
@@ -2543,7 +2144,6 @@ class KeakSDK {
2543
2144
  const experiment = this.liveExperiments.get(experimentId);
2544
2145
  if (experiment) {
2545
2146
  experiment.currentVariant = variant;
2546
- experiment.impressions = this.getImpressions(experimentId); // Update impressions
2547
2147
  this.liveExperiments.set(experimentId, experiment);
2548
2148
  }
2549
2149
  if (this.config.debug) {
@@ -2756,14 +2356,26 @@ function detectVariantElements(children) {
2756
2356
  }
2757
2357
  // Experiment Component
2758
2358
  const Experiment = ({ name, children, active = true }) => {
2759
- // In production, render children as-is (no experiment logic)
2760
- if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
2761
- return jsx(Fragment, { children: children });
2359
+ // CRITICAL: For Keak Code desktop projects, check if embedded script is loaded
2360
+ // This must be SYNCHRONOUS to prevent both variants from rendering (flicker)
2361
+ if (typeof window !== 'undefined') {
2362
+ const embeddedData = window.KEAK_EMBEDDED_DATA;
2363
+ const isDesktopProject = embeddedData && embeddedData.projectUuid;
2364
+ // If this is a desktop project, verify the script is fully loaded
2365
+ if (isDesktopProject) {
2366
+ const hasComputeFunction = typeof window.KeakAssign?.computeAssignments === 'function';
2367
+ if (!hasComputeFunction) {
2368
+ // Script not ready yet - return null to prevent flicker
2369
+ console.log(`[Keak SDK] Waiting for embedded script to load for "${name}"...`);
2370
+ return null;
2371
+ }
2372
+ console.log(`[Keak SDK] Embedded script ready for "${name}"`);
2373
+ }
2762
2374
  }
2763
- // Access global SDK instance directly (no context needed)
2764
- const assignments = keakInstance?.assignments || {};
2765
2375
  // Use enhanced variant detection
2766
2376
  const variantElements = detectVariantElements(children);
2377
+ // Access global SDK instance directly (no context needed)
2378
+ const assignments = keakInstance?.assignments || {};
2767
2379
  // Extract comprehensive variant metadata
2768
2380
  const variantMetadata = variantElements.map(variant => {
2769
2381
  const variantContent = extractVariantContent(variant.props.children);
@@ -2784,7 +2396,7 @@ const Experiment = ({ name, children, active = true }) => {
2784
2396
  window.location.hostname === '127.0.0.1' ||
2785
2397
  window.location.port !== '' ||
2786
2398
  keakInstance?.config.debug);
2787
- // Register experiment with SDK for live management
2399
+ // Register experiment with SDK for live management (for toolbar)
2788
2400
  useEffect(() => {
2789
2401
  if (keakInstance && variantElements.length > 0) {
2790
2402
  // Register experiment with enhanced metadata
@@ -2805,39 +2417,10 @@ const Experiment = ({ name, children, active = true }) => {
2805
2417
  };
2806
2418
  // Register live experiment for management panel
2807
2419
  keakInstance.registerLiveExperiment(experimentData);
2808
- // Only track impressions if experiment is active
2809
- if (active) {
2810
- const variantNames = variantMetadata.map(v => v.name);
2811
- // In dev mode, don't call getVariant (which stores in localStorage)
2812
- // Instead, use "treatment" for tracking purposes
2813
- let assignedVariant;
2814
- if (isDevMode) {
2815
- assignedVariant = variantNames.includes('treatment') ? 'treatment' : variantNames[0];
2816
- if (keakInstance.config.debug) {
2817
- console.log(`🎯 [Keak SDK] Experiment "${name}" in dev mode, using "${assignedVariant}" for tracking (not stored)`);
2818
- }
2819
- }
2820
- else {
2821
- // Production mode: use normal assignment (stores in localStorage)
2822
- assignedVariant = keakInstance.getVariant(name, variantNames);
2823
- if (keakInstance.config.debug) {
2824
- console.log(`🎯 [Keak SDK] Split test assignment for "${name}": → Variant "${assignedVariant}"`);
2825
- }
2826
- }
2827
- // Track impression immediately when variant is determined
2828
- if (assignedVariant) {
2829
- keakInstance.trackImpression(name, assignedVariant);
2830
- }
2831
- }
2832
- else {
2833
- if (keakInstance.config.debug) {
2834
- console.log(`🔇 [Keak SDK] Experiment "${name}" is inactive, not tracking impressions`);
2835
- }
2836
- }
2837
2420
  }
2838
- }, [name, variantElements.length, variantMetadata, active, isDevMode]);
2421
+ }, [name, variantElements.length, variantMetadata, active]);
2839
2422
  // Get variant assignment from SDK (with proper split testing)
2840
- const variantNames = variantMetadata.map(v => v.name);
2423
+ variantMetadata.map(v => v.name);
2841
2424
  let selectedIndex;
2842
2425
  // Priority 1: Check for forced variant from setExperimentVariant (highest priority)
2843
2426
  const forcedVariant = keakInstance?.assignments[name] || assignments[name];
@@ -2904,16 +2487,14 @@ const Experiment = ({ name, children, active = true }) => {
2904
2487
  }
2905
2488
  }
2906
2489
  else {
2907
- // Active in production: Normal A/B split testing
2908
- const assignedVariantName = keakInstance?.getVariant(name, variantNames) || variantNames[0];
2909
- // Find the index of the assigned variant
2910
- selectedIndex = variantElements.findIndex((variant) => variant.props.name === assignedVariantName);
2911
- // Safety fallback - if assigned variant not found, use first variant
2912
- if (selectedIndex === -1 && variantElements.length > 0) {
2913
- selectedIndex = 0;
2914
- if (keakInstance?.config.debug) {
2915
- console.warn(`⚠️ [Keak SDK] Assigned variant "${assignedVariantName}" not found, using first variant`);
2916
- }
2490
+ // Active in production: Show control (original) by default
2491
+ // Embedded script will handle A/B assignment if present
2492
+ selectedIndex = variantElements.findIndex((variant) => variant.props.name === 'control');
2493
+ if (selectedIndex === -1) {
2494
+ selectedIndex = 0; // Fallback to first variant if no "control" named variant
2495
+ }
2496
+ if (keakInstance?.config.debug) {
2497
+ console.log(`🎯 [Keak SDK] Experiment "${name}" in production, showing control (embedded script handles A/B)`);
2917
2498
  }
2918
2499
  }
2919
2500
  }
@@ -2992,33 +2573,7 @@ const keak = {
2992
2573
  }
2993
2574
  return Promise.resolve();
2994
2575
  },
2995
- getVariant: (experimentKey, availableVariants) => {
2996
- if (!keakInstance) {
2997
- console.warn('Keak SDK not initialized. Call keak.init() first.');
2998
- return 'control';
2999
- }
3000
- return keakInstance.getVariant(experimentKey, availableVariants);
3001
- },
3002
- track: (eventName, properties) => {
3003
- // Event tracking disabled - dashboard only receives impression data
3004
- if (keakInstance?.config.debug) {
3005
- console.log(`🔇 [Keak SDK] Global event tracking disabled: ${eventName}`, properties);
3006
- }
3007
- },
3008
- trackClick: (elementId, text) => {
3009
- // Click tracking disabled - dashboard only receives impression data
3010
- if (keakInstance?.config.debug) {
3011
- console.log(`🔇 [Keak SDK] Global click tracking disabled: ${elementId}`, text);
3012
- }
3013
- },
3014
- trackConversion: (conversionName, value, additionalData) => {
3015
- if (!keakInstance) {
3016
- console.warn('Keak SDK not initialized. Call keak.init() first.');
3017
- return;
3018
- }
3019
- keakInstance.trackConversion(conversionName, value, additionalData);
3020
- },
3021
- // Live experiment management functions
2576
+ // Live experiment management functions (for toolbar)
3022
2577
  getAllLiveExperiments: () => {
3023
2578
  if (!keakInstance) {
3024
2579
  console.warn('Keak SDK not initialized. Call keak.init() first.');
@@ -3029,24 +2584,6 @@ const keak = {
3029
2584
  setExperimentVariant: (experimentId, variant) => {
3030
2585
  keakInstance?.setExperimentVariant(experimentId, variant);
3031
2586
  },
3032
- // Impression tracking methods
3033
- trackImpression: (experimentId, variantName) => {
3034
- keakInstance?.trackImpression(experimentId, variantName);
3035
- },
3036
- getImpressions: (experimentId) => {
3037
- if (!keakInstance) {
3038
- console.warn('Keak SDK not initialized. Call keak.init() first.');
3039
- return {};
3040
- }
3041
- return keakInstance.getImpressions(experimentId);
3042
- },
3043
- getAllImpressions: () => {
3044
- if (!keakInstance) {
3045
- console.warn('Keak SDK not initialized. Call keak.init() first.');
3046
- return {};
3047
- }
3048
- return keakInstance.getAllImpressions();
3049
- },
3050
2587
  };
3051
2588
  // Initialize toolbar (called by useKeak hook)
3052
2589
  function initializeToolbar(config) {