@cascayd/experiment 0.3.16 → 0.3.19

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.
@@ -57,9 +57,15 @@
57
57
  // Try to get API key from window (if SDK was initialized)
58
58
  function getAPIKey() {
59
59
  if (typeof window !== 'undefined' && window._cascaydAPIKey) {
60
+ console.log('[cascayd-shopify] ✅ Found API key from window._cascaydAPIKey');
60
61
  return window._cascaydAPIKey;
61
62
  }
62
- return API_KEY;
63
+ if (API_KEY) {
64
+ console.log('[cascayd-shopify] ✅ Found API key from local variable');
65
+ return API_KEY;
66
+ }
67
+ console.warn('[cascayd-shopify] ⚠️ No API key found! window._cascaydAPIKey =', typeof window !== 'undefined' ? window._cascaydAPIKey : 'N/A');
68
+ return '';
63
69
  }
64
70
 
65
71
  // Direct API call functions (same logic as SDK)
@@ -151,6 +157,8 @@
151
157
  const variantId = opts.variantId || fromCookie;
152
158
  if (variantId) {
153
159
  body.variant_id = variantId;
160
+ } else {
161
+ console.warn('[cascayd-shopify] ⚠️ No variant_id available for experiment:', opts.experimentId);
154
162
  }
155
163
  }
156
164
 
@@ -158,22 +166,51 @@
158
166
  body.value = opts.value;
159
167
  }
160
168
 
169
+ // Auto-capture route if not provided
170
+ if (opts.route) {
171
+ body.route = opts.route;
172
+ } else if (typeof window !== 'undefined' && window.location) {
173
+ body.route = window.location.pathname;
174
+ }
175
+
176
+ // Validate required fields
177
+ if (!body.experiment_id || !body.variant_id) {
178
+ const error = new Error('Missing required fields: experiment_id=' + body.experiment_id + ', variant_id=' + body.variant_id);
179
+ console.error('[cascayd-shopify] ❌', error.message, 'Body:', body);
180
+ throw error;
181
+ }
182
+
161
183
  const headers = {
162
184
  'Content-Type': 'application/json'
163
185
  };
164
186
  const apiKey = getAPIKey();
165
187
  if (apiKey) {
166
188
  headers.Authorization = 'Bearer ' + apiKey;
189
+ } else {
190
+ console.warn('[cascayd-shopify] ⚠️ No API key found! Check window._cascaydAPIKey');
167
191
  }
168
192
 
169
- const res = await fetch(BASE_URL + '/events', {
170
- method: 'POST',
171
- headers: headers,
172
- body: JSON.stringify(body)
173
- });
193
+ console.log('[cascayd-shopify] 📤 Sending event:', { type: type, body: body, hasApiKey: !!apiKey });
174
194
 
175
- if (!res.ok) {
176
- throw new Error('Record failed: ' + res.status);
195
+ try {
196
+ const res = await fetch(BASE_URL + '/events', {
197
+ method: 'POST',
198
+ headers: headers,
199
+ body: JSON.stringify(body)
200
+ });
201
+
202
+ if (!res.ok) {
203
+ const errorText = await res.text();
204
+ console.error('[cascayd-shopify] ❌ API error response:', res.status, errorText);
205
+ throw new Error('Record failed: ' + res.status + ' - ' + errorText);
206
+ }
207
+
208
+ const result = await res.json();
209
+ console.log('[cascayd-shopify] ✅ Event recorded successfully:', result);
210
+ return result;
211
+ } catch (error) {
212
+ console.error('[cascayd-shopify] ❌ Fetch error:', error);
213
+ throw error;
177
214
  }
178
215
  }
179
216
 
@@ -267,6 +304,92 @@
267
304
  }
268
305
  }
269
306
 
