@zaplier/sdk 1.4.1 → 1.6.1
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 +582 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +54 -4
- package/dist/index.esm.js +582 -19
- package/dist/index.esm.js.map +1 -1
- package/dist/sdk.js +582 -19
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.min.js +1 -1
- package/dist/src/modules/auto-tracker.d.ts +101 -0
- package/dist/src/modules/auto-tracker.d.ts.map +1 -0
- package/dist/src/modules/global-interface.d.ts +14 -0
- package/dist/src/modules/global-interface.d.ts.map +1 -1
- package/dist/src/modules/session-replay.d.ts +40 -1
- package/dist/src/modules/session-replay.d.ts.map +1 -1
- package/dist/src/modules/visitor-persistence.d.ts +104 -0
- package/dist/src/modules/visitor-persistence.d.ts.map +1 -0
- package/dist/src/sdk.d.ts +24 -0
- package/dist/src/sdk.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -19016,14 +19016,20 @@ var n;
|
|
|
19016
19016
|
* Based on official rrweb example for maximum compatibility
|
|
19017
19017
|
*/
|
|
19018
19018
|
class SessionReplayEngine {
|
|
19019
|
-
constructor(sessionId, config = {}) {
|
|
19019
|
+
constructor(sessionId, visitorId, config = {}) {
|
|
19020
19020
|
this.events = [];
|
|
19021
19021
|
this.isActive = false;
|
|
19022
|
+
this.isPaused = false;
|
|
19023
|
+
this.lastActivityTime = Date.now();
|
|
19024
|
+
this.sessionStartTime = Date.now();
|
|
19022
19025
|
this.sessionId = sessionId;
|
|
19026
|
+
this.visitorId = visitorId;
|
|
19023
19027
|
this.config = {
|
|
19024
19028
|
enabled: true,
|
|
19025
19029
|
sampleRate: 1.0,
|
|
19026
19030
|
batchInterval: 10000, // 10 seconds like official example
|
|
19031
|
+
inactivityTimeout: 30000, // 30 seconds of inactivity
|
|
19032
|
+
pauseOnInactive: true, // Pause recording during inactivity
|
|
19027
19033
|
...config,
|
|
19028
19034
|
};
|
|
19029
19035
|
}
|
|
@@ -19042,21 +19048,18 @@ class SessionReplayEngine {
|
|
|
19042
19048
|
// Simple rrweb recording configuration like official example
|
|
19043
19049
|
this.rrwebStopRecord = record({
|
|
19044
19050
|
emit: (event) => {
|
|
19045
|
-
//
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
// Simple event capture
|
|
19051
|
-
this.events.push(event);
|
|
19052
|
-
if (event.type === 2) {
|
|
19053
|
-
console.log(`[Zaplier] ✅ FullSnapshot captured as event #${this.events.length}`);
|
|
19051
|
+
// Update activity time on any event
|
|
19052
|
+
this.onActivity();
|
|
19053
|
+
// Only capture events if not paused
|
|
19054
|
+
if (!this.isPaused) {
|
|
19055
|
+
this.events.push(event);
|
|
19054
19056
|
}
|
|
19055
19057
|
},
|
|
19056
19058
|
});
|
|
19057
19059
|
this.isActive = true;
|
|
19058
19060
|
this.startBatchTimer();
|
|
19059
|
-
|
|
19061
|
+
this.startInactivityTracking();
|
|
19062
|
+
console.log("[Zaplier] Session replay started - with inactivity detection");
|
|
19060
19063
|
return true;
|
|
19061
19064
|
}
|
|
19062
19065
|
catch (error) {
|
|
@@ -19080,6 +19083,10 @@ class SessionReplayEngine {
|
|
|
19080
19083
|
clearInterval(this.batchTimer);
|
|
19081
19084
|
this.batchTimer = undefined;
|
|
19082
19085
|
}
|
|
19086
|
+
if (this.inactivityTimer) {
|
|
19087
|
+
clearTimeout(this.inactivityTimer);
|
|
19088
|
+
this.inactivityTimer = undefined;
|
|
19089
|
+
}
|
|
19083
19090
|
// Send final batch
|
|
19084
19091
|
this.sendBatch();
|
|
19085
19092
|
}
|
|
@@ -19098,17 +19105,21 @@ class SessionReplayEngine {
|
|
|
19098
19105
|
if (this.events.length === 0) {
|
|
19099
19106
|
return;
|
|
19100
19107
|
}
|
|
19101
|
-
//
|
|
19108
|
+
// Enhanced payload structure with visitor linking
|
|
19102
19109
|
const payload = {
|
|
19103
19110
|
sessionId: this.sessionId,
|
|
19111
|
+
visitorId: this.visitorId,
|
|
19104
19112
|
events: [...this.events], // Copy events array
|
|
19105
19113
|
metadata: {
|
|
19106
19114
|
userAgent: navigator.userAgent,
|
|
19107
19115
|
timestamp: Date.now(),
|
|
19108
19116
|
startUrl: window.location.href,
|
|
19109
|
-
duration: Date.now() -
|
|
19117
|
+
duration: Date.now() - this.sessionStartTime,
|
|
19118
|
+
activeTime: this.getActiveTime(),
|
|
19110
19119
|
funnelSteps: [],
|
|
19111
19120
|
hasConversion: false,
|
|
19121
|
+
eventsCount: this.events.length,
|
|
19122
|
+
isPaused: this.isPaused,
|
|
19112
19123
|
},
|
|
19113
19124
|
};
|
|
19114
19125
|
// Reset events array like official example
|
|
@@ -19157,6 +19168,448 @@ class SessionReplayEngine {
|
|
|
19157
19168
|
isRecording() {
|
|
19158
19169
|
return this.isActive;
|
|
19159
19170
|
}
|
|
19171
|
+
/**
|
|
19172
|
+
* Check if recording is paused
|
|
19173
|
+
*/
|
|
19174
|
+
isPausedState() {
|
|
19175
|
+
return this.isPaused;
|
|
19176
|
+
}
|
|
19177
|
+
/**
|
|
19178
|
+
* Start inactivity tracking
|
|
19179
|
+
*/
|
|
19180
|
+
startInactivityTracking() {
|
|
19181
|
+
if (!this.config.pauseOnInactive)
|
|
19182
|
+
return;
|
|
19183
|
+
// Listen for user activity events
|
|
19184
|
+
const activityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];
|
|
19185
|
+
activityEvents.forEach(event => {
|
|
19186
|
+
document.addEventListener(event, this.onActivity.bind(this), true);
|
|
19187
|
+
});
|
|
19188
|
+
this.resetInactivityTimer();
|
|
19189
|
+
}
|
|
19190
|
+
/**
|
|
19191
|
+
* Handle activity event
|
|
19192
|
+
*/
|
|
19193
|
+
onActivity() {
|
|
19194
|
+
this.lastActivityTime = Date.now();
|
|
19195
|
+
// Resume if paused
|
|
19196
|
+
if (this.isPaused) {
|
|
19197
|
+
this.resume();
|
|
19198
|
+
}
|
|
19199
|
+
this.resetInactivityTimer();
|
|
19200
|
+
}
|
|
19201
|
+
/**
|
|
19202
|
+
* Reset inactivity timer
|
|
19203
|
+
*/
|
|
19204
|
+
resetInactivityTimer() {
|
|
19205
|
+
if (this.inactivityTimer) {
|
|
19206
|
+
clearTimeout(this.inactivityTimer);
|
|
19207
|
+
}
|
|
19208
|
+
this.inactivityTimer = window.setTimeout(() => {
|
|
19209
|
+
this.pauseForInactivity();
|
|
19210
|
+
}, this.config.inactivityTimeout);
|
|
19211
|
+
}
|
|
19212
|
+
/**
|
|
19213
|
+
* Pause recording due to inactivity
|
|
19214
|
+
*/
|
|
19215
|
+
pauseForInactivity() {
|
|
19216
|
+
if (this.isPaused)
|
|
19217
|
+
return;
|
|
19218
|
+
this.isPaused = true;
|
|
19219
|
+
console.log("[Zaplier] Session replay paused due to inactivity");
|
|
19220
|
+
}
|
|
19221
|
+
/**
|
|
19222
|
+
* Resume recording after activity
|
|
19223
|
+
*/
|
|
19224
|
+
resume() {
|
|
19225
|
+
if (!this.isPaused)
|
|
19226
|
+
return;
|
|
19227
|
+
this.isPaused = false;
|
|
19228
|
+
console.log("[Zaplier] Session replay resumed after activity");
|
|
19229
|
+
}
|
|
19230
|
+
/**
|
|
19231
|
+
* Get total active time (excluding paused periods)
|
|
19232
|
+
*/
|
|
19233
|
+
getActiveTime() {
|
|
19234
|
+
const totalTime = Date.now() - this.sessionStartTime;
|
|
19235
|
+
// For now, return total time. In production, track pause periods accurately
|
|
19236
|
+
return totalTime;
|
|
19237
|
+
}
|
|
19238
|
+
/**
|
|
19239
|
+
* Get visitor ID
|
|
19240
|
+
*/
|
|
19241
|
+
getVisitorId() {
|
|
19242
|
+
return this.visitorId;
|
|
19243
|
+
}
|
|
19244
|
+
}
|
|
19245
|
+
|
|
19246
|
+
/**
|
|
19247
|
+
* Auto Tracker - Sistema de tracking automático via data-* attributes
|
|
19248
|
+
*
|
|
19249
|
+
* Suporta:
|
|
19250
|
+
* - data-track-click="event-name"
|
|
19251
|
+
* - data-track-scroll="event-name"
|
|
19252
|
+
* - data-track-view="event-name"
|
|
19253
|
+
* - data-track-hover="event-name"
|
|
19254
|
+
* - data-track-form="event-name"
|
|
19255
|
+
*/
|
|
19256
|
+
class AutoTracker {
|
|
19257
|
+
constructor(sdkInstance, config = {}) {
|
|
19258
|
+
this.observedElements = new Set();
|
|
19259
|
+
/**
|
|
19260
|
+
* Event handlers (bound to this)
|
|
19261
|
+
*/
|
|
19262
|
+
this.handleClick = (event) => {
|
|
19263
|
+
const target = event.target;
|
|
19264
|
+
if (target.hasAttribute("data-track-click")) ;
|
|
19265
|
+
};
|
|
19266
|
+
this.handleScroll = () => {
|
|
19267
|
+
// Scroll is handled by element-specific listeners
|
|
19268
|
+
};
|
|
19269
|
+
this.handleHover = (event) => {
|
|
19270
|
+
// Hover is handled by element-specific listeners
|
|
19271
|
+
};
|
|
19272
|
+
this.handleForm = (event) => {
|
|
19273
|
+
// Form is handled by element-specific listeners
|
|
19274
|
+
};
|
|
19275
|
+
this.sdkInstance = sdkInstance;
|
|
19276
|
+
this.config = {
|
|
19277
|
+
enabled: true,
|
|
19278
|
+
trackClicks: true,
|
|
19279
|
+
trackScrolls: true,
|
|
19280
|
+
trackViews: true,
|
|
19281
|
+
trackHovers: true,
|
|
19282
|
+
trackForms: true,
|
|
19283
|
+
debug: false,
|
|
19284
|
+
...config,
|
|
19285
|
+
};
|
|
19286
|
+
}
|
|
19287
|
+
/**
|
|
19288
|
+
* Inicializar auto tracking
|
|
19289
|
+
*/
|
|
19290
|
+
start() {
|
|
19291
|
+
if (!this.config.enabled)
|
|
19292
|
+
return;
|
|
19293
|
+
if (this.config.debug) {
|
|
19294
|
+
console.log("[Zaplier AutoTracker] Iniciando auto tracking");
|
|
19295
|
+
}
|
|
19296
|
+
// Observer para novos elementos no DOM
|
|
19297
|
+
this.observeDOM();
|
|
19298
|
+
// Processar elementos já existentes
|
|
19299
|
+
this.processExistingElements();
|
|
19300
|
+
// Setup intersection observer para views
|
|
19301
|
+
if (this.config.trackViews) {
|
|
19302
|
+
this.setupViewTracking();
|
|
19303
|
+
}
|
|
19304
|
+
}
|
|
19305
|
+
/**
|
|
19306
|
+
* Parar auto tracking
|
|
19307
|
+
*/
|
|
19308
|
+
stop() {
|
|
19309
|
+
document.removeEventListener("click", this.handleClick);
|
|
19310
|
+
document.removeEventListener("scroll", this.handleScroll);
|
|
19311
|
+
document.removeEventListener("mouseover", this.handleHover);
|
|
19312
|
+
document.removeEventListener("submit", this.handleForm);
|
|
19313
|
+
if (this.intersectionObserver) {
|
|
19314
|
+
this.intersectionObserver.disconnect();
|
|
19315
|
+
}
|
|
19316
|
+
this.observedElements.clear();
|
|
19317
|
+
}
|
|
19318
|
+
/**
|
|
19319
|
+
* Observar mudanças no DOM para novos elementos
|
|
19320
|
+
*/
|
|
19321
|
+
observeDOM() {
|
|
19322
|
+
const observer = new MutationObserver((mutations) => {
|
|
19323
|
+
mutations.forEach((mutation) => {
|
|
19324
|
+
mutation.addedNodes.forEach((node) => {
|
|
19325
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
19326
|
+
this.processElement(node);
|
|
19327
|
+
}
|
|
19328
|
+
});
|
|
19329
|
+
});
|
|
19330
|
+
});
|
|
19331
|
+
observer.observe(document.body, {
|
|
19332
|
+
childList: true,
|
|
19333
|
+
subtree: true,
|
|
19334
|
+
});
|
|
19335
|
+
}
|
|
19336
|
+
/**
|
|
19337
|
+
* Processar elementos já existentes no DOM
|
|
19338
|
+
*/
|
|
19339
|
+
processExistingElements() {
|
|
19340
|
+
// Buscar todos os elementos com data-track-*
|
|
19341
|
+
const trackElements = document.querySelectorAll("[data-track-click], [data-track-scroll], [data-track-view], [data-track-hover], [data-track-form]");
|
|
19342
|
+
trackElements.forEach((element) => {
|
|
19343
|
+
this.processElement(element);
|
|
19344
|
+
});
|
|
19345
|
+
}
|
|
19346
|
+
/**
|
|
19347
|
+
* Processar um elemento específico
|
|
19348
|
+
*/
|
|
19349
|
+
processElement(element) {
|
|
19350
|
+
// Click tracking
|
|
19351
|
+
if (this.config.trackClicks && element.hasAttribute("data-track-click")) {
|
|
19352
|
+
this.setupClickTracking(element);
|
|
19353
|
+
}
|
|
19354
|
+
// Scroll tracking
|
|
19355
|
+
if (this.config.trackScrolls && element.hasAttribute("data-track-scroll")) {
|
|
19356
|
+
this.setupScrollTracking(element);
|
|
19357
|
+
}
|
|
19358
|
+
// View tracking
|
|
19359
|
+
if (this.config.trackViews && element.hasAttribute("data-track-view")) {
|
|
19360
|
+
this.setupElementViewTracking(element);
|
|
19361
|
+
}
|
|
19362
|
+
// Hover tracking
|
|
19363
|
+
if (this.config.trackHovers && element.hasAttribute("data-track-hover")) {
|
|
19364
|
+
this.setupHoverTracking(element);
|
|
19365
|
+
}
|
|
19366
|
+
// Form tracking
|
|
19367
|
+
if (this.config.trackForms && element.hasAttribute("data-track-form")) {
|
|
19368
|
+
this.setupFormTracking(element);
|
|
19369
|
+
}
|
|
19370
|
+
}
|
|
19371
|
+
/**
|
|
19372
|
+
* Setup click tracking
|
|
19373
|
+
*/
|
|
19374
|
+
setupClickTracking(element) {
|
|
19375
|
+
element.addEventListener("click", (event) => {
|
|
19376
|
+
const eventName = element.getAttribute("data-track-click");
|
|
19377
|
+
if (!eventName)
|
|
19378
|
+
return;
|
|
19379
|
+
const metadata = this.extractMetadata(element);
|
|
19380
|
+
this.trackEvent(eventName, {
|
|
19381
|
+
type: "click",
|
|
19382
|
+
element: element.tagName.toLowerCase(),
|
|
19383
|
+
...metadata,
|
|
19384
|
+
});
|
|
19385
|
+
if (this.config.debug) {
|
|
19386
|
+
console.log(`[AutoTracker] Click tracked: ${eventName}`, metadata);
|
|
19387
|
+
}
|
|
19388
|
+
});
|
|
19389
|
+
}
|
|
19390
|
+
/**
|
|
19391
|
+
* Setup scroll tracking
|
|
19392
|
+
*/
|
|
19393
|
+
setupScrollTracking(element) {
|
|
19394
|
+
let hasTriggered = false;
|
|
19395
|
+
const threshold = parseFloat(element.getAttribute("data-scroll-threshold") || "0.5");
|
|
19396
|
+
const handleScroll = () => {
|
|
19397
|
+
if (hasTriggered)
|
|
19398
|
+
return;
|
|
19399
|
+
const rect = element.getBoundingClientRect();
|
|
19400
|
+
const elementHeight = rect.height;
|
|
19401
|
+
const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
|
|
19402
|
+
const visibilityRatio = Math.max(0, visibleHeight) / elementHeight;
|
|
19403
|
+
if (visibilityRatio >= threshold) {
|
|
19404
|
+
hasTriggered = true;
|
|
19405
|
+
const eventName = element.getAttribute("data-track-scroll");
|
|
19406
|
+
if (!eventName)
|
|
19407
|
+
return;
|
|
19408
|
+
const metadata = this.extractMetadata(element);
|
|
19409
|
+
this.trackEvent(eventName, {
|
|
19410
|
+
type: "scroll",
|
|
19411
|
+
element: element.tagName.toLowerCase(),
|
|
19412
|
+
threshold,
|
|
19413
|
+
scrollDepth: window.scrollY,
|
|
19414
|
+
...metadata,
|
|
19415
|
+
});
|
|
19416
|
+
if (this.config.debug) {
|
|
19417
|
+
console.log(`[AutoTracker] Scroll tracked: ${eventName}`, metadata);
|
|
19418
|
+
}
|
|
19419
|
+
}
|
|
19420
|
+
};
|
|
19421
|
+
document.addEventListener("scroll", handleScroll, { passive: true });
|
|
19422
|
+
// Check immediately in case element is already in view
|
|
19423
|
+
setTimeout(handleScroll, 100);
|
|
19424
|
+
}
|
|
19425
|
+
/**
|
|
19426
|
+
* Setup view tracking usando Intersection Observer
|
|
19427
|
+
*/
|
|
19428
|
+
setupViewTracking() {
|
|
19429
|
+
this.intersectionObserver = new IntersectionObserver((entries) => {
|
|
19430
|
+
entries.forEach((entry) => {
|
|
19431
|
+
if (entry.isIntersecting) {
|
|
19432
|
+
const element = entry.target;
|
|
19433
|
+
const eventName = element.getAttribute("data-track-view");
|
|
19434
|
+
if (!eventName)
|
|
19435
|
+
return;
|
|
19436
|
+
const metadata = this.extractMetadata(element);
|
|
19437
|
+
this.trackEvent(eventName, {
|
|
19438
|
+
type: "view",
|
|
19439
|
+
element: element.tagName.toLowerCase(),
|
|
19440
|
+
intersectionRatio: entry.intersectionRatio,
|
|
19441
|
+
...metadata,
|
|
19442
|
+
});
|
|
19443
|
+
if (this.config.debug) {
|
|
19444
|
+
console.log(`[AutoTracker] View tracked: ${eventName}`, metadata);
|
|
19445
|
+
}
|
|
19446
|
+
// Remove from observation after first trigger
|
|
19447
|
+
this.intersectionObserver?.unobserve(element);
|
|
19448
|
+
}
|
|
19449
|
+
});
|
|
19450
|
+
}, {
|
|
19451
|
+
threshold: 0.5, // 50% visible
|
|
19452
|
+
rootMargin: "0px",
|
|
19453
|
+
});
|
|
19454
|
+
}
|
|
19455
|
+
/**
|
|
19456
|
+
* Setup view tracking para elemento específico
|
|
19457
|
+
*/
|
|
19458
|
+
setupElementViewTracking(element) {
|
|
19459
|
+
if (!this.intersectionObserver)
|
|
19460
|
+
return;
|
|
19461
|
+
if (!this.observedElements.has(element)) {
|
|
19462
|
+
this.intersectionObserver.observe(element);
|
|
19463
|
+
this.observedElements.add(element);
|
|
19464
|
+
}
|
|
19465
|
+
}
|
|
19466
|
+
/**
|
|
19467
|
+
* Setup hover tracking
|
|
19468
|
+
*/
|
|
19469
|
+
setupHoverTracking(element) {
|
|
19470
|
+
let hoverStartTime;
|
|
19471
|
+
const minHoverTime = parseInt(element.getAttribute("data-hover-time") || "1000");
|
|
19472
|
+
element.addEventListener("mouseenter", () => {
|
|
19473
|
+
hoverStartTime = Date.now();
|
|
19474
|
+
});
|
|
19475
|
+
element.addEventListener("mouseleave", () => {
|
|
19476
|
+
const hoverDuration = Date.now() - hoverStartTime;
|
|
19477
|
+
if (hoverDuration >= minHoverTime) {
|
|
19478
|
+
const eventName = element.getAttribute("data-track-hover");
|
|
19479
|
+
if (!eventName)
|
|
19480
|
+
return;
|
|
19481
|
+
const metadata = this.extractMetadata(element);
|
|
19482
|
+
this.trackEvent(eventName, {
|
|
19483
|
+
type: "hover",
|
|
19484
|
+
element: element.tagName.toLowerCase(),
|
|
19485
|
+
hoverDuration,
|
|
19486
|
+
minHoverTime,
|
|
19487
|
+
...metadata,
|
|
19488
|
+
});
|
|
19489
|
+
if (this.config.debug) {
|
|
19490
|
+
console.log(`[AutoTracker] Hover tracked: ${eventName}`, metadata);
|
|
19491
|
+
}
|
|
19492
|
+
}
|
|
19493
|
+
});
|
|
19494
|
+
}
|
|
19495
|
+
/**
|
|
19496
|
+
* Setup form tracking
|
|
19497
|
+
*/
|
|
19498
|
+
setupFormTracking(element) {
|
|
19499
|
+
if (element.tagName.toLowerCase() !== "form")
|
|
19500
|
+
return;
|
|
19501
|
+
element.addEventListener("submit", (event) => {
|
|
19502
|
+
const eventName = element.getAttribute("data-track-form");
|
|
19503
|
+
if (!eventName)
|
|
19504
|
+
return;
|
|
19505
|
+
const formData = new FormData(element);
|
|
19506
|
+
const metadata = this.extractMetadata(element);
|
|
19507
|
+
// Extract form fields (without sensitive data)
|
|
19508
|
+
const fields = {};
|
|
19509
|
+
for (const [key, value] of formData.entries()) {
|
|
19510
|
+
// Skip sensitive fields
|
|
19511
|
+
if (!this.isSensitiveField(key)) {
|
|
19512
|
+
fields[key] =
|
|
19513
|
+
typeof value === "string" ? value.substring(0, 100) : "file";
|
|
19514
|
+
}
|
|
19515
|
+
}
|
|
19516
|
+
this.trackEvent(eventName, {
|
|
19517
|
+
type: "form_submit",
|
|
19518
|
+
element: "form",
|
|
19519
|
+
fieldCount: Array.from(formData.entries()).length,
|
|
19520
|
+
fields,
|
|
19521
|
+
...metadata,
|
|
19522
|
+
});
|
|
19523
|
+
if (this.config.debug) {
|
|
19524
|
+
console.log(`[AutoTracker] Form submit tracked: ${eventName}`, metadata);
|
|
19525
|
+
}
|
|
19526
|
+
});
|
|
19527
|
+
}
|
|
19528
|
+
/**
|
|
19529
|
+
* Extrair metadata do elemento
|
|
19530
|
+
*/
|
|
19531
|
+
extractMetadata(element) {
|
|
19532
|
+
const metadata = {};
|
|
19533
|
+
// Extrair todos os data-meta-* attributes
|
|
19534
|
+
Array.from(element.attributes).forEach((attr) => {
|
|
19535
|
+
if (attr.name.startsWith("data-meta-")) {
|
|
19536
|
+
const key = attr.name.replace("data-meta-", "");
|
|
19537
|
+
metadata[key] = attr.value;
|
|
19538
|
+
}
|
|
19539
|
+
});
|
|
19540
|
+
// Adicionar informações básicas
|
|
19541
|
+
if (element.id)
|
|
19542
|
+
metadata.elementId = element.id;
|
|
19543
|
+
if (element.className)
|
|
19544
|
+
metadata.elementClass = element.className;
|
|
19545
|
+
// Text content (limitado)
|
|
19546
|
+
const textContent = element.textContent?.trim();
|
|
19547
|
+
if (textContent && textContent.length > 0) {
|
|
19548
|
+
metadata.textContent = textContent.substring(0, 50);
|
|
19549
|
+
}
|
|
19550
|
+
// Position info
|
|
19551
|
+
const rect = element.getBoundingClientRect();
|
|
19552
|
+
metadata.elementPosition = {
|
|
19553
|
+
x: Math.round(rect.left),
|
|
19554
|
+
y: Math.round(rect.top),
|
|
19555
|
+
width: Math.round(rect.width),
|
|
19556
|
+
height: Math.round(rect.height),
|
|
19557
|
+
};
|
|
19558
|
+
return metadata;
|
|
19559
|
+
}
|
|
19560
|
+
/**
|
|
19561
|
+
* Verificar se um campo é sensível
|
|
19562
|
+
*/
|
|
19563
|
+
isSensitiveField(fieldName) {
|
|
19564
|
+
const sensitivePatterns = [
|
|
19565
|
+
/password/i,
|
|
19566
|
+
/pass/i,
|
|
19567
|
+
/pwd/i,
|
|
19568
|
+
/secret/i,
|
|
19569
|
+
/token/i,
|
|
19570
|
+
/api[_-]?key/i,
|
|
19571
|
+
/credit[_-]?card/i,
|
|
19572
|
+
/ssn/i,
|
|
19573
|
+
/social/i,
|
|
19574
|
+
/tax/i,
|
|
19575
|
+
];
|
|
19576
|
+
return sensitivePatterns.some((pattern) => pattern.test(fieldName));
|
|
19577
|
+
}
|
|
19578
|
+
/**
|
|
19579
|
+
* Enviar evento para o SDK
|
|
19580
|
+
*/
|
|
19581
|
+
trackEvent(eventName, metadata) {
|
|
19582
|
+
if (!this.sdkInstance)
|
|
19583
|
+
return;
|
|
19584
|
+
try {
|
|
19585
|
+
this.sdkInstance.trackCustomEvent(eventName, {
|
|
19586
|
+
autoTracked: true,
|
|
19587
|
+
timestamp: Date.now(),
|
|
19588
|
+
url: window.location.href,
|
|
19589
|
+
...metadata,
|
|
19590
|
+
});
|
|
19591
|
+
}
|
|
19592
|
+
catch (error) {
|
|
19593
|
+
if (this.config.debug) {
|
|
19594
|
+
console.error("[AutoTracker] Error sending event:", error);
|
|
19595
|
+
}
|
|
19596
|
+
}
|
|
19597
|
+
}
|
|
19598
|
+
/**
|
|
19599
|
+
* Configurar tracking
|
|
19600
|
+
*/
|
|
19601
|
+
configure(config) {
|
|
19602
|
+
this.config = { ...this.config, ...config };
|
|
19603
|
+
}
|
|
19604
|
+
/**
|
|
19605
|
+
* Obter estatísticas
|
|
19606
|
+
*/
|
|
19607
|
+
getStats() {
|
|
19608
|
+
return {
|
|
19609
|
+
observedElements: this.observedElements.size,
|
|
19610
|
+
config: this.config,
|
|
19611
|
+
};
|
|
19612
|
+
}
|
|
19160
19613
|
}
|
|
19161
19614
|
|
|
19162
19615
|
/**
|
|
@@ -19190,7 +19643,7 @@ const DEFAULT_CONFIG = {
|
|
|
19190
19643
|
*/
|
|
19191
19644
|
class ZaplierSDK {
|
|
19192
19645
|
constructor(userConfig) {
|
|
19193
|
-
this.version = "1.
|
|
19646
|
+
this.version = "1.6.0";
|
|
19194
19647
|
this.isInitialized = false;
|
|
19195
19648
|
this.eventQueue = [];
|
|
19196
19649
|
/**
|
|
@@ -19261,8 +19714,10 @@ class ZaplierSDK {
|
|
|
19261
19714
|
}
|
|
19262
19715
|
const sessionId = this.sessionId;
|
|
19263
19716
|
// When explicitly enabled, use 100% sample rate
|
|
19264
|
-
this.replayEngine = new SessionReplayEngine(sessionId, {
|
|
19717
|
+
this.replayEngine = new SessionReplayEngine(sessionId, this.backendVisitorId || 'unknown', {
|
|
19265
19718
|
sampleRate: 1.0, // Force 100% when explicitly enabled
|
|
19719
|
+
inactivityTimeout: 30000,
|
|
19720
|
+
pauseOnInactive: true,
|
|
19266
19721
|
});
|
|
19267
19722
|
// Connect to anti-adblock manager
|
|
19268
19723
|
if (this.antiAdblockManager) {
|
|
@@ -19287,8 +19742,10 @@ class ZaplierSDK {
|
|
|
19287
19742
|
this.sessionId = this.generateSessionId();
|
|
19288
19743
|
}
|
|
19289
19744
|
const sessionId = this.sessionId;
|
|
19290
|
-
this.replayEngine = new SessionReplayEngine(sessionId, {
|
|
19745
|
+
this.replayEngine = new SessionReplayEngine(sessionId, this.backendVisitorId || 'unknown', {
|
|
19291
19746
|
sampleRate: 1.0, // Force 100% when explicitly enabled
|
|
19747
|
+
inactivityTimeout: 30000,
|
|
19748
|
+
pauseOnInactive: true,
|
|
19292
19749
|
});
|
|
19293
19750
|
// Connect to anti-adblock manager
|
|
19294
19751
|
if (this.antiAdblockManager) {
|
|
@@ -19327,8 +19784,10 @@ class ZaplierSDK {
|
|
|
19327
19784
|
this.sessionId = this.generateSessionId();
|
|
19328
19785
|
}
|
|
19329
19786
|
const sessionId = this.sessionId;
|
|
19330
|
-
this.replayEngine = new SessionReplayEngine(sessionId, {
|
|
19787
|
+
this.replayEngine = new SessionReplayEngine(sessionId, this.backendVisitorId || 'unknown', {
|
|
19331
19788
|
sampleRate: 1.0, // Force recording when manually started
|
|
19789
|
+
inactivityTimeout: 30000,
|
|
19790
|
+
pauseOnInactive: true,
|
|
19332
19791
|
});
|
|
19333
19792
|
// Connect to anti-adblock manager
|
|
19334
19793
|
if (this.antiAdblockManager) {
|
|
@@ -19360,6 +19819,45 @@ class ZaplierSDK {
|
|
|
19360
19819
|
this.trackConversion("funnel_conversion", data.value, data.currency, data);
|
|
19361
19820
|
},
|
|
19362
19821
|
};
|
|
19822
|
+
/**
|
|
19823
|
+
* Auto Tracker API
|
|
19824
|
+
*/
|
|
19825
|
+
this.autoTrack = {
|
|
19826
|
+
enable: () => {
|
|
19827
|
+
if (!this.autoTracker) {
|
|
19828
|
+
this.initializeAutoTracker();
|
|
19829
|
+
}
|
|
19830
|
+
else {
|
|
19831
|
+
this.autoTracker.configure({ enabled: true });
|
|
19832
|
+
}
|
|
19833
|
+
if (this.config.debug) {
|
|
19834
|
+
console.log("[Zaplier] Auto tracking enabled");
|
|
19835
|
+
}
|
|
19836
|
+
},
|
|
19837
|
+
disable: () => {
|
|
19838
|
+
if (this.autoTracker) {
|
|
19839
|
+
this.autoTracker.stop();
|
|
19840
|
+
this.autoTracker = undefined;
|
|
19841
|
+
}
|
|
19842
|
+
if (this.config.debug) {
|
|
19843
|
+
console.log("[Zaplier] Auto tracking disabled");
|
|
19844
|
+
}
|
|
19845
|
+
},
|
|
19846
|
+
configure: (config) => {
|
|
19847
|
+
if (this.autoTracker) {
|
|
19848
|
+
this.autoTracker.configure(config);
|
|
19849
|
+
}
|
|
19850
|
+
if (this.config.debug) {
|
|
19851
|
+
console.log("[Zaplier] Auto tracking configured:", config);
|
|
19852
|
+
}
|
|
19853
|
+
},
|
|
19854
|
+
getStats: () => {
|
|
19855
|
+
return this.autoTracker ? this.autoTracker.getStats() : null;
|
|
19856
|
+
},
|
|
19857
|
+
isEnabled: () => {
|
|
19858
|
+
return !!this.autoTracker;
|
|
19859
|
+
},
|
|
19860
|
+
};
|
|
19363
19861
|
// Validate required config
|
|
19364
19862
|
if (!userConfig.token) {
|
|
19365
19863
|
throw new Error("Zaplier: token is required");
|
|
@@ -19401,6 +19899,8 @@ class ZaplierSDK {
|
|
|
19401
19899
|
this.initializeAntiAdblock();
|
|
19402
19900
|
// Then initialize tracking engines (they'll connect to anti-adblock)
|
|
19403
19901
|
this.initializeTrackingEngines();
|
|
19902
|
+
// Initialize auto tracker
|
|
19903
|
+
this.initializeAutoTracker();
|
|
19404
19904
|
// Process queued events
|
|
19405
19905
|
this.processEventQueue();
|
|
19406
19906
|
if (this.config.debug) {
|
|
@@ -19431,8 +19931,10 @@ class ZaplierSDK {
|
|
|
19431
19931
|
// When replay is explicitly enabled, use 100% sample rate to ensure recording
|
|
19432
19932
|
// The default replaySampling (0.1) is only for automatic/production sampling
|
|
19433
19933
|
const sampleRate = this.config.replay === true ? 1.0 : this.config.replaySampling;
|
|
19434
|
-
this.replayEngine = new SessionReplayEngine(this.sessionId, {
|
|
19934
|
+
this.replayEngine = new SessionReplayEngine(this.sessionId, this.backendVisitorId || 'unknown', {
|
|
19435
19935
|
sampleRate: sampleRate,
|
|
19936
|
+
inactivityTimeout: 30000,
|
|
19937
|
+
pauseOnInactive: true,
|
|
19436
19938
|
});
|
|
19437
19939
|
// Connect SDK instance for transport
|
|
19438
19940
|
this.replayEngine.setSDKInstance(this);
|
|
@@ -19467,6 +19969,29 @@ class ZaplierSDK {
|
|
|
19467
19969
|
console.error("[Zaplier] Failed to initialize tracking engines:", error);
|
|
19468
19970
|
}
|
|
19469
19971
|
}
|
|
19972
|
+
/**
|
|
19973
|
+
* Initialize Auto Tracker for data-* attributes
|
|
19974
|
+
*/
|
|
19975
|
+
initializeAutoTracker() {
|
|
19976
|
+
try {
|
|
19977
|
+
this.autoTracker = new AutoTracker(this, {
|
|
19978
|
+
enabled: true,
|
|
19979
|
+
trackClicks: true,
|
|
19980
|
+
trackScrolls: true,
|
|
19981
|
+
trackViews: true,
|
|
19982
|
+
trackHovers: true,
|
|
19983
|
+
trackForms: true,
|
|
19984
|
+
debug: this.config.debug,
|
|
19985
|
+
});
|
|
19986
|
+
this.autoTracker.start();
|
|
19987
|
+
if (this.config.debug) {
|
|
19988
|
+
console.log("[Zaplier] Auto Tracker initialized and started");
|
|
19989
|
+
}
|
|
19990
|
+
}
|
|
19991
|
+
catch (error) {
|
|
19992
|
+
console.error("[Zaplier] Failed to initialize Auto Tracker:", error);
|
|
19993
|
+
}
|
|
19994
|
+
}
|
|
19470
19995
|
/**
|
|
19471
19996
|
* Generate session ID
|
|
19472
19997
|
*/
|
|
@@ -20409,6 +20934,44 @@ const Zaplier = {
|
|
|
20409
20934
|
globalInstance.replay.markConversion(data);
|
|
20410
20935
|
}
|
|
20411
20936
|
},
|
|
20937
|
+
/**
|
|
20938
|
+
* Auto Tracker API
|
|
20939
|
+
*/
|
|
20940
|
+
autoTrack: {
|
|
20941
|
+
enable: () => {
|
|
20942
|
+
if (!globalInstance) {
|
|
20943
|
+
console.warn('[Zaplier] SDK not initialized. Call Zaplier.init() first');
|
|
20944
|
+
return;
|
|
20945
|
+
}
|
|
20946
|
+
globalInstance.autoTrack.enable();
|
|
20947
|
+
},
|
|
20948
|
+
disable: () => {
|
|
20949
|
+
if (!globalInstance) {
|
|
20950
|
+
console.warn('[Zaplier] SDK not initialized. Call Zaplier.init() first');
|
|
20951
|
+
return;
|
|
20952
|
+
}
|
|
20953
|
+
globalInstance.autoTrack.disable();
|
|
20954
|
+
},
|
|
20955
|
+
configure: (config) => {
|
|
20956
|
+
if (!globalInstance) {
|
|
20957
|
+
console.warn('[Zaplier] SDK not initialized. Call Zaplier.init() first');
|
|
20958
|
+
return;
|
|
20959
|
+
}
|
|
20960
|
+
globalInstance.autoTrack.configure(config);
|
|
20961
|
+
},
|
|
20962
|
+
getStats: () => {
|
|
20963
|
+
if (!globalInstance) {
|
|
20964
|
+
return null;
|
|
20965
|
+
}
|
|
20966
|
+
return globalInstance.autoTrack.getStats();
|
|
20967
|
+
},
|
|
20968
|
+
isEnabled: () => {
|
|
20969
|
+
if (!globalInstance) {
|
|
20970
|
+
return false;
|
|
20971
|
+
}
|
|
20972
|
+
return globalInstance.autoTrack.isEnabled();
|
|
20973
|
+
}
|
|
20974
|
+
},
|
|
20412
20975
|
/**
|
|
20413
20976
|
* Debug and utility functions
|
|
20414
20977
|
*/
|
|
@@ -20435,7 +20998,7 @@ const Zaplier = {
|
|
|
20435
20998
|
/**
|
|
20436
20999
|
* Version info
|
|
20437
21000
|
*/
|
|
20438
|
-
version: '
|
|
21001
|
+
version: '1.6.0'
|
|
20439
21002
|
};
|
|
20440
21003
|
/**
|
|
20441
21004
|
* Auto-initialization from script tag data attributes
|