@zaplier/sdk 1.7.0 → 1.7.3

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.cjs CHANGED
@@ -19268,85 +19268,14 @@ class AutoTracker {
19268
19268
  this.scrollThrottle = 0;
19269
19269
  this.isInitialized = false;
19270
19270
  this.delegationHandlers = new Map();
19271
- this.handleScroll = () => {
19272
- if (!this.config.trackScrolls)
19273
- return;
19274
- // Throttle scroll events for performance
19275
- const now = Date.now();
19276
- if (now - this.scrollThrottle < 100)
19277
- return; // 100ms throttle
19278
- this.scrollThrottle = now;
19279
- const scrollElements = document.querySelectorAll('[data-track-scroll]');
19280
- if (this.config.debug && scrollElements.length > 0) {
19281
- console.log(`[AutoTracker] Checking ${scrollElements.length} scroll elements`, {
19282
- scrollY: window.scrollY,
19283
- innerHeight: window.innerHeight
19284
- });
19285
- }
19286
- scrollElements.forEach((element) => {
19287
- let hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
19288
- if (hasTriggered)
19289
- return;
19290
- const threshold = parseFloat(element.getAttribute("data-scroll-threshold") || "0.5");
19291
- const rect = element.getBoundingClientRect();
19292
- const elementHeight = rect.height;
19293
- const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
19294
- const visibilityRatio = Math.max(0, visibleHeight) / elementHeight;
19295
- if (this.config.debug) {
19296
- console.log(`[AutoTracker] Element check:`, {
19297
- elementId: element.id || element.className,
19298
- visibilityRatio: Math.round(visibilityRatio * 100) / 100,
19299
- threshold,
19300
- triggered: hasTriggered
19301
- });
19302
- }
19303
- if (visibilityRatio >= threshold) {
19304
- element.setAttribute('data-scroll-triggered', 'true');
19305
- const eventName = element.getAttribute("data-track-scroll");
19306
- if (!eventName)
19307
- return;
19308
- const metadata = this.extractMetadata(element);
19309
- this.trackEvent(eventName, {
19310
- type: "scroll",
19311
- element: element.tagName.toLowerCase(),
19312
- threshold,
19313
- scrollDepth: window.scrollY,
19314
- visibilityRatio: Math.round(visibilityRatio * 100) / 100,
19315
- ...metadata,
19316
- });
19317
- if (this.config.debug) {
19318
- console.log(`[AutoTracker] Scroll tracked: ${eventName}`, {
19319
- threshold,
19320
- visibilityRatio,
19321
- scrollDepth: window.scrollY,
19322
- ...metadata
19323
- });
19324
- }
19325
- }
19326
- });
19327
- };
19328
- this.handleClick = (event) => {
19329
- if (!this.config.trackClicks)
19330
- return;
19331
- const target = event.target;
19332
- if (!target || !target.hasAttribute("data-track-click"))
19333
- return;
19334
- const eventName = target.getAttribute("data-track-click");
19335
- if (!eventName)
19336
- return;
19337
- const metadata = this.extractMetadata(target);
19338
- this.trackEvent(eventName, {
19339
- type: "click",
19340
- element: target.tagName.toLowerCase(),
19341
- ...metadata,
19342
- });
19343
- if (this.config.debug) {
19344
- console.log(`[AutoTracker] Click tracked: ${eventName}`, {
19345
- element: target.tagName.toLowerCase(),
19346
- ...metadata
19347
- });
19348
- }
19349
- };
19271
+ this.initializationAttempts = 0;
19272
+ this.maxInitializationAttempts = 3;
19273
+ this.diagnostics = {};
19274
+ /**
19275
+ * Cache scroll elements for better performance
19276
+ */
19277
+ this.cachedScrollElements = null;
19278
+ this.lastScrollElementsCheck = 0;
19350
19279
  this.sdkInstance = sdkInstance;
19351
19280
  this.config = {
19352
19281
  enabled: true,
@@ -19365,33 +19294,208 @@ class AutoTracker {
19365
19294
  start() {
19366
19295
  if (!this.config.enabled)
19367
19296
  return;
19297
+ this.initializationAttempts++;
19298
+ // Enhanced diagnostics
19299
+ this.runDiagnostics();
19368
19300
  if (this.config.debug) {
19369
- console.log("[Zaplier AutoTracker] Iniciando auto tracking", {
19370
- enabled: this.config.enabled,
19371
- trackClicks: this.config.trackClicks,
19372
- trackScrolls: this.config.trackScrolls,
19373
- trackViews: this.config.trackViews,
19374
- trackHovers: this.config.trackHovers,
19375
- trackForms: this.config.trackForms,
19376
- domReady: document.readyState
19377
- });
19301
+ console.log("[🔥 AutoTracker ENHANCED] Starting auto tracking", this.diagnostics);
19378
19302
  }
19379
- // Aguardar DOM ready se necessário
19380
- if (document.readyState === 'loading') {
19381
- if (this.config.debug) {
19382
- console.log("[Zaplier AutoTracker] DOM still loading, waiting for DOMContentLoaded...");
19303
+ // Multiple initialization strategies
19304
+ this.tryInitialization();
19305
+ }
19306
+ /**
19307
+ * Run comprehensive diagnostics
19308
+ */
19309
+ runDiagnostics() {
19310
+ this.diagnostics = {
19311
+ timestamp: new Date().toISOString(),
19312
+ attempt: this.initializationAttempts,
19313
+ environment: {
19314
+ domReady: document.readyState,
19315
+ reactDetected: this.detectReact(),
19316
+ reactVersion: this.getReactVersion(),
19317
+ userAgent: navigator.userAgent,
19318
+ isMobile: /Mobile|Android|iPhone|iPad/.test(navigator.userAgent),
19319
+ isSafari: /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent),
19320
+ protocol: window.location.protocol,
19321
+ isLocalhost: window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
19322
+ },
19323
+ dom: {
19324
+ documentElement: !!document.documentElement,
19325
+ body: !!document.body,
19326
+ querySelector: typeof document.querySelector === 'function',
19327
+ addEventListener: typeof document.addEventListener === 'function',
19328
+ elementsFound: this.getElementCounts(),
19329
+ hasReactRoot: this.findReactRoot()
19330
+ },
19331
+ tracking: {
19332
+ sdkInstance: !!this.sdkInstance,
19333
+ trackCustomEvent: typeof this.sdkInstance?.trackCustomEvent === 'function',
19334
+ config: this.config,
19335
+ isInitialized: this.isInitialized,
19336
+ activeHandlers: Array.from(this.delegationHandlers.keys())
19383
19337
  }
19338
+ };
19339
+ }
19340
+ /**
19341
+ * Detect React presence
19342
+ */
19343
+ detectReact() {
19344
+ return !!(window.__REACT_DEVTOOLS_GLOBAL_HOOK__ ||
19345
+ window.React ||
19346
+ document.querySelector('[data-reactroot]') ||
19347
+ document.querySelector('#root') ||
19348
+ document.querySelector('#__next'));
19349
+ }
19350
+ /**
19351
+ * Get React version if available
19352
+ */
19353
+ getReactVersion() {
19354
+ try {
19355
+ const reactInstance = window.React;
19356
+ return reactInstance?.version || null;
19357
+ }
19358
+ catch {
19359
+ return null;
19360
+ }
19361
+ }
19362
+ /**
19363
+ * Find React root element
19364
+ */
19365
+ findReactRoot() {
19366
+ const reactRoot = document.querySelector('[data-reactroot]') ||
19367
+ document.querySelector('#root') ||
19368
+ document.querySelector('#__next') ||
19369
+ document.querySelector('div[data-react-helmet]');
19370
+ return reactRoot ? reactRoot.tagName + (reactRoot.id ? '#' + reactRoot.id : '') : null;
19371
+ }
19372
+ /**
19373
+ * Get element counts for all tracking types
19374
+ */
19375
+ getElementCounts() {
19376
+ return {
19377
+ click: document.querySelectorAll('[data-track-click]').length,
19378
+ scroll: document.querySelectorAll('[data-track-scroll]').length,
19379
+ view: document.querySelectorAll('[data-track-view]').length,
19380
+ hover: document.querySelectorAll('[data-track-hover]').length,
19381
+ form: document.querySelectorAll('[data-track-form]').length
19382
+ };
19383
+ }
19384
+ /**
19385
+ * Try multiple initialization strategies
19386
+ */
19387
+ tryInitialization() {
19388
+ const strategies = [
19389
+ () => this.immediateInitialization(),
19390
+ () => this.delayedInitialization(100),
19391
+ () => this.delayedInitialization(500),
19392
+ () => this.delayedInitialization(1000),
19393
+ () => this.reactReadyInitialization()
19394
+ ];
19395
+ // Try immediate initialization first
19396
+ if (document.readyState === 'complete') {
19397
+ this.attemptStrategy(0, strategies);
19398
+ }
19399
+ else if (document.readyState === 'interactive') {
19400
+ // DOM ready but resources still loading
19401
+ this.attemptStrategy(1, strategies);
19402
+ }
19403
+ else {
19404
+ // DOM still loading
19384
19405
  document.addEventListener('DOMContentLoaded', () => {
19385
- if (this.config.debug) {
19386
- console.log("[Zaplier AutoTracker] DOMContentLoaded fired, initializing tracking...");
19387
- }
19388
- this.initializeTracking();
19406
+ this.attemptStrategy(0, strategies);
19389
19407
  }, { once: true });
19390
19408
  }
19391
- else {
19409
+ }
19410
+ /**
19411
+ * Attempt initialization strategy with fallback
19412
+ */
19413
+ attemptStrategy(index, strategies) {
19414
+ if (index >= strategies.length || this.isInitialized)
19415
+ return;
19416
+ if (this.config.debug) {
19417
+ console.log(`[🔄 AutoTracker] Trying initialization strategy ${index + 1}/${strategies.length}`);
19418
+ }
19419
+ try {
19420
+ const strategy = strategies[index];
19421
+ if (strategy && typeof strategy === 'function') {
19422
+ strategy();
19423
+ // Verify initialization after a short delay
19424
+ setTimeout(() => {
19425
+ if (!this.verifyInitialization()) {
19426
+ if (this.config.debug) {
19427
+ console.log(`[⚠️ AutoTracker] Strategy ${index + 1} failed verification, trying next...`);
19428
+ }
19429
+ this.attemptStrategy(index + 1, strategies);
19430
+ }
19431
+ else {
19432
+ if (this.config.debug) {
19433
+ console.log(`[✅ AutoTracker] Strategy ${index + 1} successful!`);
19434
+ }
19435
+ }
19436
+ }, 50);
19437
+ }
19438
+ else {
19439
+ // Strategy is undefined or not a function, try next
19440
+ this.attemptStrategy(index + 1, strategies);
19441
+ }
19442
+ }
19443
+ catch (error) {
19444
+ if (this.config.debug) {
19445
+ console.error(`[❌ AutoTracker] Strategy ${index + 1} error:`, error);
19446
+ }
19447
+ this.attemptStrategy(index + 1, strategies);
19448
+ }
19449
+ }
19450
+ /**
19451
+ * Immediate initialization
19452
+ */
19453
+ immediateInitialization() {
19454
+ this.initializeTracking();
19455
+ }
19456
+ /**
19457
+ * Delayed initialization
19458
+ */
19459
+ delayedInitialization(delay) {
19460
+ setTimeout(() => {
19392
19461
  this.initializeTracking();
19462
+ }, delay);
19463
+ }
19464
+ /**
19465
+ * React-specific initialization timing
19466
+ */
19467
+ reactReadyInitialization() {
19468
+ // Wait for React to finish rendering
19469
+ if (typeof window.requestAnimationFrame === 'function') {
19470
+ window.requestAnimationFrame(() => {
19471
+ setTimeout(() => {
19472
+ this.initializeTracking();
19473
+ }, 0);
19474
+ });
19475
+ }
19476
+ else {
19477
+ setTimeout(() => {
19478
+ this.initializeTracking();
19479
+ }, 16); // ~60fps fallback
19393
19480
  }
19394
19481
  }
19482
+ /**
19483
+ * Verify initialization was successful
19484
+ */
19485
+ verifyInitialization() {
19486
+ const elementsFound = this.getElementCounts();
19487
+ const totalElements = Object.values(elementsFound).reduce((sum, count) => sum + count, 0);
19488
+ const hasActiveHandlers = this.delegationHandlers.size > 0;
19489
+ if (this.config.debug) {
19490
+ console.log('[🔍 AutoTracker] Verification:', {
19491
+ isInitialized: this.isInitialized,
19492
+ elementsFound: totalElements,
19493
+ hasActiveHandlers,
19494
+ handlersActive: Array.from(this.delegationHandlers.keys())
19495
+ });
19496
+ }
19497
+ return this.isInitialized && (totalElements > 0 || hasActiveHandlers);
19498
+ }
19395
19499
  initializeTracking() {
19396
19500
  if (this.config.debug) {
19397
19501
  console.log("[Zaplier AutoTracker] Initializing tracking...");
@@ -19450,119 +19554,337 @@ class AutoTracker {
19450
19554
  */
19451
19555
  setupEventDelegation() {
19452
19556
  if (this.config.debug) {
19453
- console.log("[AutoTracker] Setting up event delegation...");
19557
+ console.log("[🚀 AutoTracker] Setting up enhanced event delegation...");
19454
19558
  }
19455
- // Click delegation
19559
+ // Determine optimal delegation target based on React setup
19560
+ const delegationTarget = this.getOptimalDelegationTarget();
19561
+ if (this.config.debug) {
19562
+ console.log("[🎯 AutoTracker] Using delegation target:", delegationTarget);
19563
+ }
19564
+ // Click delegation with React compatibility
19456
19565
  if (this.config.trackClicks) {
19457
- const clickHandler = this.createDelegatedClickHandler();
19566
+ const clickHandler = this.createReactCompatibleClickHandler();
19458
19567
  this.delegationHandlers.set('click', clickHandler);
19459
- document.addEventListener('click', clickHandler, { passive: true });
19568
+ delegationTarget.addEventListener('click', clickHandler, this.getEventOptions('click'));
19569
+ if (this.config.debug) {
19570
+ console.log("[👆 AutoTracker] Click delegation handler added");
19571
+ }
19460
19572
  }
19461
- // Scroll delegation (using global handler with element detection)
19573
+ // CRITICAL FIX: Scroll delegation with enhanced detection
19462
19574
  if (this.config.trackScrolls) {
19463
- const scrollHandler = this.createDelegatedScrollHandler();
19575
+ const scrollHandler = this.createEnhancedScrollHandler();
19464
19576
  this.delegationHandlers.set('scroll', scrollHandler);
19465
- document.addEventListener('scroll', scrollHandler, { passive: true });
19577
+ // Always use document for scroll events (window doesn't work with removeEventListener)
19578
+ document.addEventListener('scroll', scrollHandler, this.getEventOptions('scroll'));
19579
+ if (this.config.debug) {
19580
+ console.log("[📜 AutoTracker] Scroll delegation handler added to document");
19581
+ // Immediate test of element detection
19582
+ setTimeout(() => {
19583
+ const scrollElements = this.getCachedScrollElements();
19584
+ console.log(`[📜 AutoTracker] Initial scroll elements check: ${scrollElements.length} found`);
19585
+ if (scrollElements.length > 0) {
19586
+ Array.from(scrollElements).forEach((element, index) => {
19587
+ console.log(`[📜 AutoTracker] Element ${index + 1}:`, {
19588
+ id: element.id || 'no-id',
19589
+ trackEvent: element.getAttribute('data-track-scroll'),
19590
+ threshold: element.getAttribute('data-scroll-threshold') || '0.5',
19591
+ tagName: element.tagName
19592
+ });
19593
+ });
19594
+ }
19595
+ }, 100);
19596
+ }
19466
19597
  }
19467
19598
  // Setup debounced mutation observer for dynamic content
19468
19599
  this.setupIntelligentMutationObserver();
19469
19600
  this.isInitialized = true;
19601
+ if (this.config.debug) {
19602
+ console.log("[✅ AutoTracker] Event delegation setup complete", {
19603
+ clickHandler: this.delegationHandlers.has('click'),
19604
+ scrollHandler: this.delegationHandlers.has('scroll'),
19605
+ totalHandlers: this.delegationHandlers.size
19606
+ });
19607
+ }
19470
19608
  }
19471
19609
  /**
19472
- * Create delegated click handler (no individual listeners needed)
19610
+ * Get optimal delegation target based on React setup
19473
19611
  */
19474
- createDelegatedClickHandler() {
19475
- return (event) => {
19476
- const target = event.target;
19477
- if (!target || !this.config.trackClicks)
19478
- return;
19479
- // Check if target or any parent has data-track-click
19480
- const trackingElement = target.closest('[data-track-click]');
19481
- if (!trackingElement)
19482
- return;
19483
- const eventName = trackingElement.getAttribute('data-track-click');
19484
- if (!eventName)
19485
- return;
19486
- const metadata = this.extractMetadata(trackingElement);
19487
- this.trackEvent(eventName, {
19488
- type: 'click',
19489
- element: trackingElement.tagName.toLowerCase(),
19490
- ...metadata,
19491
- });
19612
+ getOptimalDelegationTarget() {
19613
+ // For React 17+, prefer root container over document
19614
+ const reactRoot = document.querySelector('#root') ||
19615
+ document.querySelector('#__next') ||
19616
+ document.querySelector('[data-reactroot]');
19617
+ if (reactRoot && this.diagnostics.environment?.reactDetected) {
19492
19618
  if (this.config.debug) {
19493
- console.log(`[AutoTracker] Click tracked via delegation: ${eventName}`, {
19619
+ console.log("[⚛️ AutoTracker] Using React root for delegation:", reactRoot);
19620
+ }
19621
+ return reactRoot;
19622
+ }
19623
+ return document;
19624
+ }
19625
+ /**
19626
+ * Get optimized event options for different browsers
19627
+ */
19628
+ getEventOptions(eventType) {
19629
+ this.diagnostics.environment?.isMobile;
19630
+ const isSafari = this.diagnostics.environment?.isSafari;
19631
+ let options = {};
19632
+ switch (eventType) {
19633
+ case 'click':
19634
+ // Safari iOS requires non-passive click events for proper delegation
19635
+ options = {
19636
+ passive: !isSafari,
19637
+ capture: false
19638
+ };
19639
+ break;
19640
+ case 'scroll':
19641
+ options = {
19642
+ passive: true,
19643
+ capture: false
19644
+ };
19645
+ break;
19646
+ default:
19647
+ options = { passive: true };
19648
+ }
19649
+ if (this.config.debug) {
19650
+ console.log(`[⚙️ AutoTracker] Event options for ${eventType}:`, options);
19651
+ }
19652
+ return options;
19653
+ }
19654
+ /**
19655
+ * Create React-compatible click handler
19656
+ */
19657
+ createReactCompatibleClickHandler() {
19658
+ return (event) => {
19659
+ try {
19660
+ if (!this.config.trackClicks)
19661
+ return;
19662
+ // Enhanced target detection for nested React components
19663
+ const target = event.target;
19664
+ if (!target)
19665
+ return;
19666
+ // Multiple strategies to find tracking element
19667
+ let trackingElement = null;
19668
+ // Strategy 1: Direct closest (most common)
19669
+ trackingElement = target.closest('[data-track-click]');
19670
+ // Strategy 2: Check if target itself has the attribute (React edge case)
19671
+ if (!trackingElement && target.hasAttribute && target.hasAttribute('data-track-click')) {
19672
+ trackingElement = target;
19673
+ }
19674
+ // Strategy 3: Walk up DOM tree manually (React portal handling)
19675
+ if (!trackingElement) {
19676
+ trackingElement = this.findTrackingElementManually(target, 'data-track-click');
19677
+ }
19678
+ if (!trackingElement) {
19679
+ if (this.config.debug) {
19680
+ console.log('[🔍 AutoTracker] No tracking element found for click:', {
19681
+ target: target.tagName,
19682
+ hasClosest: typeof target.closest === 'function',
19683
+ hasAttribute: typeof target.hasAttribute === 'function'
19684
+ });
19685
+ }
19686
+ return;
19687
+ }
19688
+ const eventName = trackingElement.getAttribute('data-track-click');
19689
+ if (!eventName)
19690
+ return;
19691
+ const metadata = this.extractMetadata(trackingElement);
19692
+ this.trackEvent(eventName, {
19693
+ type: 'click',
19494
19694
  element: trackingElement.tagName.toLowerCase(),
19495
- ...metadata
19695
+ reactCompatible: true,
19696
+ ...metadata,
19496
19697
  });
19698
+ if (this.config.debug) {
19699
+ console.log(`[🎯 AutoTracker] Click tracked (React-compatible): ${eventName}`, {
19700
+ element: trackingElement.tagName.toLowerCase(),
19701
+ strategy: 'enhanced_delegation',
19702
+ ...metadata
19703
+ });
19704
+ }
19705
+ }
19706
+ catch (error) {
19707
+ if (this.config.debug) {
19708
+ console.error('[❌ AutoTracker] Click handler error:', error);
19709
+ }
19497
19710
  }
19498
19711
  };
19499
19712
  }
19500
19713
  /**
19501
- * Create delegated scroll handler (efficient global approach)
19714
+ * Manually walk up DOM tree to find tracking element
19502
19715
  */
19503
- createDelegatedScrollHandler() {
19716
+ findTrackingElementManually(element, attribute, maxDepth = 10) {
19717
+ let current = element;
19718
+ let depth = 0;
19719
+ while (current && current !== document.documentElement && depth < maxDepth) {
19720
+ if (current.hasAttribute && current.hasAttribute(attribute)) {
19721
+ return current;
19722
+ }
19723
+ current = current.parentElement;
19724
+ depth++;
19725
+ }
19726
+ return null;
19727
+ }
19728
+ /**
19729
+ * Create enhanced scroll handler with better performance
19730
+ */
19731
+ createEnhancedScrollHandler() {
19504
19732
  return () => {
19505
- if (!this.config.trackScrolls)
19506
- return;
19507
- // Throttle scroll events for performance
19508
- const now = Date.now();
19509
- if (now - this.scrollThrottle < 100)
19510
- return;
19511
- this.scrollThrottle = now;
19512
- // Find all scroll tracking elements and check visibility
19513
- const scrollElements = document.querySelectorAll('[data-track-scroll]');
19514
- if (this.config.debug && scrollElements.length > 0) {
19515
- console.log(`[AutoTracker] Checking ${scrollElements.length} scroll elements via delegation`);
19516
- }
19517
- scrollElements.forEach((element) => {
19518
- this.processScrollElement(element);
19519
- });
19733
+ try {
19734
+ if (!this.config.trackScrolls)
19735
+ return;
19736
+ // Adaptive throttling based on scroll frequency
19737
+ const now = Date.now();
19738
+ const timeDelta = now - this.scrollThrottle;
19739
+ const throttleDelay = this.diagnostics.environment?.isMobile ? 150 : 100;
19740
+ if (timeDelta < throttleDelay)
19741
+ return;
19742
+ this.scrollThrottle = now;
19743
+ // Enhanced element finding with caching
19744
+ const scrollElements = this.getCachedScrollElements();
19745
+ if (this.config.debug) {
19746
+ console.log(`[📜 AutoTracker] Enhanced scroll handler triggered`, {
19747
+ scrollElementsFound: scrollElements.length,
19748
+ scrollY: window.scrollY,
19749
+ throttleDelay,
19750
+ timeDelta
19751
+ });
19752
+ }
19753
+ // Process elements with enhanced visibility detection
19754
+ if (scrollElements.length > 0) {
19755
+ scrollElements.forEach((element) => {
19756
+ this.processScrollElementEnhanced(element);
19757
+ });
19758
+ }
19759
+ else if (this.config.debug) {
19760
+ console.log(`[📜 AutoTracker] No scroll elements found to process`);
19761
+ }
19762
+ }
19763
+ catch (error) {
19764
+ if (this.config.debug) {
19765
+ console.error('[❌ AutoTracker] Enhanced scroll handler error:', error);
19766
+ }
19767
+ }
19520
19768
  };
19521
19769
  }
19770
+ getCachedScrollElements() {
19771
+ const now = Date.now();
19772
+ const cacheExpiry = 2000; // Reduced to 2 seconds for faster detection
19773
+ if (!this.cachedScrollElements || (now - this.lastScrollElementsCheck) > cacheExpiry) {
19774
+ this.cachedScrollElements = document.querySelectorAll('[data-track-scroll]');
19775
+ this.lastScrollElementsCheck = now;
19776
+ if (this.config.debug) {
19777
+ console.log(`[🔄 AutoTracker] Refreshed scroll elements cache: ${this.cachedScrollElements.length} elements found`);
19778
+ // Log each element found for debugging
19779
+ Array.from(this.cachedScrollElements).forEach((element, index) => {
19780
+ console.log(`[🔄 AutoTracker] Cached element ${index + 1}:`, {
19781
+ id: element.id || 'no-id',
19782
+ className: element.className || 'no-class',
19783
+ trackEvent: element.getAttribute('data-track-scroll'),
19784
+ threshold: element.getAttribute('data-scroll-threshold') || '0.5',
19785
+ tagName: element.tagName,
19786
+ triggered: element.getAttribute('data-scroll-triggered') === 'true'
19787
+ });
19788
+ });
19789
+ }
19790
+ }
19791
+ return this.cachedScrollElements;
19792
+ }
19522
19793
  /**
19523
- * Process individual scroll element (extracted for reusability)
19794
+ * Process scroll element with enhanced detection
19524
19795
  */
19525
- processScrollElement(element) {
19526
- const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
19527
- if (hasTriggered)
19528
- return;
19529
- const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
19530
- const rect = element.getBoundingClientRect();
19531
- const elementHeight = rect.height;
19532
- const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
19533
- const visibilityRatio = Math.max(0, visibleHeight) / elementHeight;
19534
- if (this.config.debug) {
19535
- console.log(`[AutoTracker] Scroll element check via delegation:`, {
19536
- elementId: element.id || element.className,
19537
- visibilityRatio: Math.round(visibilityRatio * 100) / 100,
19538
- threshold,
19539
- triggered: hasTriggered
19540
- });
19541
- }
19542
- if (visibilityRatio >= threshold) {
19543
- element.setAttribute('data-scroll-triggered', 'true');
19796
+ processScrollElementEnhanced(element) {
19797
+ try {
19798
+ const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
19799
+ if (hasTriggered) {
19800
+ if (this.config.debug) {
19801
+ console.log(`[⏭️ AutoTracker] Element already triggered, skipping:`, element.id || element.className || 'no-id');
19802
+ }
19803
+ return;
19804
+ }
19805
+ const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
19806
+ // Enhanced visibility calculation
19807
+ const rect = element.getBoundingClientRect();
19808
+ const elementHeight = rect.height;
19809
+ const windowHeight = window.innerHeight;
19810
+ // Handle edge cases
19811
+ if (elementHeight <= 0) {
19812
+ if (this.config.debug) {
19813
+ console.log(`[⚠️ AutoTracker] Element has no height, skipping:`, element.id || 'no-id');
19814
+ }
19815
+ return;
19816
+ }
19817
+ const visibleTop = Math.max(rect.top, 0);
19818
+ const visibleBottom = Math.min(rect.bottom, windowHeight);
19819
+ const visibleHeight = Math.max(0, visibleBottom - visibleTop);
19820
+ const visibilityRatio = visibleHeight / elementHeight;
19544
19821
  const eventName = element.getAttribute('data-track-scroll');
19545
- if (!eventName)
19822
+ if (!eventName) {
19823
+ if (this.config.debug) {
19824
+ console.log(`[⚠️ AutoTracker] Element missing data-track-scroll attribute:`, element.id || 'no-id');
19825
+ }
19546
19826
  return;
19547
- const metadata = this.extractMetadata(element);
19548
- this.trackEvent(eventName, {
19549
- type: 'scroll',
19550
- element: element.tagName.toLowerCase(),
19551
- threshold,
19552
- scrollDepth: window.scrollY,
19553
- visibilityRatio: Math.round(visibilityRatio * 100) / 100,
19554
- ...metadata,
19555
- });
19827
+ }
19556
19828
  if (this.config.debug) {
19557
- console.log(`[AutoTracker] Scroll tracked via delegation: ${eventName}`, {
19829
+ console.log(`[📊 AutoTracker] Enhanced scroll check for "${eventName}":`, {
19830
+ elementId: element.id || element.className || 'no-id',
19831
+ rect: {
19832
+ top: Math.round(rect.top),
19833
+ bottom: Math.round(rect.bottom),
19834
+ height: Math.round(elementHeight)
19835
+ },
19836
+ window: {
19837
+ height: windowHeight,
19838
+ scrollY: window.scrollY
19839
+ },
19840
+ visibility: {
19841
+ visibleTop,
19842
+ visibleBottom,
19843
+ visibleHeight,
19844
+ ratio: Math.round(visibilityRatio * 1000) / 1000,
19845
+ threshold,
19846
+ triggered: hasTriggered,
19847
+ shouldTrigger: visibilityRatio >= threshold
19848
+ }
19849
+ });
19850
+ }
19851
+ if (visibilityRatio >= threshold) {
19852
+ // Mark as triggered to prevent duplicate events
19853
+ element.setAttribute('data-scroll-triggered', 'true');
19854
+ const metadata = this.extractMetadata(element);
19855
+ const eventData = {
19856
+ type: 'scroll',
19857
+ element: element.tagName.toLowerCase(),
19558
19858
  threshold,
19559
- visibilityRatio,
19560
19859
  scrollDepth: window.scrollY,
19561
- ...metadata
19860
+ visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
19861
+ enhanced: true,
19862
+ ...metadata,
19863
+ };
19864
+ if (this.config.debug) {
19865
+ console.log(`[🎯 AutoTracker] TRIGGERING scroll event "${eventName}":`, eventData);
19866
+ }
19867
+ this.trackEvent(eventName, eventData);
19868
+ if (this.config.debug) {
19869
+ console.log(`[✅ AutoTracker] Scroll event "${eventName}" sent successfully`);
19870
+ }
19871
+ }
19872
+ }
19873
+ catch (error) {
19874
+ if (this.config.debug) {
19875
+ console.error('[❌ AutoTracker] Scroll element processing error:', error, {
19876
+ element: element.id || element.className || 'no-id',
19877
+ tagName: element.tagName
19562
19878
  });
19563
19879
  }
19564
19880
  }
19565
19881
  }
19882
+ /**
19883
+ * Legacy method for compatibility
19884
+ */
19885
+ processScrollElement(element) {
19886
+ this.processScrollElementEnhanced(element);
19887
+ }
19566
19888
  /**
19567
19889
  * Setup intelligent mutation observer (debounced for performance)
19568
19890
  */
@@ -19853,43 +20175,90 @@ class AutoTracker {
19853
20175
  /**
19854
20176
  * Enviar evento para o SDK
19855
20177
  */
20178
+ /**
20179
+ * Enhanced event tracking with comprehensive debugging
20180
+ */
19856
20181
  trackEvent(eventName, metadata) {
20182
+ const trackingStart = performance.now();
19857
20183
  if (this.config.debug) {
19858
- console.log("[AutoTracker] trackEvent called:", { eventName, metadata });
19859
- }
19860
- if (!this.sdkInstance) {
19861
- if (this.config.debug) {
19862
- console.error("[AutoTracker] SDK instance is null!");
19863
- }
19864
- return;
20184
+ console.log("[🚀 AutoTracker] Enhanced trackEvent called:", {
20185
+ eventName,
20186
+ metadata,
20187
+ timestamp: new Date().toISOString()
20188
+ });
19865
20189
  }
19866
- if (typeof this.sdkInstance.trackCustomEvent !== 'function') {
20190
+ // Comprehensive validation
20191
+ const validation = this.validateTrackingCall(eventName, metadata);
20192
+ if (!validation.isValid) {
19867
20193
  if (this.config.debug) {
19868
- console.error("[AutoTracker] trackCustomEvent is not a function:", typeof this.sdkInstance.trackCustomEvent);
20194
+ console.error("[AutoTracker] Validation failed:", validation.errors);
19869
20195
  }
19870
20196
  return;
19871
20197
  }
19872
20198
  try {
19873
20199
  const eventData = {
20200
+ // Core tracking data
19874
20201
  autoTracked: true,
20202
+ enhanced: true,
19875
20203
  timestamp: Date.now(),
19876
20204
  url: window.location.href,
20205
+ userAgent: navigator.userAgent,
20206
+ // Performance data
20207
+ trackingLatency: Math.round((performance.now() - trackingStart) * 100) / 100,
20208
+ // Environment data
20209
+ isReactApp: this.diagnostics.environment?.reactDetected,
20210
+ isMobile: this.diagnostics.environment?.isMobile,
20211
+ // Event metadata
19877
20212
  ...metadata,
19878
20213
  };
19879
20214
  if (this.config.debug) {
19880
- console.log("[AutoTracker] Calling trackCustomEvent:", { eventName, eventData });
20215
+ console.log("[📡 AutoTracker] Sending enhanced event:", { eventName, eventData });
19881
20216
  }
19882
20217
  const result = this.sdkInstance.trackCustomEvent(eventName, eventData);
19883
20218
  if (this.config.debug) {
19884
- console.log("[AutoTracker] trackCustomEvent result:", result);
20219
+ const trackingEnd = performance.now();
20220
+ console.log("[✅ AutoTracker] Event sent successfully:", {
20221
+ eventName,
20222
+ result,
20223
+ totalLatency: Math.round((trackingEnd - trackingStart) * 100) / 100 + 'ms'
20224
+ });
19885
20225
  }
19886
20226
  }
19887
20227
  catch (error) {
19888
20228
  if (this.config.debug) {
19889
- console.error("[AutoTracker] Error sending event:", error);
20229
+ console.error("[💥 AutoTracker] Critical tracking error:", {
20230
+ eventName,
20231
+ error: error instanceof Error ? error.message : error,
20232
+ stack: error instanceof Error ? error.stack : undefined,
20233
+ metadata
20234
+ });
19890
20235
  }
19891
20236
  }
19892
20237
  }
20238
+ /**
20239
+ * Validate tracking call before sending
20240
+ */
20241
+ validateTrackingCall(eventName, metadata) {
20242
+ const errors = [];
20243
+ if (!eventName || typeof eventName !== 'string') {
20244
+ errors.push('Event name is required and must be a string');
20245
+ }
20246
+ if (!this.sdkInstance) {
20247
+ errors.push('SDK instance is null or undefined');
20248
+ }
20249
+ if (this.sdkInstance && typeof this.sdkInstance.trackCustomEvent !== 'function') {
20250
+ errors.push(`trackCustomEvent is not a function: ${typeof this.sdkInstance.trackCustomEvent}`);
20251
+ }
20252
+ if (!window || typeof window !== 'object') {
20253
+ errors.push('Window object is not available');
20254
+ }
20255
+ return {
20256
+ isValid: errors.length === 0,
20257
+ errors
20258
+ };
20259
+ }
20260
+ // Legacy handlers removed - now using enhanced event delegation system
20261
+ // All tracking is now handled by createEnhancedScrollHandler and createReactCompatibleClickHandler
19893
20262
  /**
19894
20263
  * Modern API: Refresh tracking for dynamic content (React/SPA support)
19895
20264
  * Industry best practice for SPA route changes
@@ -19919,26 +20288,83 @@ class AutoTracker {
19919
20288
  this.refreshTracking();
19920
20289
  }
19921
20290
  /**
19922
- * Get diagnostic information for debugging
20291
+ * Get comprehensive diagnostic information for debugging
19923
20292
  */
19924
20293
  getDiagnostics() {
19925
20294
  return {
19926
- isInitialized: this.isInitialized,
19927
- hasClickHandler: this.delegationHandlers.has('click'),
19928
- hasScrollHandler: this.delegationHandlers.has('scroll'),
19929
- observedElements: this.observedElements.size,
19930
- hasMutationObserver: !!this.mutationObserver,
19931
- hasIntersectionObserver: !!this.intersectionObserver,
20295
+ // Initialization status
20296
+ initialization: {
20297
+ isInitialized: this.isInitialized,
20298
+ attempts: this.initializationAttempts,
20299
+ maxAttempts: this.maxInitializationAttempts,
20300
+ timestamp: new Date().toISOString()
20301
+ },
20302
+ // Event handlers status
20303
+ eventHandlers: {
20304
+ hasClickHandler: this.delegationHandlers.has('click'),
20305
+ hasScrollHandler: this.delegationHandlers.has('scroll'),
20306
+ activeHandlers: Array.from(this.delegationHandlers.keys()),
20307
+ delegationTarget: this.getOptimalDelegationTarget() === document ? 'document' : 'react-root'
20308
+ },
20309
+ // Observers status
20310
+ observers: {
20311
+ observedElements: this.observedElements.size,
20312
+ hasMutationObserver: !!this.mutationObserver,
20313
+ hasIntersectionObserver: !!this.intersectionObserver,
20314
+ scrollElementsCache: !!this.cachedScrollElements,
20315
+ cacheExpiry: new Date(this.lastScrollElementsCheck + 5000).toISOString()
20316
+ },
20317
+ // Configuration
19932
20318
  config: this.config,
19933
- elementsFound: {
19934
- click: document.querySelectorAll('[data-track-click]').length,
19935
- scroll: document.querySelectorAll('[data-track-scroll]').length,
19936
- view: document.querySelectorAll('[data-track-view]').length,
19937
- hover: document.querySelectorAll('[data-track-hover]').length,
19938
- form: document.querySelectorAll('[data-track-form]').length
19939
- }
20319
+ // Current environment diagnostics
20320
+ environment: this.diagnostics.environment || {},
20321
+ // DOM state
20322
+ dom: this.diagnostics.dom || {},
20323
+ // SDK state
20324
+ tracking: this.diagnostics.tracking || {},
20325
+ // Real-time element detection
20326
+ elementsFound: this.getElementCounts(),
20327
+ // Performance metrics
20328
+ performance: {
20329
+ lastScrollThrottle: this.scrollThrottle,
20330
+ cacheLastUpdate: this.lastScrollElementsCheck
20331
+ },
20332
+ // Validation status
20333
+ validation: this.validateTrackingCall('test', {}),
20334
+ // Debug recommendations
20335
+ recommendations: this.generateRecommendations()
19940
20336
  };
19941
20337
  }
20338
+ /**
20339
+ * Generate diagnostic recommendations
20340
+ */
20341
+ generateRecommendations() {
20342
+ const recommendations = [];
20343
+ const elementsFound = this.getElementCounts();
20344
+ const totalElements = Object.values(elementsFound).reduce((sum, count) => sum + count, 0);
20345
+ if (!this.isInitialized) {
20346
+ recommendations.push('AutoTracker is not initialized. Check console for errors.');
20347
+ }
20348
+ if (totalElements === 0) {
20349
+ recommendations.push('No trackable elements found. Ensure data-track-* attributes are present in the DOM.');
20350
+ }
20351
+ if (!this.sdkInstance) {
20352
+ recommendations.push('SDK instance is missing. Ensure the SDK is properly initialized.');
20353
+ }
20354
+ if (this.sdkInstance && typeof this.sdkInstance.trackCustomEvent !== 'function') {
20355
+ recommendations.push('trackCustomEvent method is not available on SDK instance.');
20356
+ }
20357
+ if (!this.diagnostics.environment?.reactDetected && window.location.hostname.includes('localhost')) {
20358
+ recommendations.push('React not detected. If using React, ensure proper setup and try refreshTracking() after route changes.');
20359
+ }
20360
+ if (this.diagnostics.environment?.isMobile && !this.delegationHandlers.has('scroll')) {
20361
+ recommendations.push('Mobile device detected but scroll tracking not active. Check scroll tracking configuration.');
20362
+ }
20363
+ if (this.initializationAttempts > 1) {
20364
+ recommendations.push(`AutoTracker required ${this.initializationAttempts} initialization attempts. Consider adding delay before enabling.`);
20365
+ }
20366
+ return recommendations;
20367
+ }
19942
20368
  /**
19943
20369
  * Configurar tracking
19944
20370
  */
@@ -19958,6 +20384,33 @@ class AutoTracker {
19958
20384
  }
19959
20385
  }
19960
20386
 
20387
+ /**
20388
+ * Centralized Session Utilities
20389
+ * Standardized session ID generation for consistency across SDK and backend
20390
+ */
20391
+ /**
20392
+ * Generate standardized session ID
20393
+ * Format: visitorId_YYYYMMDD_HH
20394
+ * Example: f697a6e1-1aae-48db-bc6a-afc1d2c01852_20251231_03
20395
+ */
20396
+ function generateSessionId(visitorId, date) {
20397
+ const sessionDate = date || new Date();
20398
+ // Format: YYYYMMDD
20399
+ const year = sessionDate.getFullYear();
20400
+ const month = (sessionDate.getMonth() + 1).toString().padStart(2, '0');
20401
+ const day = sessionDate.getDate().toString().padStart(2, '0');
20402
+ const dateStr = `${year}${month}${day}`;
20403
+ // Format: HH (24-hour format)
20404
+ const hour = sessionDate.getHours().toString().padStart(2, '0');
20405
+ return `${visitorId}_${dateStr}_${hour}`;
20406
+ }
20407
+ /**
20408
+ * Generate session ID for current time
20409
+ */
20410
+ function generateCurrentSessionId(visitorId) {
20411
+ return generateSessionId(visitorId, new Date());
20412
+ }
20413
+
19961
20414
  /**
19962
20415
  * Visitor Persistence Manager for SDK
19963
20416
  * Implements client-side visitor identification with localStorage camouflage
@@ -20117,9 +20570,23 @@ class VisitorIdentityManager {
20117
20570
  // REMOVED: generateVisitorId() and generateVisitorIdFromHash() methods
20118
20571
  // SDK no longer generates visitor IDs - only backend does
20119
20572
  generateSessionId() {
20120
- return "ses_" + Array.from(crypto.getRandomValues(new Uint8Array(8)))
20121
- .map(b => b.toString(16).padStart(2, '0'))
20122
- .join('') + "_" + Date.now().toString(36);
20573
+ // Try to get existing visitor identity from storage
20574
+ const { value: storedData } = PersistenceManager.get(STORAGE_KEYS.prefs);
20575
+ if (storedData) {
20576
+ try {
20577
+ const parsed = JSON.parse(storedData);
20578
+ if (parsed._v && parsed._vb === true) {
20579
+ // We have a valid visitor ID from backend
20580
+ return generateCurrentSessionId(parsed._v);
20581
+ }
20582
+ }
20583
+ catch (e) {
20584
+ // Invalid data, continue to fallback
20585
+ }
20586
+ }
20587
+ // Fallback for cases where visitor ID is not available yet
20588
+ const tempVisitorId = "temp-" + Date.now().toString(36);
20589
+ return generateCurrentSessionId(tempVisitorId);
20123
20590
  }
20124
20591
  createCamouflageData(visitorId, sessionId, stableCoreHash, fromBackend = false) {
20125
20592
  return {
@@ -20129,7 +20596,7 @@ class VisitorIdentityManager {
20129
20596
  analytics: true,
20130
20597
  cookies: true,
20131
20598
  _v: visitorId, // Hidden visitor ID
20132
- _s: sessionId, // Hidden session ID
20599
+ _s: sessionId, // Hidden session ID
20133
20600
  _sc: stableCoreHash, // Hidden stable core
20134
20601
  _vb: fromBackend ? true : undefined, // Flag: visitor ID from backend (v1.7.0+)
20135
20602
  ts: Date.now(),
@@ -20173,7 +20640,9 @@ class VisitorIdentityManager {
20173
20640
  const { value: storedData, method } = PersistenceManager.get(STORAGE_KEYS.prefs);
20174
20641
  if (storedData) {
20175
20642
  const existingIdentity = this.extractFromCamouflage(storedData);
20176
- if (existingIdentity && existingIdentity.stableCoreHash === stableCoreHash && existingIdentity.visitorId) {
20643
+ if (existingIdentity &&
20644
+ existingIdentity.stableCoreHash === stableCoreHash &&
20645
+ existingIdentity.visitorId) {
20177
20646
  // Update last seen time only if we have a valid visitor ID from backend
20178
20647
  const updatedCamouflage = this.createCamouflageData(existingIdentity.visitorId, existingIdentity.sessionId, stableCoreHash);
20179
20648
  PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(updatedCamouflage));
@@ -20193,7 +20662,7 @@ class VisitorIdentityManager {
20193
20662
  stableCoreHash,
20194
20663
  deviceFingerprint: params.deviceFingerprint,
20195
20664
  persistenceMethod: "memory", // Start with memory, upgrade after backend response
20196
- confidence: 0.90,
20665
+ confidence: 0.9,
20197
20666
  createdAt: Date.now(),
20198
20667
  lastSeen: Date.now(),
20199
20668
  reused: false,
@@ -20208,7 +20677,12 @@ class VisitorIdentityManager {
20208
20677
  async updateVisitorIdFromBackend(visitorId, stableCoreHash, sessionId) {
20209
20678
  try {
20210
20679
  // Create or update camouflaged data with backend visitor ID
20211
- const currentSessionId = sessionId || this.getCurrentSessionId() || this.generateSessionId();
20680
+ // Regenerate session ID with proper visitor ID if needed
20681
+ let currentSessionId = sessionId || this.getCurrentSessionId();
20682
+ // If we have a temp session ID or no session ID, generate a new one with the proper visitor ID
20683
+ if (!currentSessionId || currentSessionId.includes("temp-")) {
20684
+ currentSessionId = generateCurrentSessionId(visitorId);
20685
+ }
20212
20686
  const camouflageData = this.createCamouflageData(visitorId, currentSessionId, stableCoreHash, true // Mark as coming from backend
20213
20687
  );
20214
20688
  const { success, method } = PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(camouflageData));
@@ -20220,7 +20694,7 @@ class VisitorIdentityManager {
20220
20694
  return false;
20221
20695
  }
20222
20696
  catch (error) {
20223
- console.error('[VisitorIdentityManager] Failed to update visitor ID from backend:', error);
20697
+ console.error("[VisitorIdentityManager] Failed to update visitor ID from backend:", error);
20224
20698
  return false;
20225
20699
  }
20226
20700
  }
@@ -20674,36 +21148,17 @@ class ZaplierSDK {
20674
21148
  }
20675
21149
  }
20676
21150
  /**
20677
- * Generate session ID
21151
+ * Generate session ID using standardized format
20678
21152
  */
20679
21153
  generateSessionId() {
20680
- // Create deterministic session ID based on page load time and stable browser characteristics
20681
- const pageLoadTime = performance.timeOrigin || Date.now();
20682
- const browserFingerprint = this.getBrowserFingerprint();
20683
- // Use page load time + browser fingerprint for session uniqueness within same page load
20684
- return pageLoadTime.toString(36) + browserFingerprint.substring(0, 8);
20685
- }
20686
- /**
20687
- * Get stable browser characteristics for session ID generation
20688
- * Uses only stable, privacy-safe values that don't change during session
20689
- */
20690
- getBrowserFingerprint() {
20691
- const components = [
20692
- navigator.userAgent || "",
20693
- navigator.platform || "",
20694
- screen.width || 0,
20695
- screen.height || 0,
20696
- new Date(2024, 0, 1).getTimezoneOffset(),
20697
- navigator.language || "",
20698
- navigator.hardwareConcurrency || 0,
20699
- ];
20700
- const combined = components.join("|");
20701
- let hash = 0;
20702
- for (let i = 0; i < combined.length; i++) {
20703
- const char = combined.charCodeAt(i);
20704
- hash = ((hash << 5) - hash + char) & 0xffffffff;
21154
+ // Use centralized session generation with current visitor ID
21155
+ if (this.backendVisitorId) {
21156
+ return generateCurrentSessionId(this.backendVisitorId);
20705
21157
  }
20706
- return Math.abs(hash).toString(36);
21158
+ // Fallback for cases where backendVisitorId is not available yet
21159
+ // This should be rare and will be updated when visitor ID is available
21160
+ const tempVisitorId = this.visitorId || 'temp-' + Date.now().toString(36);
21161
+ return generateCurrentSessionId(tempVisitorId);
20707
21162
  }
20708
21163
  /**
20709
21164
  * Initialize Anti-Adblock Manager
@@ -20962,6 +21417,10 @@ class ZaplierSDK {
20962
21417
  if (response.sessionId) {
20963
21418
  this.sessionId = response.sessionId;
20964
21419
  }
21420
+ else if (this.backendVisitorId && (!this.sessionId || this.sessionId.includes('temp-'))) {
21421
+ // Generate new session ID now that we have the proper visitor ID
21422
+ this.sessionId = generateCurrentSessionId(this.backendVisitorId);
21423
+ }
20965
21424
  return response;
20966
21425
  }
20967
21426
  catch (error) {