307
+ // Find variant ID from element (with DOM fallback)
308
+ function findVariantIdFromElement(el, experimentId) {
309
+ // First try cookie (most reliable)
310
+ const fromCookie = readVariantChoice(experimentId);
311
+ if (fromCookie) {
312
+ console.log('[cascayd-shopify] 📖 Found variant from cookie:', fromCookie);
313
+ return fromCookie;
314
+ }
315
+
316
+ // Fallback: traverse up DOM to find parent with data-cascayd-variant
317
+ console.log('[cascayd-shopify] 🔍 Cookie not found, traversing DOM for variant ID...');
318
+ let current = el;
319
+ while (current) {
320
+ const variantId = current.getAttribute('data-cascayd-variant');
321
+ if (variantId) {
322
+ console.log('[cascayd-shopify] ✅ Found variant ID in DOM:', variantId);
323
+ return variantId;
324
+ }
325
+
326
+ // Check if we're inside an experiment container
327
+ const experimentIdAttr = current.getAttribute('data-cascayd-experiment');
328
+ if (experimentIdAttr === experimentId) {
329
+ // We're in the right experiment container, continue up
330
+ current = current.parentElement;
331
+ } else {
332
+ // Move up to find experiment container
333
+ current = current.parentElement;
334
+ }
335
+ }
336
+
337
+ console.warn('[cascayd-shopify] ⚠️ No variant ID found for experiment:', experimentId);
338
+ return null;
339
+ }
340
+
341
+ // Setup conversion tracking for an experiment
342
+ function setupConversionTracking(experimentId, sdk) {
343
+ const selector = '[data-cascayd-experiment="' + experimentId + '"] [data-cascayd-conversion]';
344
+ const elements = document.querySelectorAll(selector);
345
+ console.log('[cascayd-shopify] 🎯 Setting up conversion tracking for experiment:', experimentId, 'found', elements.length, 'conversion elements', 'hasSDK:', !!sdk);
346
+
347
+ elements.forEach(function(el) {
348
+ // Skip if already tracked
349
+ if (el.hasAttribute('data-cascayd-tracked')) {
350
+ console.log('[cascayd-shopify] ⏭️ Element already tracked, skipping');
351
+ return;
352
+ }
353
+
354
+ el.setAttribute('data-cascayd-tracked', 'true');
355
+ console.log('[cascayd-shopify] ✅ Marked element as tracked:', el);
356
+
357
+ el.addEventListener('click', function(e) {
358
+ console.log('[cascayd-shopify] 🎯 Conversion click detected!');
359
+ const variantId = findVariantIdFromElement(el, experimentId);
360
+ if (variantId) {
361
+ console.log('[cascayd-shopify] 📊 Recording conversion:', { experimentId, variantId, hasSDK: !!sdk, hasRecordFn: !!(sdk && sdk.record) });
362
+
363
+ // Use SDK's record function if available (same as impressions), otherwise fallback to direct API call
364
+ if (sdk && sdk.record) {
365
+ console.log('[cascayd-shopify] ✅ Using SDK record function for conversion');
366
+ sdk.record('conversion', {
367
+ experimentId: experimentId,
368
+ variantId: variantId
369
+ }).then(function() {
370
+ console.log('[cascayd-shopify] ✅ Conversion recorded successfully via SDK');
371
+ }).catch(function(error) {
372
+ console.error('[cascayd-shopify] ❌ Failed to record conversion via SDK:', error);
373
+ });
374
+ } else {
375
+ console.log('[cascayd-shopify] ⚠️ SDK record not available, using direct API call');
376
+ // Fallback to direct API call
377
+ recordDirect('conversion', {
378
+ experimentId: experimentId,
379
+ variantId: variantId
380
+ }).then(function() {
381
+ console.log('[cascayd-shopify] ✅ Conversion recorded successfully via direct API');
382
+ }).catch(function(error) {
383
+ console.error('[cascayd-shopify] ❌ Failed to record conversion via direct API:', error);
384
+ });
385
+ }
386
+ } else {
387
+ console.warn('[cascayd-shopify] ⚠️ No variant found for experiment', experimentId, 'when recording conversion');
388
+ }
389
+ });
390
+ });
391
+ }
392
+
270
393
  // Process a single experiment
271
394
  async function processExperiment(experimentId, variantElements, sdk) {
272
395
  console.log('[cascayd-shopify] 🔬 Processing experiment:', { experimentId, variantElementCount: variantElements.length, hasSDK: !!sdk });
@@ -340,6 +463,9 @@
340
463
  el.classList.remove('cascayd-visible', 'cascayd-visible-inline');
341
464
  }
342
465
  });
466
+
467
+ // Setup conversion tracking after variant is shown
468
+ setupConversionTracking(experimentId, sdk);
343
469
  console.log('[cascayd-shopify] ✅ Finished processing experiment:', experimentId);
344
470
  }
345
471
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cascayd/experiment",
3
- "version": "0.3.16",
3
+ "version": "0.3.19",
4
4
  "description": "A lightweight A/B testing SDK for React applications with server-side analytics integration",
5
5
  "keywords": [
6
6
  "ab-testing",