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