@zaplier/sdk 1.6.9 → 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 +818 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/index.esm.js +818 -51
- package/dist/index.esm.js.map +1 -1
- package/dist/sdk.js +818 -51
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.min.js +1 -1
- package/dist/src/modules/auto-tracker.d.ts +138 -3
- package/dist/src/modules/auto-tracker.d.ts.map +1 -1
- package/dist/src/modules/global-interface.d.ts +2 -0
- package/dist/src/modules/global-interface.d.ts.map +1 -1
- package/dist/src/sdk.d.ts +16 -0
- package/dist/src/sdk.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -19266,6 +19266,16 @@ class AutoTracker {
|
|
|
19266
19266
|
constructor(sdkInstance, config = {}) {
|
|
19267
19267
|
this.observedElements = new Set();
|
|
19268
19268
|
this.scrollThrottle = 0;
|
|
19269
|
+
this.isInitialized = false;
|
|
19270
|
+
this.delegationHandlers = new Map();
|
|
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;
|
|
19269
19279
|
this.handleScroll = () => {
|
|
19270
19280
|
if (!this.config.trackScrolls)
|
|
19271
19281
|
return;
|
|
@@ -19363,37 +19373,211 @@ class AutoTracker {
|
|
|
19363
19373
|
start() {
|
|
19364
19374
|
if (!this.config.enabled)
|
|
19365
19375
|
return;
|
|
19376
|
+
this.initializationAttempts++;
|
|
19377
|
+
// Enhanced diagnostics
|
|
19378
|
+
this.runDiagnostics();
|
|
19366
19379
|
if (this.config.debug) {
|
|
19367
|
-
console.log("[
|
|
19368
|
-
|
|
19369
|
-
|
|
19370
|
-
|
|
19371
|
-
|
|
19372
|
-
|
|
19373
|
-
|
|
19380
|
+
console.log("[🔥 AutoTracker ENHANCED] Starting auto tracking", this.diagnostics);
|
|
19381
|
+
}
|
|
19382
|
+
// Multiple initialization strategies
|
|
19383
|
+
this.tryInitialization();
|
|
19384
|
+
}
|
|
19385
|
+
/**
|
|
19386
|
+
* Run comprehensive diagnostics
|
|
19387
|
+
*/
|
|
19388
|
+
runDiagnostics() {
|
|
19389
|
+
this.diagnostics = {
|
|
19390
|
+
timestamp: new Date().toISOString(),
|
|
19391
|
+
attempt: this.initializationAttempts,
|
|
19392
|
+
environment: {
|
|
19393
|
+
domReady: document.readyState,
|
|
19394
|
+
reactDetected: this.detectReact(),
|
|
19395
|
+
reactVersion: this.getReactVersion(),
|
|
19396
|
+
userAgent: navigator.userAgent,
|
|
19397
|
+
isMobile: /Mobile|Android|iPhone|iPad/.test(navigator.userAgent),
|
|
19398
|
+
isSafari: /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent),
|
|
19399
|
+
protocol: window.location.protocol,
|
|
19400
|
+
isLocalhost: window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
|
|
19401
|
+
},
|
|
19402
|
+
dom: {
|
|
19403
|
+
documentElement: !!document.documentElement,
|
|
19404
|
+
body: !!document.body,
|
|
19405
|
+
querySelector: typeof document.querySelector === 'function',
|
|
19406
|
+
addEventListener: typeof document.addEventListener === 'function',
|
|
19407
|
+
elementsFound: this.getElementCounts(),
|
|
19408
|
+
hasReactRoot: this.findReactRoot()
|
|
19409
|
+
},
|
|
19410
|
+
tracking: {
|
|
19411
|
+
sdkInstance: !!this.sdkInstance,
|
|
19412
|
+
trackCustomEvent: typeof this.sdkInstance?.trackCustomEvent === 'function',
|
|
19413
|
+
config: this.config,
|
|
19414
|
+
isInitialized: this.isInitialized,
|
|
19415
|
+
activeHandlers: Array.from(this.delegationHandlers.keys())
|
|
19416
|
+
}
|
|
19417
|
+
};
|
|
19418
|
+
}
|
|
19419
|
+
/**
|
|
19420
|
+
* Detect React presence
|
|
19421
|
+
*/
|
|
19422
|
+
detectReact() {
|
|
19423
|
+
return !!(window.__REACT_DEVTOOLS_GLOBAL_HOOK__ ||
|
|
19424
|
+
window.React ||
|
|
19425
|
+
document.querySelector('[data-reactroot]') ||
|
|
19426
|
+
document.querySelector('#root') ||
|
|
19427
|
+
document.querySelector('#__next'));
|
|
19428
|
+
}
|
|
19429
|
+
/**
|
|
19430
|
+
* Get React version if available
|
|
19431
|
+
*/
|
|
19432
|
+
getReactVersion() {
|
|
19433
|
+
try {
|
|
19434
|
+
const reactInstance = window.React;
|
|
19435
|
+
return reactInstance?.version || null;
|
|
19436
|
+
}
|
|
19437
|
+
catch {
|
|
19438
|
+
return null;
|
|
19439
|
+
}
|
|
19440
|
+
}
|
|
19441
|
+
/**
|
|
19442
|
+
* Find React root element
|
|
19443
|
+
*/
|
|
19444
|
+
findReactRoot() {
|
|
19445
|
+
const reactRoot = document.querySelector('[data-reactroot]') ||
|
|
19446
|
+
document.querySelector('#root') ||
|
|
19447
|
+
document.querySelector('#__next') ||
|
|
19448
|
+
document.querySelector('div[data-react-helmet]');
|
|
19449
|
+
return reactRoot ? reactRoot.tagName + (reactRoot.id ? '#' + reactRoot.id : '') : null;
|
|
19450
|
+
}
|
|
19451
|
+
/**
|
|
19452
|
+
* Get element counts for all tracking types
|
|
19453
|
+
*/
|
|
19454
|
+
getElementCounts() {
|
|
19455
|
+
return {
|
|
19456
|
+
click: document.querySelectorAll('[data-track-click]').length,
|
|
19457
|
+
scroll: document.querySelectorAll('[data-track-scroll]').length,
|
|
19458
|
+
view: document.querySelectorAll('[data-track-view]').length,
|
|
19459
|
+
hover: document.querySelectorAll('[data-track-hover]').length,
|
|
19460
|
+
form: document.querySelectorAll('[data-track-form]').length
|
|
19461
|
+
};
|
|
19462
|
+
}
|
|
19463
|
+
/**
|
|
19464
|
+
* Try multiple initialization strategies
|
|
19465
|
+
*/
|
|
19466
|
+
tryInitialization() {
|
|
19467
|
+
const strategies = [
|
|
19468
|
+
() => this.immediateInitialization(),
|
|
19469
|
+
() => this.delayedInitialization(100),
|
|
19470
|
+
() => this.delayedInitialization(500),
|
|
19471
|
+
() => this.delayedInitialization(1000),
|
|
19472
|
+
() => this.reactReadyInitialization()
|
|
19473
|
+
];
|
|
19474
|
+
// Try immediate initialization first
|
|
19475
|
+
if (document.readyState === 'complete') {
|
|
19476
|
+
this.attemptStrategy(0, strategies);
|
|
19477
|
+
}
|
|
19478
|
+
else if (document.readyState === 'interactive') {
|
|
19479
|
+
// DOM ready but resources still loading
|
|
19480
|
+
this.attemptStrategy(1, strategies);
|
|
19481
|
+
}
|
|
19482
|
+
else {
|
|
19483
|
+
// DOM still loading
|
|
19484
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
19485
|
+
this.attemptStrategy(0, strategies);
|
|
19486
|
+
}, { once: true });
|
|
19487
|
+
}
|
|
19488
|
+
}
|
|
19489
|
+
/**
|
|
19490
|
+
* Attempt initialization strategy with fallback
|
|
19491
|
+
*/
|
|
19492
|
+
attemptStrategy(index, strategies) {
|
|
19493
|
+
if (index >= strategies.length || this.isInitialized)
|
|
19494
|
+
return;
|
|
19495
|
+
if (this.config.debug) {
|
|
19496
|
+
console.log(`[🔄 AutoTracker] Trying initialization strategy ${index + 1}/${strategies.length}`);
|
|
19497
|
+
}
|
|
19498
|
+
try {
|
|
19499
|
+
const strategy = strategies[index];
|
|
19500
|
+
if (strategy && typeof strategy === 'function') {
|
|
19501
|
+
strategy();
|
|
19502
|
+
// Verify initialization after a short delay
|
|
19503
|
+
setTimeout(() => {
|
|
19504
|
+
if (!this.verifyInitialization()) {
|
|
19505
|
+
if (this.config.debug) {
|
|
19506
|
+
console.log(`[⚠️ AutoTracker] Strategy ${index + 1} failed verification, trying next...`);
|
|
19507
|
+
}
|
|
19508
|
+
this.attemptStrategy(index + 1, strategies);
|
|
19509
|
+
}
|
|
19510
|
+
else {
|
|
19511
|
+
if (this.config.debug) {
|
|
19512
|
+
console.log(`[✅ AutoTracker] Strategy ${index + 1} successful!`);
|
|
19513
|
+
}
|
|
19514
|
+
}
|
|
19515
|
+
}, 50);
|
|
19516
|
+
}
|
|
19517
|
+
else {
|
|
19518
|
+
// Strategy is undefined or not a function, try next
|
|
19519
|
+
this.attemptStrategy(index + 1, strategies);
|
|
19520
|
+
}
|
|
19521
|
+
}
|
|
19522
|
+
catch (error) {
|
|
19523
|
+
if (this.config.debug) {
|
|
19524
|
+
console.error(`[❌ AutoTracker] Strategy ${index + 1} error:`, error);
|
|
19525
|
+
}
|
|
19526
|
+
this.attemptStrategy(index + 1, strategies);
|
|
19527
|
+
}
|
|
19528
|
+
}
|
|
19529
|
+
/**
|
|
19530
|
+
* Immediate initialization
|
|
19531
|
+
*/
|
|
19532
|
+
immediateInitialization() {
|
|
19533
|
+
this.initializeTracking();
|
|
19534
|
+
}
|
|
19535
|
+
/**
|
|
19536
|
+
* Delayed initialization
|
|
19537
|
+
*/
|
|
19538
|
+
delayedInitialization(delay) {
|
|
19539
|
+
setTimeout(() => {
|
|
19540
|
+
this.initializeTracking();
|
|
19541
|
+
}, delay);
|
|
19542
|
+
}
|
|
19543
|
+
/**
|
|
19544
|
+
* React-specific initialization timing
|
|
19545
|
+
*/
|
|
19546
|
+
reactReadyInitialization() {
|
|
19547
|
+
// Wait for React to finish rendering
|
|
19548
|
+
if (typeof window.requestAnimationFrame === 'function') {
|
|
19549
|
+
window.requestAnimationFrame(() => {
|
|
19550
|
+
setTimeout(() => {
|
|
19551
|
+
this.initializeTracking();
|
|
19552
|
+
}, 0);
|
|
19374
19553
|
});
|
|
19375
|
-
|
|
19554
|
+
}
|
|
19555
|
+
else {
|
|
19376
19556
|
setTimeout(() => {
|
|
19377
|
-
|
|
19378
|
-
|
|
19379
|
-
|
|
19380
|
-
|
|
19381
|
-
|
|
19382
|
-
|
|
19383
|
-
|
|
19384
|
-
|
|
19385
|
-
|
|
19386
|
-
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
|
|
19393
|
-
|
|
19394
|
-
|
|
19395
|
-
|
|
19396
|
-
|
|
19557
|
+
this.initializeTracking();
|
|
19558
|
+
}, 16); // ~60fps fallback
|
|
19559
|
+
}
|
|
19560
|
+
}
|
|
19561
|
+
/**
|
|
19562
|
+
* Verify initialization was successful
|
|
19563
|
+
*/
|
|
19564
|
+
verifyInitialization() {
|
|
19565
|
+
const elementsFound = this.getElementCounts();
|
|
19566
|
+
const totalElements = Object.values(elementsFound).reduce((sum, count) => sum + count, 0);
|
|
19567
|
+
const hasActiveHandlers = this.delegationHandlers.size > 0;
|
|
19568
|
+
if (this.config.debug) {
|
|
19569
|
+
console.log('[🔍 AutoTracker] Verification:', {
|
|
19570
|
+
isInitialized: this.isInitialized,
|
|
19571
|
+
elementsFound: totalElements,
|
|
19572
|
+
hasActiveHandlers,
|
|
19573
|
+
handlersActive: Array.from(this.delegationHandlers.keys())
|
|
19574
|
+
});
|
|
19575
|
+
}
|
|
19576
|
+
return this.isInitialized && (totalElements > 0 || hasActiveHandlers);
|
|
19577
|
+
}
|
|
19578
|
+
initializeTracking() {
|
|
19579
|
+
if (this.config.debug) {
|
|
19580
|
+
console.log("[Zaplier AutoTracker] Initializing tracking...");
|
|
19397
19581
|
}
|
|
19398
19582
|
// Observer para novos elementos no DOM
|
|
19399
19583
|
this.observeDOM();
|
|
@@ -19403,42 +19587,422 @@ class AutoTracker {
|
|
|
19403
19587
|
if (this.config.trackViews) {
|
|
19404
19588
|
this.setupViewTracking();
|
|
19405
19589
|
}
|
|
19406
|
-
// Setup
|
|
19590
|
+
// Setup event delegation (modern approach)
|
|
19591
|
+
this.setupEventDelegation();
|
|
19592
|
+
// Debug: Log elementos encontrados após inicialização
|
|
19593
|
+
if (this.config.debug) {
|
|
19594
|
+
this.logFoundElements();
|
|
19595
|
+
// Também agendar uma verificação após delay para elementos React
|
|
19596
|
+
setTimeout(() => {
|
|
19597
|
+
console.log("[Zaplier AutoTracker] Re-checking elements after 500ms...");
|
|
19598
|
+
this.logFoundElements();
|
|
19599
|
+
}, 500);
|
|
19600
|
+
setTimeout(() => {
|
|
19601
|
+
console.log("[Zaplier AutoTracker] Re-checking elements after 2s...");
|
|
19602
|
+
this.logFoundElements();
|
|
19603
|
+
}, 2000);
|
|
19604
|
+
}
|
|
19605
|
+
}
|
|
19606
|
+
logFoundElements() {
|
|
19607
|
+
const clickElements = document.querySelectorAll('[data-track-click]');
|
|
19608
|
+
const scrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19609
|
+
const viewElements = document.querySelectorAll('[data-track-view]');
|
|
19610
|
+
const hoverElements = document.querySelectorAll('[data-track-hover]');
|
|
19611
|
+
const formElements = document.querySelectorAll('[data-track-form]');
|
|
19612
|
+
console.log("[Zaplier AutoTracker] Elementos encontrados:", {
|
|
19613
|
+
clickElements: clickElements.length,
|
|
19614
|
+
scrollElements: scrollElements.length,
|
|
19615
|
+
viewElements: viewElements.length,
|
|
19616
|
+
hoverElements: hoverElements.length,
|
|
19617
|
+
formElements: formElements.length,
|
|
19618
|
+
totalElements: clickElements.length + scrollElements.length + viewElements.length + hoverElements.length + formElements.length
|
|
19619
|
+
});
|
|
19620
|
+
if (scrollElements.length > 0) {
|
|
19621
|
+
console.log("[Zaplier AutoTracker] Elementos de scroll:", Array.from(scrollElements).map(el => ({
|
|
19622
|
+
tagName: el.tagName,
|
|
19623
|
+
trackEvent: el.getAttribute('data-track-scroll'),
|
|
19624
|
+
threshold: el.getAttribute('data-scroll-threshold') || '0.5',
|
|
19625
|
+
id: el.id || 'no-id',
|
|
19626
|
+
classes: el.className || 'no-classes'
|
|
19627
|
+
})));
|
|
19628
|
+
}
|
|
19629
|
+
}
|
|
19630
|
+
/**
|
|
19631
|
+
* Setup Event Delegation (Industry Best Practice)
|
|
19632
|
+
* Uses single document-level listeners instead of individual element listeners
|
|
19633
|
+
*/
|
|
19634
|
+
setupEventDelegation() {
|
|
19635
|
+
if (this.config.debug) {
|
|
19636
|
+
console.log("[🚀 AutoTracker] Setting up enhanced event delegation...");
|
|
19637
|
+
}
|
|
19638
|
+
// Determine optimal delegation target based on React setup
|
|
19639
|
+
const delegationTarget = this.getOptimalDelegationTarget();
|
|
19640
|
+
if (this.config.debug) {
|
|
19641
|
+
console.log("[🎯 AutoTracker] Using delegation target:", delegationTarget);
|
|
19642
|
+
}
|
|
19643
|
+
// Click delegation with React compatibility
|
|
19407
19644
|
if (this.config.trackClicks) {
|
|
19408
|
-
|
|
19645
|
+
const clickHandler = this.createReactCompatibleClickHandler();
|
|
19646
|
+
this.delegationHandlers.set('click', clickHandler);
|
|
19647
|
+
delegationTarget.addEventListener('click', clickHandler, this.getEventOptions('click'));
|
|
19409
19648
|
}
|
|
19649
|
+
// Scroll delegation with enhanced detection
|
|
19410
19650
|
if (this.config.trackScrolls) {
|
|
19411
|
-
|
|
19651
|
+
const scrollHandler = this.createEnhancedScrollHandler();
|
|
19652
|
+
this.delegationHandlers.set('scroll', scrollHandler);
|
|
19653
|
+
document.addEventListener('scroll', scrollHandler, this.getEventOptions('scroll'));
|
|
19654
|
+
}
|
|
19655
|
+
// Setup debounced mutation observer for dynamic content
|
|
19656
|
+
this.setupIntelligentMutationObserver();
|
|
19657
|
+
this.isInitialized = true;
|
|
19658
|
+
if (this.config.debug) {
|
|
19659
|
+
console.log("[✅ AutoTracker] Event delegation setup complete");
|
|
19412
19660
|
}
|
|
19413
19661
|
}
|
|
19414
19662
|
/**
|
|
19415
|
-
*
|
|
19663
|
+
* Get optimal delegation target based on React setup
|
|
19416
19664
|
*/
|
|
19417
|
-
|
|
19418
|
-
document
|
|
19419
|
-
document.
|
|
19420
|
-
|
|
19421
|
-
|
|
19665
|
+
getOptimalDelegationTarget() {
|
|
19666
|
+
// For React 17+, prefer root container over document
|
|
19667
|
+
const reactRoot = document.querySelector('#root') ||
|
|
19668
|
+
document.querySelector('#__next') ||
|
|
19669
|
+
document.querySelector('[data-reactroot]');
|
|
19670
|
+
if (reactRoot && this.diagnostics.environment?.reactDetected) {
|
|
19671
|
+
if (this.config.debug) {
|
|
19672
|
+
console.log("[⚛️ AutoTracker] Using React root for delegation:", reactRoot);
|
|
19673
|
+
}
|
|
19674
|
+
return reactRoot;
|
|
19422
19675
|
}
|
|
19423
|
-
|
|
19676
|
+
return document;
|
|
19424
19677
|
}
|
|
19425
19678
|
/**
|
|
19426
|
-
*
|
|
19679
|
+
* Get optimized event options for different browsers
|
|
19427
19680
|
*/
|
|
19428
|
-
|
|
19429
|
-
|
|
19430
|
-
|
|
19431
|
-
|
|
19681
|
+
getEventOptions(eventType) {
|
|
19682
|
+
this.diagnostics.environment?.isMobile;
|
|
19683
|
+
const isSafari = this.diagnostics.environment?.isSafari;
|
|
19684
|
+
let options = {};
|
|
19685
|
+
switch (eventType) {
|
|
19686
|
+
case 'click':
|
|
19687
|
+
// Safari iOS requires non-passive click events for proper delegation
|
|
19688
|
+
options = {
|
|
19689
|
+
passive: !isSafari,
|
|
19690
|
+
capture: false
|
|
19691
|
+
};
|
|
19692
|
+
break;
|
|
19693
|
+
case 'scroll':
|
|
19694
|
+
options = {
|
|
19695
|
+
passive: true,
|
|
19696
|
+
capture: false
|
|
19697
|
+
};
|
|
19698
|
+
break;
|
|
19699
|
+
default:
|
|
19700
|
+
options = { passive: true };
|
|
19701
|
+
}
|
|
19702
|
+
if (this.config.debug) {
|
|
19703
|
+
console.log(`[⚙️ AutoTracker] Event options for ${eventType}:`, options);
|
|
19704
|
+
}
|
|
19705
|
+
return options;
|
|
19706
|
+
}
|
|
19707
|
+
/**
|
|
19708
|
+
* Create React-compatible click handler
|
|
19709
|
+
*/
|
|
19710
|
+
createReactCompatibleClickHandler() {
|
|
19711
|
+
return (event) => {
|
|
19712
|
+
try {
|
|
19713
|
+
if (!this.config.trackClicks)
|
|
19714
|
+
return;
|
|
19715
|
+
// Enhanced target detection for nested React components
|
|
19716
|
+
const target = event.target;
|
|
19717
|
+
if (!target)
|
|
19718
|
+
return;
|
|
19719
|
+
// Multiple strategies to find tracking element
|
|
19720
|
+
let trackingElement = null;
|
|
19721
|
+
// Strategy 1: Direct closest (most common)
|
|
19722
|
+
trackingElement = target.closest('[data-track-click]');
|
|
19723
|
+
// Strategy 2: Check if target itself has the attribute (React edge case)
|
|
19724
|
+
if (!trackingElement && target.hasAttribute && target.hasAttribute('data-track-click')) {
|
|
19725
|
+
trackingElement = target;
|
|
19726
|
+
}
|
|
19727
|
+
// Strategy 3: Walk up DOM tree manually (React portal handling)
|
|
19728
|
+
if (!trackingElement) {
|
|
19729
|
+
trackingElement = this.findTrackingElementManually(target, 'data-track-click');
|
|
19730
|
+
}
|
|
19731
|
+
if (!trackingElement) {
|
|
19732
|
+
if (this.config.debug) {
|
|
19733
|
+
console.log('[🔍 AutoTracker] No tracking element found for click:', {
|
|
19734
|
+
target: target.tagName,
|
|
19735
|
+
hasClosest: typeof target.closest === 'function',
|
|
19736
|
+
hasAttribute: typeof target.hasAttribute === 'function'
|
|
19737
|
+
});
|
|
19738
|
+
}
|
|
19739
|
+
return;
|
|
19740
|
+
}
|
|
19741
|
+
const eventName = trackingElement.getAttribute('data-track-click');
|
|
19742
|
+
if (!eventName)
|
|
19743
|
+
return;
|
|
19744
|
+
const metadata = this.extractMetadata(trackingElement);
|
|
19745
|
+
this.trackEvent(eventName, {
|
|
19746
|
+
type: 'click',
|
|
19747
|
+
element: trackingElement.tagName.toLowerCase(),
|
|
19748
|
+
reactCompatible: true,
|
|
19749
|
+
...metadata,
|
|
19750
|
+
});
|
|
19751
|
+
if (this.config.debug) {
|
|
19752
|
+
console.log(`[🎯 AutoTracker] Click tracked (React-compatible): ${eventName}`, {
|
|
19753
|
+
element: trackingElement.tagName.toLowerCase(),
|
|
19754
|
+
strategy: 'enhanced_delegation',
|
|
19755
|
+
...metadata
|
|
19756
|
+
});
|
|
19757
|
+
}
|
|
19758
|
+
}
|
|
19759
|
+
catch (error) {
|
|
19760
|
+
if (this.config.debug) {
|
|
19761
|
+
console.error('[❌ AutoTracker] Click handler error:', error);
|
|
19762
|
+
}
|
|
19763
|
+
}
|
|
19764
|
+
};
|
|
19765
|
+
}
|
|
19766
|
+
/**
|
|
19767
|
+
* Manually walk up DOM tree to find tracking element
|
|
19768
|
+
*/
|
|
19769
|
+
findTrackingElementManually(element, attribute, maxDepth = 10) {
|
|
19770
|
+
let current = element;
|
|
19771
|
+
let depth = 0;
|
|
19772
|
+
while (current && current !== document.documentElement && depth < maxDepth) {
|
|
19773
|
+
if (current.hasAttribute && current.hasAttribute(attribute)) {
|
|
19774
|
+
return current;
|
|
19775
|
+
}
|
|
19776
|
+
current = current.parentElement;
|
|
19777
|
+
depth++;
|
|
19778
|
+
}
|
|
19779
|
+
return null;
|
|
19780
|
+
}
|
|
19781
|
+
/**
|
|
19782
|
+
* Create enhanced scroll handler with better performance
|
|
19783
|
+
*/
|
|
19784
|
+
createEnhancedScrollHandler() {
|
|
19785
|
+
return () => {
|
|
19786
|
+
try {
|
|
19787
|
+
if (!this.config.trackScrolls)
|
|
19788
|
+
return;
|
|
19789
|
+
// Adaptive throttling based on scroll frequency
|
|
19790
|
+
const now = Date.now();
|
|
19791
|
+
const timeDelta = now - this.scrollThrottle;
|
|
19792
|
+
const throttleDelay = this.diagnostics.environment?.isMobile ? 150 : 100;
|
|
19793
|
+
if (timeDelta < throttleDelay)
|
|
19794
|
+
return;
|
|
19795
|
+
this.scrollThrottle = now;
|
|
19796
|
+
// Enhanced element finding with caching
|
|
19797
|
+
const scrollElements = this.getCachedScrollElements();
|
|
19798
|
+
if (this.config.debug && scrollElements.length > 0) {
|
|
19799
|
+
console.log(`[📜 AutoTracker] Processing ${scrollElements.length} scroll elements`, {
|
|
19800
|
+
throttleDelay,
|
|
19801
|
+
timeDelta,
|
|
19802
|
+
scrollY: window.scrollY
|
|
19803
|
+
});
|
|
19804
|
+
}
|
|
19805
|
+
// Process elements with enhanced visibility detection
|
|
19806
|
+
scrollElements.forEach((element) => {
|
|
19807
|
+
this.processScrollElementEnhanced(element);
|
|
19808
|
+
});
|
|
19809
|
+
}
|
|
19810
|
+
catch (error) {
|
|
19811
|
+
if (this.config.debug) {
|
|
19812
|
+
console.error('[❌ AutoTracker] Scroll handler error:', error);
|
|
19813
|
+
}
|
|
19814
|
+
}
|
|
19815
|
+
};
|
|
19816
|
+
}
|
|
19817
|
+
getCachedScrollElements() {
|
|
19818
|
+
const now = Date.now();
|
|
19819
|
+
const cacheExpiry = 5000; // 5 seconds
|
|
19820
|
+
if (!this.cachedScrollElements || (now - this.lastScrollElementsCheck) > cacheExpiry) {
|
|
19821
|
+
this.cachedScrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19822
|
+
this.lastScrollElementsCheck = now;
|
|
19823
|
+
if (this.config.debug) {
|
|
19824
|
+
console.log(`[🔄 AutoTracker] Refreshed scroll elements cache: ${this.cachedScrollElements.length} elements`);
|
|
19825
|
+
}
|
|
19826
|
+
}
|
|
19827
|
+
return this.cachedScrollElements;
|
|
19828
|
+
}
|
|
19829
|
+
/**
|
|
19830
|
+
* Process scroll element with enhanced detection
|
|
19831
|
+
*/
|
|
19832
|
+
processScrollElementEnhanced(element) {
|
|
19833
|
+
try {
|
|
19834
|
+
const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
|
|
19835
|
+
if (hasTriggered)
|
|
19836
|
+
return;
|
|
19837
|
+
const threshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.5');
|
|
19838
|
+
// Enhanced visibility calculation
|
|
19839
|
+
const rect = element.getBoundingClientRect();
|
|
19840
|
+
const elementHeight = rect.height;
|
|
19841
|
+
const windowHeight = window.innerHeight;
|
|
19842
|
+
// Handle edge cases
|
|
19843
|
+
if (elementHeight <= 0)
|
|
19844
|
+
return;
|
|
19845
|
+
const visibleTop = Math.max(rect.top, 0);
|
|
19846
|
+
const visibleBottom = Math.min(rect.bottom, windowHeight);
|
|
19847
|
+
const visibleHeight = Math.max(0, visibleBottom - visibleTop);
|
|
19848
|
+
const visibilityRatio = visibleHeight / elementHeight;
|
|
19849
|
+
if (this.config.debug) {
|
|
19850
|
+
console.log(`[📊 AutoTracker] Enhanced scroll check:`, {
|
|
19851
|
+
elementId: element.id || element.className || 'no-id',
|
|
19852
|
+
rect: {
|
|
19853
|
+
top: Math.round(rect.top),
|
|
19854
|
+
bottom: Math.round(rect.bottom),
|
|
19855
|
+
height: Math.round(elementHeight)
|
|
19856
|
+
},
|
|
19857
|
+
visibility: {
|
|
19858
|
+
ratio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19859
|
+
threshold,
|
|
19860
|
+
triggered: hasTriggered
|
|
19861
|
+
},
|
|
19862
|
+
scroll: window.scrollY
|
|
19863
|
+
});
|
|
19864
|
+
}
|
|
19865
|
+
if (visibilityRatio >= threshold) {
|
|
19866
|
+
element.setAttribute('data-scroll-triggered', 'true');
|
|
19867
|
+
const eventName = element.getAttribute('data-track-scroll');
|
|
19868
|
+
if (!eventName)
|
|
19869
|
+
return;
|
|
19870
|
+
const metadata = this.extractMetadata(element);
|
|
19871
|
+
this.trackEvent(eventName, {
|
|
19872
|
+
type: 'scroll',
|
|
19873
|
+
element: element.tagName.toLowerCase(),
|
|
19874
|
+
threshold,
|
|
19875
|
+
scrollDepth: window.scrollY,
|
|
19876
|
+
visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19877
|
+
enhanced: true,
|
|
19878
|
+
...metadata,
|
|
19879
|
+
});
|
|
19880
|
+
if (this.config.debug) {
|
|
19881
|
+
console.log(`[🎯 AutoTracker] Scroll tracked (enhanced): ${eventName}`, {
|
|
19882
|
+
threshold,
|
|
19883
|
+
visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19884
|
+
scrollDepth: window.scrollY,
|
|
19885
|
+
...metadata
|
|
19886
|
+
});
|
|
19887
|
+
}
|
|
19888
|
+
}
|
|
19889
|
+
}
|
|
19890
|
+
catch (error) {
|
|
19891
|
+
if (this.config.debug) {
|
|
19892
|
+
console.error('[❌ AutoTracker] Scroll element processing error:', error);
|
|
19893
|
+
}
|
|
19894
|
+
}
|
|
19895
|
+
}
|
|
19896
|
+
/**
|
|
19897
|
+
* Legacy method for compatibility
|
|
19898
|
+
*/
|
|
19899
|
+
processScrollElement(element) {
|
|
19900
|
+
this.processScrollElementEnhanced(element);
|
|
19901
|
+
}
|
|
19902
|
+
/**
|
|
19903
|
+
* Setup intelligent mutation observer (debounced for performance)
|
|
19904
|
+
*/
|
|
19905
|
+
setupIntelligentMutationObserver() {
|
|
19906
|
+
if (this.mutationObserver)
|
|
19907
|
+
return; // Already setup
|
|
19908
|
+
const debouncedCallback = this.debounce((mutations) => {
|
|
19909
|
+
let hasRelevantChanges = false;
|
|
19910
|
+
mutations.forEach(mutation => {
|
|
19911
|
+
mutation.addedNodes.forEach(node => {
|
|
19432
19912
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
19433
|
-
|
|
19913
|
+
const element = node;
|
|
19914
|
+
if (this.hasTrackingAttributes(element) || this.hasTrackingDescendants(element)) {
|
|
19915
|
+
hasRelevantChanges = true;
|
|
19916
|
+
if (this.config.debug) {
|
|
19917
|
+
console.log('[AutoTracker] New trackable element detected via mutation observer:', element);
|
|
19918
|
+
}
|
|
19919
|
+
}
|
|
19434
19920
|
}
|
|
19435
19921
|
});
|
|
19436
19922
|
});
|
|
19437
|
-
|
|
19438
|
-
|
|
19923
|
+
if (hasRelevantChanges) {
|
|
19924
|
+
if (this.config.debug) {
|
|
19925
|
+
console.log('[AutoTracker] Processing new elements from mutations...');
|
|
19926
|
+
}
|
|
19927
|
+
// Process elements for view tracking (only thing that needs setup)
|
|
19928
|
+
this.processExistingElements();
|
|
19929
|
+
}
|
|
19930
|
+
}, 150);
|
|
19931
|
+
this.mutationObserver = new MutationObserver(debouncedCallback);
|
|
19932
|
+
this.mutationObserver.observe(document.body, {
|
|
19439
19933
|
childList: true,
|
|
19440
19934
|
subtree: true,
|
|
19441
19935
|
});
|
|
19936
|
+
if (this.config.debug) {
|
|
19937
|
+
console.log('[AutoTracker] Intelligent mutation observer setup complete');
|
|
19938
|
+
}
|
|
19939
|
+
}
|
|
19940
|
+
/**
|
|
19941
|
+
* Check if element has tracking attributes
|
|
19942
|
+
*/
|
|
19943
|
+
hasTrackingAttributes(element) {
|
|
19944
|
+
return element.hasAttribute && (element.hasAttribute('data-track-click') ||
|
|
19945
|
+
element.hasAttribute('data-track-scroll') ||
|
|
19946
|
+
element.hasAttribute('data-track-view') ||
|
|
19947
|
+
element.hasAttribute('data-track-hover') ||
|
|
19948
|
+
element.hasAttribute('data-track-form'));
|
|
19949
|
+
}
|
|
19950
|
+
/**
|
|
19951
|
+
* Check if element has tracking descendants
|
|
19952
|
+
*/
|
|
19953
|
+
hasTrackingDescendants(element) {
|
|
19954
|
+
if (!element.querySelector)
|
|
19955
|
+
return false;
|
|
19956
|
+
return !!(element.querySelector('[data-track-click]') ||
|
|
19957
|
+
element.querySelector('[data-track-scroll]') ||
|
|
19958
|
+
element.querySelector('[data-track-view]') ||
|
|
19959
|
+
element.querySelector('[data-track-hover]') ||
|
|
19960
|
+
element.querySelector('[data-track-form]'));
|
|
19961
|
+
}
|
|
19962
|
+
/**
|
|
19963
|
+
* Utility: Debounce function for performance optimization
|
|
19964
|
+
*/
|
|
19965
|
+
debounce(func, wait) {
|
|
19966
|
+
let timeout;
|
|
19967
|
+
return (...args) => {
|
|
19968
|
+
clearTimeout(timeout);
|
|
19969
|
+
timeout = setTimeout(() => func.apply(this, args), wait);
|
|
19970
|
+
};
|
|
19971
|
+
}
|
|
19972
|
+
/**
|
|
19973
|
+
* Parar auto tracking (with proper cleanup)
|
|
19974
|
+
*/
|
|
19975
|
+
stop() {
|
|
19976
|
+
if (this.config.debug) {
|
|
19977
|
+
console.log('[AutoTracker] Stopping auto tracking and cleaning up...');
|
|
19978
|
+
}
|
|
19979
|
+
// Remove delegation handlers
|
|
19980
|
+
this.delegationHandlers.forEach((handler, eventType) => {
|
|
19981
|
+
document.removeEventListener(eventType, handler);
|
|
19982
|
+
});
|
|
19983
|
+
this.delegationHandlers.clear();
|
|
19984
|
+
// Disconnect observers
|
|
19985
|
+
if (this.intersectionObserver) {
|
|
19986
|
+
this.intersectionObserver.disconnect();
|
|
19987
|
+
this.intersectionObserver = undefined;
|
|
19988
|
+
}
|
|
19989
|
+
if (this.mutationObserver) {
|
|
19990
|
+
this.mutationObserver.disconnect();
|
|
19991
|
+
this.mutationObserver = undefined;
|
|
19992
|
+
}
|
|
19993
|
+
// Clear caches
|
|
19994
|
+
this.observedElements.clear();
|
|
19995
|
+
this.isInitialized = false;
|
|
19996
|
+
}
|
|
19997
|
+
/**
|
|
19998
|
+
* Legacy method - now handled by intelligent mutation observer
|
|
19999
|
+
* @deprecated Use setupIntelligentMutationObserver instead
|
|
20000
|
+
*/
|
|
20001
|
+
observeDOM() {
|
|
20002
|
+
// This is now handled by setupIntelligentMutationObserver in setupEventDelegation
|
|
20003
|
+
if (this.config.debug) {
|
|
20004
|
+
console.log('[AutoTracker] observeDOM() is deprecated - using intelligent mutation observer');
|
|
20005
|
+
}
|
|
19442
20006
|
}
|
|
19443
20007
|
/**
|
|
19444
20008
|
* Processar elementos já existentes no DOM
|
|
@@ -19625,23 +20189,194 @@ class AutoTracker {
|
|
|
19625
20189
|
/**
|
|
19626
20190
|
* Enviar evento para o SDK
|
|
19627
20191
|
*/
|
|
20192
|
+
/**
|
|
20193
|
+
* Enhanced event tracking with comprehensive debugging
|
|
20194
|
+
*/
|
|
19628
20195
|
trackEvent(eventName, metadata) {
|
|
19629
|
-
|
|
20196
|
+
const trackingStart = performance.now();
|
|
20197
|
+
if (this.config.debug) {
|
|
20198
|
+
console.log("[🚀 AutoTracker] Enhanced trackEvent called:", {
|
|
20199
|
+
eventName,
|
|
20200
|
+
metadata,
|
|
20201
|
+
timestamp: new Date().toISOString()
|
|
20202
|
+
});
|
|
20203
|
+
}
|
|
20204
|
+
// Comprehensive validation
|
|
20205
|
+
const validation = this.validateTrackingCall(eventName, metadata);
|
|
20206
|
+
if (!validation.isValid) {
|
|
20207
|
+
if (this.config.debug) {
|
|
20208
|
+
console.error("[❌ AutoTracker] Validation failed:", validation.errors);
|
|
20209
|
+
}
|
|
19630
20210
|
return;
|
|
20211
|
+
}
|
|
19631
20212
|
try {
|
|
19632
|
-
|
|
20213
|
+
const eventData = {
|
|
20214
|
+
// Core tracking data
|
|
19633
20215
|
autoTracked: true,
|
|
20216
|
+
enhanced: true,
|
|
19634
20217
|
timestamp: Date.now(),
|
|
19635
20218
|
url: window.location.href,
|
|
20219
|
+
userAgent: navigator.userAgent,
|
|
20220
|
+
// Performance data
|
|
20221
|
+
trackingLatency: Math.round((performance.now() - trackingStart) * 100) / 100,
|
|
20222
|
+
// Environment data
|
|
20223
|
+
isReactApp: this.diagnostics.environment?.reactDetected,
|
|
20224
|
+
isMobile: this.diagnostics.environment?.isMobile,
|
|
20225
|
+
// Event metadata
|
|
19636
20226
|
...metadata,
|
|
19637
|
-
}
|
|
20227
|
+
};
|
|
20228
|
+
if (this.config.debug) {
|
|
20229
|
+
console.log("[📡 AutoTracker] Sending enhanced event:", { eventName, eventData });
|
|
20230
|
+
}
|
|
20231
|
+
const result = this.sdkInstance.trackCustomEvent(eventName, eventData);
|
|
20232
|
+
if (this.config.debug) {
|
|
20233
|
+
const trackingEnd = performance.now();
|
|
20234
|
+
console.log("[✅ AutoTracker] Event sent successfully:", {
|
|
20235
|
+
eventName,
|
|
20236
|
+
result,
|
|
20237
|
+
totalLatency: Math.round((trackingEnd - trackingStart) * 100) / 100 + 'ms'
|
|
20238
|
+
});
|
|
20239
|
+
}
|
|
19638
20240
|
}
|
|
19639
20241
|
catch (error) {
|
|
19640
20242
|
if (this.config.debug) {
|
|
19641
|
-
console.error("[AutoTracker]
|
|
20243
|
+
console.error("[💥 AutoTracker] Critical tracking error:", {
|
|
20244
|
+
eventName,
|
|
20245
|
+
error: error instanceof Error ? error.message : error,
|
|
20246
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
20247
|
+
metadata
|
|
20248
|
+
});
|
|
19642
20249
|
}
|
|
19643
20250
|
}
|
|
19644
20251
|
}
|
|
20252
|
+
/**
|
|
20253
|
+
* Validate tracking call before sending
|
|
20254
|
+
*/
|
|
20255
|
+
validateTrackingCall(eventName, metadata) {
|
|
20256
|
+
const errors = [];
|
|
20257
|
+
if (!eventName || typeof eventName !== 'string') {
|
|
20258
|
+
errors.push('Event name is required and must be a string');
|
|
20259
|
+
}
|
|
20260
|
+
if (!this.sdkInstance) {
|
|
20261
|
+
errors.push('SDK instance is null or undefined');
|
|
20262
|
+
}
|
|
20263
|
+
if (this.sdkInstance && typeof this.sdkInstance.trackCustomEvent !== 'function') {
|
|
20264
|
+
errors.push(`trackCustomEvent is not a function: ${typeof this.sdkInstance.trackCustomEvent}`);
|
|
20265
|
+
}
|
|
20266
|
+
if (!window || typeof window !== 'object') {
|
|
20267
|
+
errors.push('Window object is not available');
|
|
20268
|
+
}
|
|
20269
|
+
return {
|
|
20270
|
+
isValid: errors.length === 0,
|
|
20271
|
+
errors
|
|
20272
|
+
};
|
|
20273
|
+
}
|
|
20274
|
+
/**
|
|
20275
|
+
* Modern API: Refresh tracking for dynamic content (React/SPA support)
|
|
20276
|
+
* Industry best practice for SPA route changes
|
|
20277
|
+
*/
|
|
20278
|
+
refreshTracking() {
|
|
20279
|
+
if (!this.isInitialized) {
|
|
20280
|
+
if (this.config.debug) {
|
|
20281
|
+
console.log('[AutoTracker] Not initialized, cannot refresh tracking');
|
|
20282
|
+
}
|
|
20283
|
+
return;
|
|
20284
|
+
}
|
|
20285
|
+
if (this.config.debug) {
|
|
20286
|
+
console.log('[AutoTracker] Refreshing tracking for dynamic content...');
|
|
20287
|
+
}
|
|
20288
|
+
// Re-process elements for view tracking (only thing that needs setup)
|
|
20289
|
+
this.processExistingElements();
|
|
20290
|
+
// Log current state
|
|
20291
|
+
if (this.config.debug) {
|
|
20292
|
+
this.logFoundElements();
|
|
20293
|
+
}
|
|
20294
|
+
}
|
|
20295
|
+
/**
|
|
20296
|
+
* Legacy method - use refreshTracking() instead
|
|
20297
|
+
* @deprecated Use refreshTracking() for better performance
|
|
20298
|
+
*/
|
|
20299
|
+
rescan() {
|
|
20300
|
+
this.refreshTracking();
|
|
20301
|
+
}
|
|
20302
|
+
/**
|
|
20303
|
+
* Get comprehensive diagnostic information for debugging
|
|
20304
|
+
*/
|
|
20305
|
+
getDiagnostics() {
|
|
20306
|
+
return {
|
|
20307
|
+
// Initialization status
|
|
20308
|
+
initialization: {
|
|
20309
|
+
isInitialized: this.isInitialized,
|
|
20310
|
+
attempts: this.initializationAttempts,
|
|
20311
|
+
maxAttempts: this.maxInitializationAttempts,
|
|
20312
|
+
timestamp: new Date().toISOString()
|
|
20313
|
+
},
|
|
20314
|
+
// Event handlers status
|
|
20315
|
+
eventHandlers: {
|
|
20316
|
+
hasClickHandler: this.delegationHandlers.has('click'),
|
|
20317
|
+
hasScrollHandler: this.delegationHandlers.has('scroll'),
|
|
20318
|
+
activeHandlers: Array.from(this.delegationHandlers.keys()),
|
|
20319
|
+
delegationTarget: this.getOptimalDelegationTarget() === document ? 'document' : 'react-root'
|
|
20320
|
+
},
|
|
20321
|
+
// Observers status
|
|
20322
|
+
observers: {
|
|
20323
|
+
observedElements: this.observedElements.size,
|
|
20324
|
+
hasMutationObserver: !!this.mutationObserver,
|
|
20325
|
+
hasIntersectionObserver: !!this.intersectionObserver,
|
|
20326
|
+
scrollElementsCache: !!this.cachedScrollElements,
|
|
20327
|
+
cacheExpiry: new Date(this.lastScrollElementsCheck + 5000).toISOString()
|
|
20328
|
+
},
|
|
20329
|
+
// Configuration
|
|
20330
|
+
config: this.config,
|
|
20331
|
+
// Current environment diagnostics
|
|
20332
|
+
environment: this.diagnostics.environment || {},
|
|
20333
|
+
// DOM state
|
|
20334
|
+
dom: this.diagnostics.dom || {},
|
|
20335
|
+
// SDK state
|
|
20336
|
+
tracking: this.diagnostics.tracking || {},
|
|
20337
|
+
// Real-time element detection
|
|
20338
|
+
elementsFound: this.getElementCounts(),
|
|
20339
|
+
// Performance metrics
|
|
20340
|
+
performance: {
|
|
20341
|
+
lastScrollThrottle: this.scrollThrottle,
|
|
20342
|
+
cacheLastUpdate: this.lastScrollElementsCheck
|
|
20343
|
+
},
|
|
20344
|
+
// Validation status
|
|
20345
|
+
validation: this.validateTrackingCall('test', {}),
|
|
20346
|
+
// Debug recommendations
|
|
20347
|
+
recommendations: this.generateRecommendations()
|
|
20348
|
+
};
|
|
20349
|
+
}
|
|
20350
|
+
/**
|
|
20351
|
+
* Generate diagnostic recommendations
|
|
20352
|
+
*/
|
|
20353
|
+
generateRecommendations() {
|
|
20354
|
+
const recommendations = [];
|
|
20355
|
+
const elementsFound = this.getElementCounts();
|
|
20356
|
+
const totalElements = Object.values(elementsFound).reduce((sum, count) => sum + count, 0);
|
|
20357
|
+
if (!this.isInitialized) {
|
|
20358
|
+
recommendations.push('AutoTracker is not initialized. Check console for errors.');
|
|
20359
|
+
}
|
|
20360
|
+
if (totalElements === 0) {
|
|
20361
|
+
recommendations.push('No trackable elements found. Ensure data-track-* attributes are present in the DOM.');
|
|
20362
|
+
}
|
|
20363
|
+
if (!this.sdkInstance) {
|
|
20364
|
+
recommendations.push('SDK instance is missing. Ensure the SDK is properly initialized.');
|
|
20365
|
+
}
|
|
20366
|
+
if (this.sdkInstance && typeof this.sdkInstance.trackCustomEvent !== 'function') {
|
|
20367
|
+
recommendations.push('trackCustomEvent method is not available on SDK instance.');
|
|
20368
|
+
}
|
|
20369
|
+
if (!this.diagnostics.environment?.reactDetected && window.location.hostname.includes('localhost')) {
|
|
20370
|
+
recommendations.push('React not detected. If using React, ensure proper setup and try refreshTracking() after route changes.');
|
|
20371
|
+
}
|
|
20372
|
+
if (this.diagnostics.environment?.isMobile && !this.delegationHandlers.has('scroll')) {
|
|
20373
|
+
recommendations.push('Mobile device detected but scroll tracking not active. Check scroll tracking configuration.');
|
|
20374
|
+
}
|
|
20375
|
+
if (this.initializationAttempts > 1) {
|
|
20376
|
+
recommendations.push(`AutoTracker required ${this.initializationAttempts} initialization attempts. Consider adding delay before enabling.`);
|
|
20377
|
+
}
|
|
20378
|
+
return recommendations;
|
|
20379
|
+
}
|
|
19645
20380
|
/**
|
|
19646
20381
|
* Configurar tracking
|
|
19647
20382
|
*/
|
|
@@ -19649,12 +20384,14 @@ class AutoTracker {
|
|
|
19649
20384
|
this.config = { ...this.config, ...config };
|
|
19650
20385
|
}
|
|
19651
20386
|
/**
|
|
19652
|
-
*
|
|
20387
|
+
* Enhanced stats with diagnostic information
|
|
19653
20388
|
*/
|
|
19654
20389
|
getStats() {
|
|
19655
20390
|
return {
|
|
19656
20391
|
observedElements: this.observedElements.size,
|
|
19657
20392
|
config: this.config,
|
|
20393
|
+
isModern: this.isInitialized, // Indicates if using new delegation system
|
|
20394
|
+
diagnostics: this.config.debug ? this.getDiagnostics() : undefined
|
|
19658
20395
|
};
|
|
19659
20396
|
}
|
|
19660
20397
|
}
|
|
@@ -20203,6 +20940,36 @@ class ZaplierSDK {
|
|
|
20203
20940
|
console.log("[Zaplier] Auto tracking configured:", config);
|
|
20204
20941
|
}
|
|
20205
20942
|
},
|
|
20943
|
+
/**
|
|
20944
|
+
* Refresh tracking for dynamic content (React/SPA route changes)
|
|
20945
|
+
* Modern alternative to rescan() - follows GA4/industry best practices
|
|
20946
|
+
*/
|
|
20947
|
+
refreshTracking: () => {
|
|
20948
|
+
if (this.autoTracker) {
|
|
20949
|
+
this.autoTracker.refreshTracking();
|
|
20950
|
+
}
|
|
20951
|
+
if (this.config.debug) {
|
|
20952
|
+
console.log("[Zaplier] Auto tracking refreshed");
|
|
20953
|
+
}
|
|
20954
|
+
},
|
|
20955
|
+
/**
|
|
20956
|
+
* Legacy rescan method - use refreshTracking() instead
|
|
20957
|
+
* @deprecated Use refreshTracking() for better performance
|
|
20958
|
+
*/
|
|
20959
|
+
rescan: () => {
|
|
20960
|
+
if (this.autoTracker) {
|
|
20961
|
+
this.autoTracker.rescan();
|
|
20962
|
+
}
|
|
20963
|
+
if (this.config.debug) {
|
|
20964
|
+
console.log("[Zaplier] Auto tracking rescanned (deprecated - use refreshTracking)");
|
|
20965
|
+
}
|
|
20966
|
+
},
|
|
20967
|
+
/**
|
|
20968
|
+
* Get diagnostic information for debugging
|
|
20969
|
+
*/
|
|
20970
|
+
getDiagnostics: () => {
|
|
20971
|
+
return this.autoTracker ? this.autoTracker.getDiagnostics() : null;
|
|
20972
|
+
},
|
|
20206
20973
|
getStats: () => {
|
|
20207
20974
|
return this.autoTracker ? this.autoTracker.getStats() : null;
|
|
20208
20975
|
},
|