@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/sdk.js
CHANGED
|
@@ -19268,6 +19268,16 @@
|
|
|
19268
19268
|
constructor(sdkInstance, config = {}) {
|
|
19269
19269
|
this.observedElements = new Set();
|
|
19270
19270
|
this.scrollThrottle = 0;
|
|
19271
|
+
this.isInitialized = false;
|
|
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;
|
|
19271
19281
|
this.handleScroll = () => {
|
|
19272
19282
|
if (!this.config.trackScrolls)
|
|
19273
19283
|
return;
|
|
@@ -19365,37 +19375,211 @@
|
|
|
19365
19375
|
start() {
|
|
19366
19376
|
if (!this.config.enabled)
|
|
19367
19377
|
return;
|
|
19378
|
+
this.initializationAttempts++;
|
|
19379
|
+
// Enhanced diagnostics
|
|
19380
|
+
this.runDiagnostics();
|
|
19368
19381
|
if (this.config.debug) {
|
|
19369
|
-
console.log("[
|
|
19370
|
-
|
|
19371
|
-
|
|
19372
|
-
|
|
19373
|
-
|
|
19374
|
-
|
|
19375
|
-
|
|
19382
|
+
console.log("[🔥 AutoTracker ENHANCED] Starting auto tracking", this.diagnostics);
|
|
19383
|
+
}
|
|
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())
|
|
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
|
|
19486
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
19487
|
+
this.attemptStrategy(0, strategies);
|
|
19488
|
+
}, { once: true });
|
|
19489
|
+
}
|
|
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(() => {
|
|
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);
|
|
19376
19555
|
});
|
|
19377
|
-
|
|
19556
|
+
}
|
|
19557
|
+
else {
|
|
19378
19558
|
setTimeout(() => {
|
|
19379
|
-
|
|
19380
|
-
|
|
19381
|
-
|
|
19382
|
-
|
|
19383
|
-
|
|
19384
|
-
|
|
19385
|
-
|
|
19386
|
-
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
|
|
19393
|
-
|
|
19394
|
-
|
|
19395
|
-
|
|
19396
|
-
|
|
19397
|
-
|
|
19398
|
-
|
|
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);
|
|
19579
|
+
}
|
|
19580
|
+
initializeTracking() {
|
|
19581
|
+
if (this.config.debug) {
|
|
19582
|
+
console.log("[Zaplier AutoTracker] Initializing tracking...");
|
|
19399
19583
|
}
|
|
19400
19584
|
// Observer para novos elementos no DOM
|
|
19401
19585
|
this.observeDOM();
|
|
@@ -19405,42 +19589,422 @@
|
|
|
19405
19589
|
if (this.config.trackViews) {
|
|
19406
19590
|
this.setupViewTracking();
|
|
19407
19591
|
}
|
|
19408
|
-
// Setup
|
|
19592
|
+
// Setup event delegation (modern approach)
|
|
19593
|
+
this.setupEventDelegation();
|
|
19594
|
+
// Debug: Log elementos encontrados após inicialização
|
|
19595
|
+
if (this.config.debug) {
|
|
19596
|
+
this.logFoundElements();
|
|
19597
|
+
// Também agendar uma verificação após delay para elementos React
|
|
19598
|
+
setTimeout(() => {
|
|
19599
|
+
console.log("[Zaplier AutoTracker] Re-checking elements after 500ms...");
|
|
19600
|
+
this.logFoundElements();
|
|
19601
|
+
}, 500);
|
|
19602
|
+
setTimeout(() => {
|
|
19603
|
+
console.log("[Zaplier AutoTracker] Re-checking elements after 2s...");
|
|
19604
|
+
this.logFoundElements();
|
|
19605
|
+
}, 2000);
|
|
19606
|
+
}
|
|
19607
|
+
}
|
|
19608
|
+
logFoundElements() {
|
|
19609
|
+
const clickElements = document.querySelectorAll('[data-track-click]');
|
|
19610
|
+
const scrollElements = document.querySelectorAll('[data-track-scroll]');
|
|
19611
|
+
const viewElements = document.querySelectorAll('[data-track-view]');
|
|
19612
|
+
const hoverElements = document.querySelectorAll('[data-track-hover]');
|
|
19613
|
+
const formElements = document.querySelectorAll('[data-track-form]');
|
|
19614
|
+
console.log("[Zaplier AutoTracker] Elementos encontrados:", {
|
|
19615
|
+
clickElements: clickElements.length,
|
|
19616
|
+
scrollElements: scrollElements.length,
|
|
19617
|
+
viewElements: viewElements.length,
|
|
19618
|
+
hoverElements: hoverElements.length,
|
|
19619
|
+
formElements: formElements.length,
|
|
19620
|
+
totalElements: clickElements.length + scrollElements.length + viewElements.length + hoverElements.length + formElements.length
|
|
19621
|
+
});
|
|
19622
|
+
if (scrollElements.length > 0) {
|
|
19623
|
+
console.log("[Zaplier AutoTracker] Elementos de scroll:", Array.from(scrollElements).map(el => ({
|
|
19624
|
+
tagName: el.tagName,
|
|
19625
|
+
trackEvent: el.getAttribute('data-track-scroll'),
|
|
19626
|
+
threshold: el.getAttribute('data-scroll-threshold') || '0.5',
|
|
19627
|
+
id: el.id || 'no-id',
|
|
19628
|
+
classes: el.className || 'no-classes'
|
|
19629
|
+
})));
|
|
19630
|
+
}
|
|
19631
|
+
}
|
|
19632
|
+
/**
|
|
19633
|
+
* Setup Event Delegation (Industry Best Practice)
|
|
19634
|
+
* Uses single document-level listeners instead of individual element listeners
|
|
19635
|
+
*/
|
|
19636
|
+
setupEventDelegation() {
|
|
19637
|
+
if (this.config.debug) {
|
|
19638
|
+
console.log("[🚀 AutoTracker] Setting up enhanced event delegation...");
|
|
19639
|
+
}
|
|
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
|
|
19409
19646
|
if (this.config.trackClicks) {
|
|
19410
|
-
|
|
19647
|
+
const clickHandler = this.createReactCompatibleClickHandler();
|
|
19648
|
+
this.delegationHandlers.set('click', clickHandler);
|
|
19649
|
+
delegationTarget.addEventListener('click', clickHandler, this.getEventOptions('click'));
|
|
19411
19650
|
}
|
|
19651
|
+
// Scroll delegation with enhanced detection
|
|
19412
19652
|
if (this.config.trackScrolls) {
|
|
19413
|
-
|
|
19653
|
+
const scrollHandler = this.createEnhancedScrollHandler();
|
|
19654
|
+
this.delegationHandlers.set('scroll', scrollHandler);
|
|
19655
|
+
document.addEventListener('scroll', scrollHandler, this.getEventOptions('scroll'));
|
|
19656
|
+
}
|
|
19657
|
+
// Setup debounced mutation observer for dynamic content
|
|
19658
|
+
this.setupIntelligentMutationObserver();
|
|
19659
|
+
this.isInitialized = true;
|
|
19660
|
+
if (this.config.debug) {
|
|
19661
|
+
console.log("[✅ AutoTracker] Event delegation setup complete");
|
|
19414
19662
|
}
|
|
19415
19663
|
}
|
|
19416
19664
|
/**
|
|
19417
|
-
*
|
|
19665
|
+
* Get optimal delegation target based on React setup
|
|
19418
19666
|
*/
|
|
19419
|
-
|
|
19420
|
-
document
|
|
19421
|
-
document.
|
|
19422
|
-
|
|
19423
|
-
|
|
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) {
|
|
19673
|
+
if (this.config.debug) {
|
|
19674
|
+
console.log("[⚛️ AutoTracker] Using React root for delegation:", reactRoot);
|
|
19675
|
+
}
|
|
19676
|
+
return reactRoot;
|
|
19424
19677
|
}
|
|
19425
|
-
|
|
19678
|
+
return document;
|
|
19426
19679
|
}
|
|
19427
19680
|
/**
|
|
19428
|
-
*
|
|
19681
|
+
* Get optimized event options for different browsers
|
|
19429
19682
|
*/
|
|
19430
|
-
|
|
19431
|
-
|
|
19432
|
-
|
|
19433
|
-
|
|
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',
|
|
19749
|
+
element: trackingElement.tagName.toLowerCase(),
|
|
19750
|
+
reactCompatible: true,
|
|
19751
|
+
...metadata,
|
|
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
|
+
}
|
|
19765
|
+
}
|
|
19766
|
+
};
|
|
19767
|
+
}
|
|
19768
|
+
/**
|
|
19769
|
+
* Manually walk up DOM tree to find tracking element
|
|
19770
|
+
*/
|
|
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() {
|
|
19787
|
+
return () => {
|
|
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
|
+
}
|
|
19816
|
+
}
|
|
19817
|
+
};
|
|
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
|
+
}
|
|
19831
|
+
/**
|
|
19832
|
+
* Process scroll element with enhanced detection
|
|
19833
|
+
*/
|
|
19834
|
+
processScrollElementEnhanced(element) {
|
|
19835
|
+
try {
|
|
19836
|
+
const hasTriggered = element.getAttribute('data-scroll-triggered') === 'true';
|
|
19837
|
+
if (hasTriggered)
|
|
19838
|
+
return;
|
|
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;
|
|
19851
|
+
if (this.config.debug) {
|
|
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(),
|
|
19876
|
+
threshold,
|
|
19877
|
+
scrollDepth: window.scrollY,
|
|
19878
|
+
visibilityRatio: Math.round(visibilityRatio * 1000) / 1000,
|
|
19879
|
+
enhanced: true,
|
|
19880
|
+
...metadata,
|
|
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
|
+
}
|
|
19890
|
+
}
|
|
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);
|
|
19903
|
+
}
|
|
19904
|
+
/**
|
|
19905
|
+
* Setup intelligent mutation observer (debounced for performance)
|
|
19906
|
+
*/
|
|
19907
|
+
setupIntelligentMutationObserver() {
|
|
19908
|
+
if (this.mutationObserver)
|
|
19909
|
+
return; // Already setup
|
|
19910
|
+
const debouncedCallback = this.debounce((mutations) => {
|
|
19911
|
+
let hasRelevantChanges = false;
|
|
19912
|
+
mutations.forEach(mutation => {
|
|
19913
|
+
mutation.addedNodes.forEach(node => {
|
|
19434
19914
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
19435
|
-
|
|
19915
|
+
const element = node;
|
|
19916
|
+
if (this.hasTrackingAttributes(element) || this.hasTrackingDescendants(element)) {
|
|
19917
|
+
hasRelevantChanges = true;
|
|
19918
|
+
if (this.config.debug) {
|
|
19919
|
+
console.log('[AutoTracker] New trackable element detected via mutation observer:', element);
|
|
19920
|
+
}
|
|
19921
|
+
}
|
|
19436
19922
|
}
|
|
19437
19923
|
});
|
|
19438
19924
|
});
|
|
19439
|
-
|
|
19440
|
-
|
|
19925
|
+
if (hasRelevantChanges) {
|
|
19926
|
+
if (this.config.debug) {
|
|
19927
|
+
console.log('[AutoTracker] Processing new elements from mutations...');
|
|
19928
|
+
}
|
|
19929
|
+
// Process elements for view tracking (only thing that needs setup)
|
|
19930
|
+
this.processExistingElements();
|
|
19931
|
+
}
|
|
19932
|
+
}, 150);
|
|
19933
|
+
this.mutationObserver = new MutationObserver(debouncedCallback);
|
|
19934
|
+
this.mutationObserver.observe(document.body, {
|
|
19441
19935
|
childList: true,
|
|
19442
19936
|
subtree: true,
|
|
19443
19937
|
});
|
|
19938
|
+
if (this.config.debug) {
|
|
19939
|
+
console.log('[AutoTracker] Intelligent mutation observer setup complete');
|
|
19940
|
+
}
|
|
19941
|
+
}
|
|
19942
|
+
/**
|
|
19943
|
+
* Check if element has tracking attributes
|
|
19944
|
+
*/
|
|
19945
|
+
hasTrackingAttributes(element) {
|
|
19946
|
+
return element.hasAttribute && (element.hasAttribute('data-track-click') ||
|
|
19947
|
+
element.hasAttribute('data-track-scroll') ||
|
|
19948
|
+
element.hasAttribute('data-track-view') ||
|
|
19949
|
+
element.hasAttribute('data-track-hover') ||
|
|
19950
|
+
element.hasAttribute('data-track-form'));
|
|
19951
|
+
}
|
|
19952
|
+
/**
|
|
19953
|
+
* Check if element has tracking descendants
|
|
19954
|
+
*/
|
|
19955
|
+
hasTrackingDescendants(element) {
|
|
19956
|
+
if (!element.querySelector)
|
|
19957
|
+
return false;
|
|
19958
|
+
return !!(element.querySelector('[data-track-click]') ||
|
|
19959
|
+
element.querySelector('[data-track-scroll]') ||
|
|
19960
|
+
element.querySelector('[data-track-view]') ||
|
|
19961
|
+
element.querySelector('[data-track-hover]') ||
|
|
19962
|
+
element.querySelector('[data-track-form]'));
|
|
19963
|
+
}
|
|
19964
|
+
/**
|
|
19965
|
+
* Utility: Debounce function for performance optimization
|
|
19966
|
+
*/
|
|
19967
|
+
debounce(func, wait) {
|
|
19968
|
+
let timeout;
|
|
19969
|
+
return (...args) => {
|
|
19970
|
+
clearTimeout(timeout);
|
|
19971
|
+
timeout = setTimeout(() => func.apply(this, args), wait);
|
|
19972
|
+
};
|
|
19973
|
+
}
|
|
19974
|
+
/**
|
|
19975
|
+
* Parar auto tracking (with proper cleanup)
|
|
19976
|
+
*/
|
|
19977
|
+
stop() {
|
|
19978
|
+
if (this.config.debug) {
|
|
19979
|
+
console.log('[AutoTracker] Stopping auto tracking and cleaning up...');
|
|
19980
|
+
}
|
|
19981
|
+
// Remove delegation handlers
|
|
19982
|
+
this.delegationHandlers.forEach((handler, eventType) => {
|
|
19983
|
+
document.removeEventListener(eventType, handler);
|
|
19984
|
+
});
|
|
19985
|
+
this.delegationHandlers.clear();
|
|
19986
|
+
// Disconnect observers
|
|
19987
|
+
if (this.intersectionObserver) {
|
|
19988
|
+
this.intersectionObserver.disconnect();
|
|
19989
|
+
this.intersectionObserver = undefined;
|
|
19990
|
+
}
|
|
19991
|
+
if (this.mutationObserver) {
|
|
19992
|
+
this.mutationObserver.disconnect();
|
|
19993
|
+
this.mutationObserver = undefined;
|
|
19994
|
+
}
|
|
19995
|
+
// Clear caches
|
|
19996
|
+
this.observedElements.clear();
|
|
19997
|
+
this.isInitialized = false;
|
|
19998
|
+
}
|
|
19999
|
+
/**
|
|
20000
|
+
* Legacy method - now handled by intelligent mutation observer
|
|
20001
|
+
* @deprecated Use setupIntelligentMutationObserver instead
|
|
20002
|
+
*/
|
|
20003
|
+
observeDOM() {
|
|
20004
|
+
// This is now handled by setupIntelligentMutationObserver in setupEventDelegation
|
|
20005
|
+
if (this.config.debug) {
|
|
20006
|
+
console.log('[AutoTracker] observeDOM() is deprecated - using intelligent mutation observer');
|
|
20007
|
+
}
|
|
19444
20008
|
}
|
|
19445
20009
|
/**
|
|
19446
20010
|
* Processar elementos já existentes no DOM
|
|
@@ -19627,23 +20191,194 @@
|
|
|
19627
20191
|
/**
|
|
19628
20192
|
* Enviar evento para o SDK
|
|
19629
20193
|
*/
|
|
20194
|
+
/**
|
|
20195
|
+
* Enhanced event tracking with comprehensive debugging
|
|
20196
|
+
*/
|
|
19630
20197
|
trackEvent(eventName, metadata) {
|
|
19631
|
-
|
|
20198
|
+
const trackingStart = performance.now();
|
|
20199
|
+
if (this.config.debug) {
|
|
20200
|
+
console.log("[🚀 AutoTracker] Enhanced trackEvent called:", {
|
|
20201
|
+
eventName,
|
|
20202
|
+
metadata,
|
|
20203
|
+
timestamp: new Date().toISOString()
|
|
20204
|
+
});
|
|
20205
|
+
}
|
|
20206
|
+
// Comprehensive validation
|
|
20207
|
+
const validation = this.validateTrackingCall(eventName, metadata);
|
|
20208
|
+
if (!validation.isValid) {
|
|
20209
|
+
if (this.config.debug) {
|
|
20210
|
+
console.error("[❌ AutoTracker] Validation failed:", validation.errors);
|
|
20211
|
+
}
|
|
19632
20212
|
return;
|
|
20213
|
+
}
|
|
19633
20214
|
try {
|
|
19634
|
-
|
|
20215
|
+
const eventData = {
|
|
20216
|
+
// Core tracking data
|
|
19635
20217
|
autoTracked: true,
|
|
20218
|
+
enhanced: true,
|
|
19636
20219
|
timestamp: Date.now(),
|
|
19637
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
|
|
19638
20228
|
...metadata,
|
|
19639
|
-
}
|
|
20229
|
+
};
|
|
20230
|
+
if (this.config.debug) {
|
|
20231
|
+
console.log("[📡 AutoTracker] Sending enhanced event:", { eventName, eventData });
|
|
20232
|
+
}
|
|
20233
|
+
const result = this.sdkInstance.trackCustomEvent(eventName, eventData);
|
|
20234
|
+
if (this.config.debug) {
|
|
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
|
+
});
|
|
20241
|
+
}
|
|
19640
20242
|
}
|
|
19641
20243
|
catch (error) {
|
|
19642
20244
|
if (this.config.debug) {
|
|
19643
|
-
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
|
+
});
|
|
19644
20251
|
}
|
|
19645
20252
|
}
|
|
19646
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
|
+
}
|
|
20276
|
+
/**
|
|
20277
|
+
* Modern API: Refresh tracking for dynamic content (React/SPA support)
|
|
20278
|
+
* Industry best practice for SPA route changes
|
|
20279
|
+
*/
|
|
20280
|
+
refreshTracking() {
|
|
20281
|
+
if (!this.isInitialized) {
|
|
20282
|
+
if (this.config.debug) {
|
|
20283
|
+
console.log('[AutoTracker] Not initialized, cannot refresh tracking');
|
|
20284
|
+
}
|
|
20285
|
+
return;
|
|
20286
|
+
}
|
|
20287
|
+
if (this.config.debug) {
|
|
20288
|
+
console.log('[AutoTracker] Refreshing tracking for dynamic content...');
|
|
20289
|
+
}
|
|
20290
|
+
// Re-process elements for view tracking (only thing that needs setup)
|
|
20291
|
+
this.processExistingElements();
|
|
20292
|
+
// Log current state
|
|
20293
|
+
if (this.config.debug) {
|
|
20294
|
+
this.logFoundElements();
|
|
20295
|
+
}
|
|
20296
|
+
}
|
|
20297
|
+
/**
|
|
20298
|
+
* Legacy method - use refreshTracking() instead
|
|
20299
|
+
* @deprecated Use refreshTracking() for better performance
|
|
20300
|
+
*/
|
|
20301
|
+
rescan() {
|
|
20302
|
+
this.refreshTracking();
|
|
20303
|
+
}
|
|
20304
|
+
/**
|
|
20305
|
+
* Get comprehensive diagnostic information for debugging
|
|
20306
|
+
*/
|
|
20307
|
+
getDiagnostics() {
|
|
20308
|
+
return {
|
|
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
|
|
20332
|
+
config: this.config,
|
|
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()
|
|
20350
|
+
};
|
|
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
|
+
}
|
|
19647
20382
|
/**
|
|
19648
20383
|
* Configurar tracking
|
|
19649
20384
|
*/
|
|
@@ -19651,12 +20386,14 @@
|
|
|
19651
20386
|
this.config = { ...this.config, ...config };
|
|
19652
20387
|
}
|
|
19653
20388
|
/**
|
|
19654
|
-
*
|
|
20389
|
+
* Enhanced stats with diagnostic information
|
|
19655
20390
|
*/
|
|
19656
20391
|
getStats() {
|
|
19657
20392
|
return {
|
|
19658
20393
|
observedElements: this.observedElements.size,
|
|
19659
20394
|
config: this.config,
|
|
20395
|
+
isModern: this.isInitialized, // Indicates if using new delegation system
|
|
20396
|
+
diagnostics: this.config.debug ? this.getDiagnostics() : undefined
|
|
19660
20397
|
};
|
|
19661
20398
|
}
|
|
19662
20399
|
}
|
|
@@ -20205,6 +20942,36 @@
|
|
|
20205
20942
|
console.log("[Zaplier] Auto tracking configured:", config);
|
|
20206
20943
|
}
|
|
20207
20944
|
},
|
|
20945
|
+
/**
|
|
20946
|
+
* Refresh tracking for dynamic content (React/SPA route changes)
|
|
20947
|
+
* Modern alternative to rescan() - follows GA4/industry best practices
|
|
20948
|
+
*/
|
|
20949
|
+
refreshTracking: () => {
|
|
20950
|
+
if (this.autoTracker) {
|
|
20951
|
+
this.autoTracker.refreshTracking();
|
|
20952
|
+
}
|
|
20953
|
+
if (this.config.debug) {
|
|
20954
|
+
console.log("[Zaplier] Auto tracking refreshed");
|
|
20955
|
+
}
|
|
20956
|
+
},
|
|
20957
|
+
/**
|
|
20958
|
+
* Legacy rescan method - use refreshTracking() instead
|
|
20959
|
+
* @deprecated Use refreshTracking() for better performance
|
|
20960
|
+
*/
|
|
20961
|
+
rescan: () => {
|
|
20962
|
+
if (this.autoTracker) {
|
|
20963
|
+
this.autoTracker.rescan();
|
|
20964
|
+
}
|
|
20965
|
+
if (this.config.debug) {
|
|
20966
|
+
console.log("[Zaplier] Auto tracking rescanned (deprecated - use refreshTracking)");
|
|
20967
|
+
}
|
|
20968
|
+
},
|
|
20969
|
+
/**
|
|
20970
|
+
* Get diagnostic information for debugging
|
|
20971
|
+
*/
|
|
20972
|
+
getDiagnostics: () => {
|
|
20973
|
+
return this.autoTracker ? this.autoTracker.getDiagnostics() : null;
|
|
20974
|
+
},
|
|
20208
20975
|
getStats: () => {
|
|
20209
20976
|
return this.autoTracker ? this.autoTracker.getStats() : null;
|
|
20210
20977
|
},
|