@zaplier/sdk 1.7.0 → 1.7.2
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 +560 -122
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +560 -122
- package/dist/index.esm.js.map +1 -1
- package/dist/sdk.js +560 -122
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.min.js +1 -1
- package/dist/src/modules/auto-tracker.d.ts +86 -6
- package/dist/src/modules/auto-tracker.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/sdk.js
CHANGED
|
@@ -19270,6 +19270,14 @@
|
|
|
19270
19270
|
this.scrollThrottle = 0;
|
|
19271
19271
|
this.isInitialized = false;
|
|
19272
19272
|
this.delegationHandlers = new Map();
|
|
19273
|
+
this.initializationAttempts = 0;
|
|
19274
|
+
this.maxInitializationAttempts = 3;
|
|
19275
|
+
this.diagnostics = {};
|
|
19276
|
+
/**
|
|
19277
|
+
* Cache scroll elements for better performance
|
|
19278
|
+
*/
|
|
19279
|
+
this.cachedScrollElements = null;
|
|
19280
|
+
this.lastScrollElementsCheck = 0;
|
|
19273
19281
|
this.handleScroll = () => {
|
|
19274
19282
|
if (!this.config.trackScrolls)
|
|
19275
19283
|
return;
|
|
@@ -19367,32 +19375,207 @@
|
|
|
19367
19375
|
start() {
|
|
19368
19376
|
if (!this.config.enabled)
|
|
19369
19377
|
return;
|
|
19378
|
+
this.initializationAttempts++;
|
|
19379
|
+
// Enhanced diagnostics
|
|
19380
|
+
this.runDiagnostics();
|
|
19370
19381
|
if (this.config.debug) {
|
|
19371
|
-
console.log("[
|
|
19372
|
-
enabled: this.config.enabled,
|
|
19373
|
-
trackClicks: this.config.trackClicks,
|
|
19374
|
-
trackScrolls: this.config.trackScrolls,
|
|
19375
|
-
trackViews: this.config.trackViews,
|
|
19376
|
-
trackHovers: this.config.trackHovers,
|
|
19377
|
-
trackForms: this.config.trackForms,
|
|
19378
|
-
domReady: document.readyState
|
|
19379
|
-
});
|
|
19382
|
+
console.log("[🔥 AutoTracker ENHANCED] Starting auto tracking", this.diagnostics);
|
|
19380
19383
|
}
|
|
19381
|
-
//
|
|
19382
|
-
|
|
19383
|
-
|
|
19384
|
-
|
|
19384
|
+
// Multiple initialization strategies
|
|
19385
|
+
this.tryInitialization();
|
|
19386
|
+
}
|
|
19387
|
+
/**
|
|
19388
|
+
* Run comprehensive diagnostics
|
|
19389
|
+
*/
|
|
19390
|
+
runDiagnostics() {
|
|
19391
|
+
this.diagnostics = {
|
|
19392
|
+
timestamp: new Date().toISOString(),
|
|
19393
|
+
attempt: this.initializationAttempts,
|
|
19394
|
+
environment: {
|
|
19395
|
+
domReady: document.readyState,
|
|
19396
|
+
reactDetected: this.detectReact(),
|
|
19397
|
+
reactVersion: this.getReactVersion(),
|
|
19398
|
+
userAgent: navigator.userAgent,
|
|
19399
|
+
isMobile: /Mobile|Android|iPhone|iPad/.test(navigator.userAgent),
|
|
19400
|
+
isSafari: /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent),
|
|
19401
|
+
protocol: window.location.protocol,
|
|
19402
|
+
isLocalhost: window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
|
|
19403
|
+
},
|
|
19404
|
+
dom: {
|
|
19405
|
+
documentElement: !!document.documentElement,
|
|
19406
|
+
body: !!document.body,
|
|
19407
|
+
querySelector: typeof document.querySelector === 'function',
|
|
19408
|
+
addEventListener: typeof document.addEventListener === 'function',
|
|
19409
|
+
elementsFound: this.getElementCounts(),
|
|
19410
|
+
hasReactRoot: this.findReactRoot()
|
|
19411
|
+
},
|
|
19412
|
+
tracking: {
|
|
19413
|
+
sdkInstance: !!this.sdkInstance,
|
|
19414
|
+
trackCustomEvent: typeof this.sdkInstance?.trackCustomEvent === 'function',
|
|
19415
|
+
config: this.config,
|
|
19416
|
+
isInitialized: this.isInitialized,
|
|
19417
|
+
activeHandlers: Array.from(this.delegationHandlers.keys())
|
|
19385
19418
|
}
|
|
19419
|
+
};
|
|
19420
|
+
}
|
|
19421
|
+
/**
|
|
19422
|
+
* Detect React presence
|
|
19423
|
+
*/
|
|
19424
|
+
detectReact() {
|
|
19425
|
+
return !!(window.__REACT_DEVTOOLS_GLOBAL_HOOK__ ||
|
|
19426
|
+
window.React ||
|
|
19427
|
+
document.querySelector('[data-reactroot]') ||
|
|
19428
|
+
document.querySelector('#root') ||
|
|
19429
|
+
document.querySelector('#__next'));
|
|
19430
|
+
}
|
|
19431
|
+
/**
|
|
19432
|
+
* Get React version if available
|
|
19433
|
+
*/
|
|
19434
|
+
getReactVersion() {
|
|
19435
|
+
try {
|
|
19436
|
+
const reactInstance = window.React;
|
|
19437
|
+
return reactInstance?.version || null;
|
|
19438
|
+
}
|
|
19439
|
+
catch {
|
|
19440
|
+
return null;
|
|
19441
|
+
}
|
|
19442
|
+
}
|
|
19443
|
+
/**
|
|
19444
|
+
* Find React root element
|
|
19445
|
+
*/
|
|
19446
|
+
findReactRoot() {
|
|
19447
|
+
const reactRoot = document.querySelector('[data-reactroot]') ||
|
|
19448
|
+
document.querySelector('#root') ||
|
|
19449
|
+
document.querySelector('#__next') ||
|
|
19450
|
+
document.querySelector('div[data-react-helmet]');
|
|
19451
|
+
return reactRoot ? reactRoot.tagName + (reactRoot.id ? '#' + reactRoot.id : '') : null;
|
|
19452
|
+
}
|
|
19453
|
+
/**
|
|
19454
|
+
* Get element counts for all tracking types
|
|
19455
|
+
*/
|
|
19456
|
+
getElementCounts() {
|
|
19457
|
+
return {
|
|
19458
|
+
click: document.querySelectorAll('[data-track-click]').length,
|
|
19459
|
+
scroll: document.querySelectorAll('[data-track-scroll]').length,
|
|
19460
|
+
view: document.querySelectorAll('[data-track-view]').length,
|
|
19461
|
+
hover: document.querySelectorAll('[data-track-hover]').length,
|
|
19462
|
+
form: document.querySelectorAll('[data-track-form]').length
|
|
19463
|
+
};
|
|
19464
|
+
}
|
|
19465
|
+
/**
|
|
19466
|
+
* Try multiple initialization strategies
|
|
19467
|
+
*/
|
|
19468
|
+
tryInitialization() {
|
|
19469
|
+
const strategies = [
|
|
19470
|
+
() => this.immediateInitialization(),
|
|
19471
|
+
() => this.delayedInitialization(100),
|
|
19472
|
+
() => this.delayedInitialization(500),
|
|
19473
|
+
() => this.delayedInitialization(1000),
|
|
19474
|
+
() => this.reactReadyInitialization()
|
|
19475
|
+
];
|
|
19476
|
+
// Try immediate initialization first
|
|
19477
|
+
if (document.readyState === 'complete') {
|
|
19478
|
+
this.attemptStrategy(0, strategies);
|
|
19479
|
+
}
|
|
19480
|
+
else if (document.readyState === 'interactive') {
|
|
19481
|
+
// DOM ready but resources still loading
|
|
19482
|
+
this.attemptStrategy(1, strategies);
|
|
19483
|
+
}
|
|
19484
|
+
else {
|
|
19485
|
+
// DOM still loading
|
|
19386
19486
|
document.addEventListener('DOMContentLoaded', () => {
|
|
19387
|
-
|
|
19388
|
-
console.log("[Zaplier AutoTracker] DOMContentLoaded fired, initializing tracking...");
|
|
19389
|
-
}
|
|
19390
|
-
this.initializeTracking();
|
|
19487
|
+
this.attemptStrategy(0, strategies);
|
|
19391
19488
|
}, { once: true });
|
|
19392
19489
|
}
|
|
19393
|
-
|
|
19490
|
+
}
|
|
19491
|
+
/**
|
|
19492
|
+
* Attempt initialization strategy with fallback
|
|
19493
|
+
*/
|
|
19494
|
+
attemptStrategy(index, strategies) {
|
|
19495
|
+
if (index >= strategies.length || this.isInitialized)
|
|
19496
|
+
return;
|
|
19497
|
+
if (this.config.debug) {
|
|
19498
|
+
console.log(`[🔄 AutoTracker] Trying initialization strategy ${index + 1}/${strategies.length}`);
|
|
19499
|
+
}
|
|
19500
|
+
try {
|
|
19501
|
+
const strategy = strategies[index];
|
|
19502
|
+
if (strategy && typeof strategy === 'function') {
|
|
19503
|
+
strategy();
|
|
19504
|
+
// Verify initialization after a short delay
|
|
19505
|
+
setTimeout(() => {
|
|
19506
|
+
if (!this.verifyInitialization()) {
|
|
19507
|
+
if (this.config.debug) {
|
|
19508
|
+
console.log(`[⚠️ AutoTracker] Strategy ${index + 1} failed verification, trying next...`);
|
|
19509
|
+
}
|
|
19510
|
+
this.attemptStrategy(index + 1, strategies);
|
|
19511
|
+
}
|
|
19512
|
+
else {
|
|
19513
|
+
if (this.config.debug) {
|
|
19514
|
+
console.log(`[✅ AutoTracker] Strategy ${index + 1} successful!`);
|
|
19515
|
+
}
|
|
19516
|
+
}
|
|
19517
|
+
}, 50);
|
|
19518
|
+
}
|
|
19519
|
+
else {
|
|
19520
|
+
// Strategy is undefined or not a function, try next
|
|
19521
|
+
this.attemptStrategy(index + 1, strategies);
|
|
19522
|
+
}
|
|
19523
|
+
}
|
|
19524
|
+
catch (error) {
|
|
19525
|
+
if (this.config.debug) {
|
|
19526
|
+
console.error(`[❌ AutoTracker] Strategy ${index + 1} error:`, error);
|
|
19527
|
+
}
|
|
19528
|
+
this.attemptStrategy(index + 1, strategies);
|
|
19529
|
+
}
|
|
19530
|
+
}
|
|
19531
|
+
/**
|
|
19532
|
+
* Immediate initialization
|
|
19533
|
+
*/
|
|
19534
|
+
immediateInitialization() {
|
|
19535
|
+
this.initializeTracking();
|
|
19536
|
+
}
|
|
19537
|
+
/**
|
|
19538
|
+
* Delayed initialization
|
|
19539
|
+
*/
|
|
19540
|
+
delayedInitialization(delay) {
|
|
19541
|
+
setTimeout(() => {
|
|
19394
19542
|
this.initializeTracking();
|
|
19543
|
+
}, delay);
|
|
19544
|
+
}
|
|
19545
|
+
/**
|
|
19546
|
+
* React-specific initialization timing
|
|
19547
|
+
*/
|
|
19548
|
+
reactReadyInitialization() {
|
|
19549
|
+
// Wait for React to finish rendering
|
|
19550
|
+
if (typeof window.requestAnimationFrame === 'function') {
|
|
19551
|
+
window.requestAnimationFrame(() => {
|
|
19552
|
+
setTimeout(() => {
|
|
19553
|
+
this.initializeTracking();
|
|
19554
|
+
}, 0);
|
|
19555
|
+
});
|
|
19395
19556
|
}
|
|
19557
|
+
else {
|
|
19558
|
+
setTimeout(() => {
|
|
19559
|
+
this.initializeTracking();
|
|
19560
|
+
}, 16); // ~60fps fallback
|
|
19561
|
+
}
|
|
19562
|
+
}
|
|
19563
|
+
/**
|
|
19564
|
+
* Verify initialization was successful
|
|
19565
|
+
*/
|
|
19566
|
+
verifyInitialization() {
|
|
19567
|
+
const elementsFound = this.getElementCounts();
|
|
19568
|
+
const totalElements = Object.values(elementsFound).reduce((sum, count) => sum + count, 0);
|
|
19569
|
+
const hasActiveHandlers = this.delegationHandlers.size > 0;
|
|
19570
|
+
if (this.config.debug) {
|
|
19571
|
+
console.log('[🔍 AutoTracker] Verification:', {
|
|
19572
|
+
isInitialized: this.isInitialized,
|
|
19573
|
+
elementsFound: totalElements,
|
|
19574
|
+
hasActiveHandlers,
|
|
19575
|
+
handlersActive: Array.from(this.delegationHandlers.keys())
|
|
19576
|
+
});
|
|
19577
|
+
}
|
|
19578
|
+
return this.isInitialized && (totalElements > 0 || hasActiveHandlers);
|
|
19396
19579
|
}
|
|
19397
19580
|
initializeTracking() {
|
|
19398
19581
|
if (this.config.debug) {
|
|
@@ -19452,118 +19635,271 @@
|
|
|
19452
19635
|
*/
|
|
19453
19636
|
setupEventDelegation() {
|
|
19454
19637
|
if (this.config.debug) {
|
|
19455
|
-
console.log("[AutoTracker] Setting up event delegation...");
|
|
19638
|
+
console.log("[🚀 AutoTracker] Setting up enhanced event delegation...");
|
|
19456
19639
|
}
|
|
19457
|
-
//
|
|
19640
|
+
// Determine optimal delegation target based on React setup
|
|
19641
|
+
const delegationTarget = this.getOptimalDelegationTarget();
|
|
19642
|
+
if (this.config.debug) {
|
|
19643
|
+
console.log("[🎯 AutoTracker] Using delegation target:", delegationTarget);
|
|
19644
|
+
}
|
|
19645
|
+
// Click delegation with React compatibility
|
|
19458
19646
|
if (this.config.trackClicks) {
|
|
19459
|
-
const clickHandler = this.
|
|
19647
|
+
const clickHandler = this.createReactCompatibleClickHandler();
|
|
19460
19648
|
this.delegationHandlers.set('click', clickHandler);
|
|
19461
|
-
|
|
19649
|
+
delegationTarget.addEventListener('click', clickHandler, this.getEventOptions('click'));
|
|
19462
19650
|
}
|
|
19463
|
-
// Scroll delegation
|
|
19651
|
+
// Scroll delegation with enhanced detection
|
|
19464
19652
|
if (this.config.trackScrolls) {
|
|
19465
|
-
const scrollHandler = this.
|
|
19653
|
+
const scrollHandler = this.createEnhancedScrollHandler();
|
|
19466
19654
|
this.delegationHandlers.set('scroll', scrollHandler);
|
|
19467
|
-
document.addEventListener('scroll', scrollHandler,
|
|
19655
|
+
document.addEventListener('scroll', scrollHandler, this.getEventOptions('scroll'));
|
|
19468
19656
|
}
|
|
19469
19657
|
// Setup debounced mutation observer for dynamic content
|
|
19470
19658
|
this.setupIntelligentMutationObserver();
|
|
19471
19659
|
this.isInitialized = true;
|
|
19660
|
+
if (this.config.debug) {
|
|
19661
|
+
console.log("[✅ AutoTracker] Event delegation setup complete");
|
|
19662
|
+
}
|
|
19472
19663
|
}
|
|
19473
19664
|
/**
|
|
19474
|
-
*
|
|
19665
|
+
* Get optimal delegation target based on React setup
|
|
19475
19666
|
*/
|
|
19476
|
-
|
|
19477
|
-
|
|
19478
|
-
|
|
19479
|
-
|
|
19480
|
-
|
|
19481
|
-
|
|
19482
|
-
const trackingElement = target.closest('[data-track-click]');
|
|
19483
|
-
if (!trackingElement)
|
|
19484
|
-
return;
|
|
19485
|
-
const eventName = trackingElement.getAttribute('data-track-click');
|
|
19486
|
-
if (!eventName)
|
|
19487
|
-
return;
|
|
19488
|
-
const metadata = this.extractMetadata(trackingElement);
|
|
19489
|
-
this.trackEvent(eventName, {
|
|
19490
|
-
type: 'click',
|
|
19491
|
-
element: trackingElement.tagName.toLowerCase(),
|
|
19492
|
-
...metadata,
|
|
19493
|
-
});
|
|
19667
|
+
getOptimalDelegationTarget() {
|
|
19668
|
+
// For React 17+, prefer root container over document
|
|
19669
|
+
const reactRoot = document.querySelector('#root') ||
|
|
19670
|
+
document.querySelector('#__next') ||
|
|
19671
|
+
document.querySelector('[data-reactroot]');
|
|
19672
|
+
if (reactRoot && this.diagnostics.environment?.reactDetected) {
|
|
19494
19673
|
if (this.config.debug) {
|
|
19495
|
-
console.log(
|
|
19674
|
+
console.log("[⚛️ AutoTracker] Using React root for delegation:", reactRoot);
|
|
19675
|
+
}
|
|
19676
|
+
return reactRoot;
|
|
19677
|
+
}
|
|
19678
|
+
return document;
|
|
19679
|
+
}
|
|
19680
|
+
/**
|
|
19681
|
+
* Get optimized event options for different browsers
|
|
19682
|
+
*/
|
|
19683
|
+
getEventOptions(eventType) {
|
|
19684
|
+
this.diagnostics.environment?.isMobile;
|
|
19685
|
+
const isSafari = this.diagnostics.environment?.isSafari;
|
|
19686
|
+
let options = {};
|
|
19687
|
+
switch (eventType) {
|
|
19688
|
+
case 'click':
|
|
19689
|
+
// Safari iOS requires non-passive click events for proper delegation
|
|
19690
|
+
options = {
|
|
19691
|
+
passive: !isSafari,
|
|
19692
|
+
capture: false
|
|
19693
|
+
};
|
|
19694
|
+
break;
|
|
19695
|
+
case 'scroll':
|
|
19696
|
+
options = {
|
|
19697
|
+
passive: true,
|
|
19698
|
+
capture: false
|
|
19699
|
+
};
|
|
19700
|
+
break;
|
|
19701
|
+
default:
|
|
19702
|
+
options = { passive: true };
|
|
19703
|
+
}
|
|
19704
|
+
if (this.config.debug) {
|
|
19705
|
+
console.log(`[⚙️ AutoTracker] Event options for ${eventType}:`, options);
|
|
19706
|
+
}
|
|
19707
|
+
return options;
|
|
19708
|
+
}
|
|
19709
|
+
/**
|
|
19710
|
+
* Create React-compatible click handler
|
|
19711
|
+
*/
|
|
19712
|
+
createReactCompatibleClickHandler() {
|
|
19713
|
+
return (event) => {
|
|
19714
|
+
try {
|
|
19715
|
+
if (!this.config.trackClicks)
|
|
19716
|
+
return;
|
|
19717
|
+
// Enhanced target detection for nested React components
|
|
19718
|
+
const target = event.target;
|
|
19719
|
+
if (!target)
|
|
19720
|
+
return;
|
|
19721
|
+
// Multiple strategies to find tracking element
|
|
19722
|
+
let trackingElement = null;
|
|
19723
|
+
// Strategy 1: Direct closest (most common)
|
|
19724
|
+
trackingElement = target.closest('[data-track-click]');
|
|
19725
|
+
// Strategy 2: Check if target itself has the attribute (React edge case)
|
|
19726
|
+
if (!trackingElement && target.hasAttribute && target.hasAttribute('data-track-click')) {
|
|
19727
|
+
trackingElement = target;
|
|
19728
|
+
}
|
|
19729
|
+
// Strategy 3: Walk up DOM tree manually (React portal handling)
|
|
19730
|
+
if (!trackingElement) {
|
|
19731
|
+
trackingElement = this.findTrackingElementManually(target, 'data-track-click');
|
|
19732
|
+
}
|
|
19733
|
+
if (!trackingElement) {
|
|
19734
|
+
if (this.config.debug) {
|
|
19735
|
+
console.log('[🔍 AutoTracker] No tracking element found for click:', {
|
|
19736
|
+
target: target.tagName,
|
|
19737
|
+
hasClosest: typeof target.closest === 'function',
|
|
19738
|
+
hasAttribute: typeof target.hasAttribute === 'function'
|
|
19739
|
+
});
|
|
19740
|
+
}
|
|
19741
|
+
return;
|
|
19742
|
+
}
|
|
19743
|
+
const eventName = trackingElement.getAttribute('data-track-click');
|
|
19744
|
+
if (!eventName)
|
|
19745
|
+
return;
|
|
19746
|
+
const metadata = this.extractMetadata(trackingElement);
|
|
19747
|
+
this.trackEvent(eventName, {
|
|
19748
|
+
type: 'click',
|
|
19496
19749
|
element: trackingElement.tagName.toLowerCase(),
|
|
19497
|
-
|
|
19750
|
+
reactCompatible: true,
|
|
19751
|
+
...metadata,
|
|
19498
19752
|
});
|
|
19753
|
+
if (this.config.debug) {
|
|
19754
|
+
console.log(`[🎯 AutoTracker] Click tracked (React-compatible): ${eventName}`, {
|
|
19755
|
+
element: trackingElement.tagName.toLowerCase(),
|
|
19756
|
+
strategy: 'enhanced_delegation',
|
|
19757
|
+
...metadata
|
|
19758
|
+
});
|
|
19759
|
+
}
|
|
19760
|
+
}
|
|
19761
|
+
catch (error) {
|
|
19762
|
+
if (this.config.debug) {
|
|
19763
|
+
console.error('[❌ AutoTracker] Click handler error:', error);
|
|
19764
|
+
}
|
|
19499
19765
|
}
|
|
19500
19766
|
};
|
|
19501
19767
|
}
|
|
19502
19768
|
/**
|
|
19503
|
-
*
|
|
19769
|
+
* Manually walk up DOM tree to find tracking element
|
|
19504
19770
|
*/
|
|
19505
|
-
|
|
19771
|
+
findTrackingElementManually(element, attribute, maxDepth = 10) {
|
|
19772
|
+
let current = element;
|
|
19773
|
+
let depth = 0;
|
|
19774
|
+
while (current && current !== document.documentElement && depth < maxDepth) {
|
|
19775
|
+
if (current.hasAttribute && current.hasAttribute(attribute)) {
|
|
19776
|
+
return current;
|
|
19777
|
+
}
|
|
19778
|
+
current = current.parentElement;
|
|
19779
|
+
depth++;
|
|
19780
|
+
}
|
|
19781
|
+
return null;
|
|
19782
|
+
}
|
|
19783
|
+
/**
|
|
19784
|
+
* Create enhanced scroll handler with better performance
|
|
19785
|
+
*/
|
|
19786
|
+
createEnhancedScrollHandler() {
|
|
19506
19787
|
return () => {
|
|
19507
|
-
|
|
19508
|
-
|
|
19509
|
-
|
|
19510
|
-
|
|
19511
|
-
|
|
19512
|
-
|
|
19513
|
-
|
|
19514
|
-
|
|
19515
|
-
|
|
19516
|
-
|
|
19517
|
-
|
|
19788
|
+
try {
|
|
19789
|
+
if (!this.config.trackScrolls)
|
|
19790
|
+
return;
|
|
19791
|
+
// Adaptive throttling based on scroll frequency
|
|
19792
|
+
const now = Date.now();
|
|
19793
|
+
const timeDelta = now - this.scrollThrottle;
|
|
19794
|
+
const throttleDelay = this.diagnostics.environment?.isMobile ? 150 : 100;
|
|
19795
|
+
if (timeDelta < throttleDelay)
|
|
19796
|
+
return;
|
|
19797
|
+
this.scrollThrottle = now;
|
|
19798
|
+
// Enhanced element finding with caching
|
|
19799
|
+
const scrollElements = this.getCachedScrollElements();
|
|
19800
|
+
if (this.config.debug && scrollElements.length > 0) {
|
|
19801
|
+
console.log(`[📜 AutoTracker] Processing ${scrollElements.length} scroll elements`, {
|
|
19802
|
+
throttleDelay,
|
|
19803
|
+
timeDelta,
|
|
19804
|
+
scrollY: window.scrollY
|
|
19805
|
+
});
|
|
19806
|
+
}
|
|
19807
|
+
// Process elements with enhanced visibility detection
|
|
19808
|
+
scrollElements.forEach((element) => {
|
|
19809
|
+
this.processScrollElementEnhanced(element);
|
|
19810
|
+
});
|
|
19811
|
+
}
|
|
19812
|
+
catch (error) {
|
|
19813
|
+
if (this.config.debug) {
|
|
19814
|
+
console.error('[❌ AutoTracker] Scroll handler error:', error);
|
|
19815
|
+
}
|
|
19518
19816
|
}
|
|
19519
|
-
scrollElements.forEach((element) => {
|
|
19520
|
-
this.processScrollElement(element);
|
|
19521
|
-
});
|
|
19522
19817
|
};
|
|
19523
19818
|
}
|
|
19819
|
+
getCachedScrollElements() {
|
|
19820
|
+
const now = Date.now();
|
|
19821
|
+
const cacheExpiry = 5000; // 5 seconds
|
|
19822
|
+
if (!this.cachedScrollElements || (now - this.lastScrollElementsCheck) > cacheExpiry) {
|
|
19823
|
+
this.cachedScrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19824
|
+
this.lastScrollElementsCheck = now;
|
|
19825
|
+
if (this.config.debug) {
|
|
19826
|
+
console.log(`[🔄 AutoTracker] Refreshed scroll elements cache: ${this.cachedScrollElements.length} elements`);
|
|
19827
|
+
}
|
|
19828
|
+
}
|
|
19829
|
+
return this.cachedScrollElements;
|
|
19830
|
+
}
|
|
19524
19831
|
/**
|
|
19525
|
-
* Process
|
|
19832
|
+
* Process scroll element with enhanced detection
|
|
19526
19833
|
*/
|
|
19527
|
-
|
|
19528
|
-
|
|
19529
|
-
|
|
19530
|
-
|
|
19531
|
-
const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
|
|
19532
|
-
const rect = element.getBoundingClientRect();
|
|
19533
|
-
const elementHeight = rect.height;
|
|
19534
|
-
const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
|
|
19535
|
-
const visibilityRatio = Math.max(0, visibleHeight) / elementHeight;
|
|
19536
|
-
if (this.config.debug) {
|
|
19537
|
-
console.log(`[AutoTracker] Scroll element check via delegation:`, {
|
|
19538
|
-
elementId: element.id || element.className,
|
|
19539
|
-
visibilityRatio: Math.round(visibilityRatio * 100) / 100,
|
|
19540
|
-
threshold,
|
|
19541
|
-
triggered: hasTriggered
|
|
19542
|
-
});
|
|
19543
|
-
}
|
|
19544
|
-
if (visibilityRatio >= threshold) {
|
|
19545
|
-
element.setAttribute('data-scroll-triggered', 'true');
|
|
19546
|
-
const eventName = element.getAttribute('data-track-scroll');
|
|
19547
|
-
if (!eventName)
|
|
19834
|
+
processScrollElementEnhanced(element) {
|
|
19835
|
+
try {
|
|
19836
|
+
const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
|
|
19837
|
+
if (hasTriggered)
|
|
19548
19838
|
return;
|
|
19549
|
-
const
|
|
19550
|
-
|
|
19551
|
-
|
|
19552
|
-
|
|
19553
|
-
|
|
19554
|
-
|
|
19555
|
-
|
|
19556
|
-
|
|
19557
|
-
|
|
19839
|
+
const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
|
|
19840
|
+
// Enhanced visibility calculation
|
|
19841
|
+
const rect = element.getBoundingClientRect();
|
|
19842
|
+
const elementHeight = rect.height;
|
|
19843
|
+
const windowHeight = window.innerHeight;
|
|
19844
|
+
// Handle edge cases
|
|
19845
|
+
if (elementHeight <= 0)
|
|
19846
|
+
return;
|
|
19847
|
+
const visibleTop = Math.max(rect.top, 0);
|
|
19848
|
+
const visibleBottom = Math.min(rect.bottom, windowHeight);
|
|
19849
|
+
const visibleHeight = Math.max(0, visibleBottom - visibleTop);
|
|
19850
|
+
const visibilityRatio = visibleHeight / elementHeight;
|
|
19558
19851
|
if (this.config.debug) {
|
|
19559
|
-
console.log(`[AutoTracker]
|
|
19852
|
+
console.log(`[📊 AutoTracker] Enhanced scroll check:`, {
|
|
19853
|
+
elementId: element.id || element.className || 'no-id',
|
|
19854
|
+
rect: {
|
|
19855
|
+
top: Math.round(rect.top),
|
|
19856
|
+
bottom: Math.round(rect.bottom),
|
|
19857
|
+
height: Math.round(elementHeight)
|
|
19858
|
+
},
|
|
19859
|
+
visibility: {
|
|
19860
|
+
ratio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19861
|
+
threshold,
|
|
19862
|
+
triggered: hasTriggered
|
|
19863
|
+
},
|
|
19864
|
+
scroll: window.scrollY
|
|
19865
|
+
});
|
|
19866
|
+
}
|
|
19867
|
+
if (visibilityRatio >= threshold) {
|
|
19868
|
+
element.setAttribute('data-scroll-triggered', 'true');
|
|
19869
|
+
const eventName = element.getAttribute('data-track-scroll');
|
|
19870
|
+
if (!eventName)
|
|
19871
|
+
return;
|
|
19872
|
+
const metadata = this.extractMetadata(element);
|
|
19873
|
+
this.trackEvent(eventName, {
|
|
19874
|
+
type: 'scroll',
|
|
19875
|
+
element: element.tagName.toLowerCase(),
|
|
19560
19876
|
threshold,
|
|
19561
|
-
visibilityRatio,
|
|
19562
19877
|
scrollDepth: window.scrollY,
|
|
19563
|
-
|
|
19878
|
+
visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19879
|
+
enhanced: true,
|
|
19880
|
+
...metadata,
|
|
19564
19881
|
});
|
|
19882
|
+
if (this.config.debug) {
|
|
19883
|
+
console.log(`[🎯 AutoTracker] Scroll tracked (enhanced): ${eventName}`, {
|
|
19884
|
+
threshold,
|
|
19885
|
+
visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19886
|
+
scrollDepth: window.scrollY,
|
|
19887
|
+
...metadata
|
|
19888
|
+
});
|
|
19889
|
+
}
|
|
19565
19890
|
}
|
|
19566
19891
|
}
|
|
19892
|
+
catch (error) {
|
|
19893
|
+
if (this.config.debug) {
|
|
19894
|
+
console.error('[❌ AutoTracker] Scroll element processing error:', error);
|
|
19895
|
+
}
|
|
19896
|
+
}
|
|
19897
|
+
}
|
|
19898
|
+
/**
|
|
19899
|
+
* Legacy method for compatibility
|
|
19900
|
+
*/
|
|
19901
|
+
processScrollElement(element) {
|
|
19902
|
+
this.processScrollElementEnhanced(element);
|
|
19567
19903
|
}
|
|
19568
19904
|
/**
|
|
19569
19905
|
* Setup intelligent mutation observer (debounced for performance)
|
|
@@ -19855,43 +20191,88 @@
|
|
|
19855
20191
|
/**
|
|
19856
20192
|
* Enviar evento para o SDK
|
|
19857
20193
|
*/
|
|
20194
|
+
/**
|
|
20195
|
+
* Enhanced event tracking with comprehensive debugging
|
|
20196
|
+
*/
|
|
19858
20197
|
trackEvent(eventName, metadata) {
|
|
20198
|
+
const trackingStart = performance.now();
|
|
19859
20199
|
if (this.config.debug) {
|
|
19860
|
-
console.log("[AutoTracker] trackEvent called:", {
|
|
19861
|
-
|
|
19862
|
-
|
|
19863
|
-
|
|
19864
|
-
|
|
19865
|
-
}
|
|
19866
|
-
return;
|
|
20200
|
+
console.log("[🚀 AutoTracker] Enhanced trackEvent called:", {
|
|
20201
|
+
eventName,
|
|
20202
|
+
metadata,
|
|
20203
|
+
timestamp: new Date().toISOString()
|
|
20204
|
+
});
|
|
19867
20205
|
}
|
|
19868
|
-
|
|
20206
|
+
// Comprehensive validation
|
|
20207
|
+
const validation = this.validateTrackingCall(eventName, metadata);
|
|
20208
|
+
if (!validation.isValid) {
|
|
19869
20209
|
if (this.config.debug) {
|
|
19870
|
-
console.error("[AutoTracker]
|
|
20210
|
+
console.error("[❌ AutoTracker] Validation failed:", validation.errors);
|
|
19871
20211
|
}
|
|
19872
20212
|
return;
|
|
19873
20213
|
}
|
|
19874
20214
|
try {
|
|
19875
20215
|
const eventData = {
|
|
20216
|
+
// Core tracking data
|
|
19876
20217
|
autoTracked: true,
|
|
20218
|
+
enhanced: true,
|
|
19877
20219
|
timestamp: Date.now(),
|
|
19878
20220
|
url: window.location.href,
|
|
20221
|
+
userAgent: navigator.userAgent,
|
|
20222
|
+
// Performance data
|
|
20223
|
+
trackingLatency: Math.round((performance.now() - trackingStart) * 100) / 100,
|
|
20224
|
+
// Environment data
|
|
20225
|
+
isReactApp: this.diagnostics.environment?.reactDetected,
|
|
20226
|
+
isMobile: this.diagnostics.environment?.isMobile,
|
|
20227
|
+
// Event metadata
|
|
19879
20228
|
...metadata,
|
|
19880
20229
|
};
|
|
19881
20230
|
if (this.config.debug) {
|
|
19882
|
-
console.log("[AutoTracker]
|
|
20231
|
+
console.log("[📡 AutoTracker] Sending enhanced event:", { eventName, eventData });
|
|
19883
20232
|
}
|
|
19884
20233
|
const result = this.sdkInstance.trackCustomEvent(eventName, eventData);
|
|
19885
20234
|
if (this.config.debug) {
|
|
19886
|
-
|
|
20235
|
+
const trackingEnd = performance.now();
|
|
20236
|
+
console.log("[✅ AutoTracker] Event sent successfully:", {
|
|
20237
|
+
eventName,
|
|
20238
|
+
result,
|
|
20239
|
+
totalLatency: Math.round((trackingEnd - trackingStart) * 100) / 100 + 'ms'
|
|
20240
|
+
});
|
|
19887
20241
|
}
|
|
19888
20242
|
}
|
|
19889
20243
|
catch (error) {
|
|
19890
20244
|
if (this.config.debug) {
|
|
19891
|
-
console.error("[AutoTracker]
|
|
20245
|
+
console.error("[💥 AutoTracker] Critical tracking error:", {
|
|
20246
|
+
eventName,
|
|
20247
|
+
error: error instanceof Error ? error.message : error,
|
|
20248
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
20249
|
+
metadata
|
|
20250
|
+
});
|
|
19892
20251
|
}
|
|
19893
20252
|
}
|
|
19894
20253
|
}
|
|
20254
|
+
/**
|
|
20255
|
+
* Validate tracking call before sending
|
|
20256
|
+
*/
|
|
20257
|
+
validateTrackingCall(eventName, metadata) {
|
|
20258
|
+
const errors = [];
|
|
20259
|
+
if (!eventName || typeof eventName !== 'string') {
|
|
20260
|
+
errors.push('Event name is required and must be a string');
|
|
20261
|
+
}
|
|
20262
|
+
if (!this.sdkInstance) {
|
|
20263
|
+
errors.push('SDK instance is null or undefined');
|
|
20264
|
+
}
|
|
20265
|
+
if (this.sdkInstance && typeof this.sdkInstance.trackCustomEvent !== 'function') {
|
|
20266
|
+
errors.push(`trackCustomEvent is not a function: ${typeof this.sdkInstance.trackCustomEvent}`);
|
|
20267
|
+
}
|
|
20268
|
+
if (!window || typeof window !== 'object') {
|
|
20269
|
+
errors.push('Window object is not available');
|
|
20270
|
+
}
|
|
20271
|
+
return {
|
|
20272
|
+
isValid: errors.length === 0,
|
|
20273
|
+
errors
|
|
20274
|
+
};
|
|
20275
|
+
}
|
|
19895
20276
|
/**
|
|
19896
20277
|
* Modern API: Refresh tracking for dynamic content (React/SPA support)
|
|
19897
20278
|
* Industry best practice for SPA route changes
|
|
@@ -19921,26 +20302,83 @@
|
|
|
19921
20302
|
this.refreshTracking();
|
|
19922
20303
|
}
|
|
19923
20304
|
/**
|
|
19924
|
-
* Get diagnostic information for debugging
|
|
20305
|
+
* Get comprehensive diagnostic information for debugging
|
|
19925
20306
|
*/
|
|
19926
20307
|
getDiagnostics() {
|
|
19927
20308
|
return {
|
|
19928
|
-
|
|
19929
|
-
|
|
19930
|
-
|
|
19931
|
-
|
|
19932
|
-
|
|
19933
|
-
|
|
20309
|
+
// Initialization status
|
|
20310
|
+
initialization: {
|
|
20311
|
+
isInitialized: this.isInitialized,
|
|
20312
|
+
attempts: this.initializationAttempts,
|
|
20313
|
+
maxAttempts: this.maxInitializationAttempts,
|
|
20314
|
+
timestamp: new Date().toISOString()
|
|
20315
|
+
},
|
|
20316
|
+
// Event handlers status
|
|
20317
|
+
eventHandlers: {
|
|
20318
|
+
hasClickHandler: this.delegationHandlers.has('click'),
|
|
20319
|
+
hasScrollHandler: this.delegationHandlers.has('scroll'),
|
|
20320
|
+
activeHandlers: Array.from(this.delegationHandlers.keys()),
|
|
20321
|
+
delegationTarget: this.getOptimalDelegationTarget() === document ? 'document' : 'react-root'
|
|
20322
|
+
},
|
|
20323
|
+
// Observers status
|
|
20324
|
+
observers: {
|
|
20325
|
+
observedElements: this.observedElements.size,
|
|
20326
|
+
hasMutationObserver: !!this.mutationObserver,
|
|
20327
|
+
hasIntersectionObserver: !!this.intersectionObserver,
|
|
20328
|
+
scrollElementsCache: !!this.cachedScrollElements,
|
|
20329
|
+
cacheExpiry: new Date(this.lastScrollElementsCheck + 5000).toISOString()
|
|
20330
|
+
},
|
|
20331
|
+
// Configuration
|
|
19934
20332
|
config: this.config,
|
|
19935
|
-
|
|
19936
|
-
|
|
19937
|
-
|
|
19938
|
-
|
|
19939
|
-
|
|
19940
|
-
|
|
19941
|
-
|
|
20333
|
+
// Current environment diagnostics
|
|
20334
|
+
environment: this.diagnostics.environment || {},
|
|
20335
|
+
// DOM state
|
|
20336
|
+
dom: this.diagnostics.dom || {},
|
|
20337
|
+
// SDK state
|
|
20338
|
+
tracking: this.diagnostics.tracking || {},
|
|
20339
|
+
// Real-time element detection
|
|
20340
|
+
elementsFound: this.getElementCounts(),
|
|
20341
|
+
// Performance metrics
|
|
20342
|
+
performance: {
|
|
20343
|
+
lastScrollThrottle: this.scrollThrottle,
|
|
20344
|
+
cacheLastUpdate: this.lastScrollElementsCheck
|
|
20345
|
+
},
|
|
20346
|
+
// Validation status
|
|
20347
|
+
validation: this.validateTrackingCall('test', {}),
|
|
20348
|
+
// Debug recommendations
|
|
20349
|
+
recommendations: this.generateRecommendations()
|
|
19942
20350
|
};
|
|
19943
20351
|
}
|
|
20352
|
+
/**
|
|
20353
|
+
* Generate diagnostic recommendations
|
|
20354
|
+
*/
|
|
20355
|
+
generateRecommendations() {
|
|
20356
|
+
const recommendations = [];
|
|
20357
|
+
const elementsFound = this.getElementCounts();
|
|
20358
|
+
const totalElements = Object.values(elementsFound).reduce((sum, count) => sum + count, 0);
|
|
20359
|
+
if (!this.isInitialized) {
|
|
20360
|
+
recommendations.push('AutoTracker is not initialized. Check console for errors.');
|
|
20361
|
+
}
|
|
20362
|
+
if (totalElements === 0) {
|
|
20363
|
+
recommendations.push('No trackable elements found. Ensure data-track-* attributes are present in the DOM.');
|
|
20364
|
+
}
|
|
20365
|
+
if (!this.sdkInstance) {
|
|
20366
|
+
recommendations.push('SDK instance is missing. Ensure the SDK is properly initialized.');
|
|
20367
|
+
}
|
|
20368
|
+
if (this.sdkInstance && typeof this.sdkInstance.trackCustomEvent !== 'function') {
|
|
20369
|
+
recommendations.push('trackCustomEvent method is not available on SDK instance.');
|
|
20370
|
+
}
|
|
20371
|
+
if (!this.diagnostics.environment?.reactDetected && window.location.hostname.includes('localhost')) {
|
|
20372
|
+
recommendations.push('React not detected. If using React, ensure proper setup and try refreshTracking() after route changes.');
|
|
20373
|
+
}
|
|
20374
|
+
if (this.diagnostics.environment?.isMobile && !this.delegationHandlers.has('scroll')) {
|
|
20375
|
+
recommendations.push('Mobile device detected but scroll tracking not active. Check scroll tracking configuration.');
|
|
20376
|
+
}
|
|
20377
|
+
if (this.initializationAttempts > 1) {
|
|
20378
|
+
recommendations.push(`AutoTracker required ${this.initializationAttempts} initialization attempts. Consider adding delay before enabling.`);
|
|
20379
|
+
}
|
|
20380
|
+
return recommendations;
|
|
20381
|
+
}
|
|
19944
20382
|
/**
|
|
19945
20383
|
* Configurar tracking
|
|
19946
20384
|
*/
|