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