@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/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,21 +19050,18 @@
|
|
|
19044
19050
|
// Simple rrweb recording configuration like official example
|
|
19045
19051
|
this.rrwebStopRecord = record({
|
|
19046
19052
|
emit: (event) => {
|
|
19047
|
-
//
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
// Simple event capture
|
|
19053
|
-
this.events.push(event);
|
|
19054
|
-
if (event.type === 2) {
|
|
19055
|
-
console.log(`[Zaplier] ✅ FullSnapshot captured as event #${this.events.length}`);
|
|
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);
|
|
19056
19058
|
}
|
|
19057
19059
|
},
|
|
19058
19060
|
});
|
|
19059
19061
|
this.isActive = true;
|
|
19060
19062
|
this.startBatchTimer();
|
|
19061
|
-
|
|
19063
|
+
this.startInactivityTracking();
|
|
19064
|
+
console.log("[Zaplier] Session replay started - with inactivity detection");
|
|
19062
19065
|
return true;
|
|
19063
19066
|
}
|
|
19064
19067
|
catch (error) {
|
|
@@ -19082,6 +19085,10 @@
|
|
|
19082
19085
|
clearInterval(this.batchTimer);
|
|
19083
19086
|
this.batchTimer = undefined;
|
|
19084
19087
|
}
|
|
19088
|
+
if (this.inactivityTimer) {
|
|
19089
|
+
clearTimeout(this.inactivityTimer);
|
|
19090
|
+
this.inactivityTimer = undefined;
|
|
19091
|
+
}
|
|
19085
19092
|
// Send final batch
|
|
19086
19093
|
this.sendBatch();
|
|
19087
19094
|
}
|
|
@@ -19100,17 +19107,21 @@
|
|
|
19100
19107
|
if (this.events.length === 0) {
|
|
19101
19108
|
return;
|
|
19102
19109
|
}
|
|
19103
|
-
//
|
|
19110
|
+
// Enhanced payload structure with visitor linking
|
|
19104
19111
|
const payload = {
|
|
19105
19112
|
sessionId: this.sessionId,
|
|
19113
|
+
visitorId: this.visitorId,
|
|
19106
19114
|
events: [...this.events], // Copy events array
|
|
19107
19115
|
metadata: {
|
|
19108
19116
|
userAgent: navigator.userAgent,
|
|
19109
19117
|
timestamp: Date.now(),
|
|
19110
19118
|
startUrl: window.location.href,
|
|
19111
|
-
duration: Date.now() -
|
|
19119
|
+
duration: Date.now() - this.sessionStartTime,
|
|
19120
|
+
activeTime: this.getActiveTime(),
|
|
19112
19121
|
funnelSteps: [],
|
|
19113
19122
|
hasConversion: false,
|
|
19123
|
+
eventsCount: this.events.length,
|
|
19124
|
+
isPaused: this.isPaused,
|
|
19114
19125
|
},
|
|
19115
19126
|
};
|
|
19116
19127
|
// Reset events array like official example
|
|
@@ -19159,6 +19170,448 @@
|
|
|
19159
19170
|
isRecording() {
|
|
19160
19171
|
return this.isActive;
|
|
19161
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
|
+
}
|
|
19162
19615
|
}
|
|
19163
19616
|
|
|
19164
19617
|
/**
|
|
@@ -19192,7 +19645,7 @@
|
|
|
19192
19645
|
*/
|
|
19193
19646
|
class ZaplierSDK {
|
|
19194
19647
|
constructor(userConfig) {
|
|
19195
|
-
this.version = "1.
|
|
19648
|
+
this.version = "1.6.0";
|
|
19196
19649
|
this.isInitialized = false;
|
|
19197
19650
|
this.eventQueue = [];
|
|
19198
19651
|
/**
|
|
@@ -19263,8 +19716,10 @@
|
|
|
19263
19716
|
}
|
|
19264
19717
|
const sessionId = this.sessionId;
|
|
19265
19718
|
// When explicitly enabled, use 100% sample rate
|
|
19266
|
-
this.replayEngine = new SessionReplayEngine(sessionId, {
|
|
19719
|
+
this.replayEngine = new SessionReplayEngine(sessionId, this.backendVisitorId || 'unknown', {
|
|
19267
19720
|
sampleRate: 1.0, // Force 100% when explicitly enabled
|
|
19721
|
+
inactivityTimeout: 30000,
|
|
19722
|
+
pauseOnInactive: true,
|
|
19268
19723
|
});
|
|
19269
19724
|
// Connect to anti-adblock manager
|
|
19270
19725
|
if (this.antiAdblockManager) {
|
|
@@ -19289,8 +19744,10 @@
|
|
|
19289
19744
|
this.sessionId = this.generateSessionId();
|
|
19290
19745
|
}
|
|
19291
19746
|
const sessionId = this.sessionId;
|
|
19292
|
-
this.replayEngine = new SessionReplayEngine(sessionId, {
|
|
19747
|
+
this.replayEngine = new SessionReplayEngine(sessionId, this.backendVisitorId || 'unknown', {
|
|
19293
19748
|
sampleRate: 1.0, // Force 100% when explicitly enabled
|
|
19749
|
+
inactivityTimeout: 30000,
|
|
19750
|
+
pauseOnInactive: true,
|
|
19294
19751
|
});
|
|
19295
19752
|
// Connect to anti-adblock manager
|
|
19296
19753
|
if (this.antiAdblockManager) {
|
|
@@ -19329,8 +19786,10 @@
|
|
|
19329
19786
|
this.sessionId = this.generateSessionId();
|
|
19330
19787
|
}
|
|
19331
19788
|
const sessionId = this.sessionId;
|
|
19332
|
-
this.replayEngine = new SessionReplayEngine(sessionId, {
|
|
19789
|
+
this.replayEngine = new SessionReplayEngine(sessionId, this.backendVisitorId || 'unknown', {
|
|
19333
19790
|
sampleRate: 1.0, // Force recording when manually started
|
|
19791
|
+
inactivityTimeout: 30000,
|
|
19792
|
+
pauseOnInactive: true,
|
|
19334
19793
|
});
|
|
19335
19794
|
// Connect to anti-adblock manager
|
|
19336
19795
|
if (this.antiAdblockManager) {
|
|
@@ -19362,6 +19821,45 @@
|
|
|
19362
19821
|
this.trackConversion("funnel_conversion", data.value, data.currency, data);
|
|
19363
19822
|
},
|
|
19364
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
|
+
};
|
|
19365
19863
|
// Validate required config
|
|
19366
19864
|
if (!userConfig.token) {
|
|
19367
19865
|
throw new Error("Zaplier: token is required");
|
|
@@ -19403,6 +19901,8 @@
|
|
|
19403
19901
|
this.initializeAntiAdblock();
|
|
19404
19902
|
// Then initialize tracking engines (they'll connect to anti-adblock)
|
|
19405
19903
|
this.initializeTrackingEngines();
|
|
19904
|
+
// Initialize auto tracker
|
|
19905
|
+
this.initializeAutoTracker();
|
|
19406
19906
|
// Process queued events
|
|
19407
19907
|
this.processEventQueue();
|
|
19408
19908
|
if (this.config.debug) {
|
|
@@ -19433,8 +19933,10 @@
|
|
|
19433
19933
|
// When replay is explicitly enabled, use 100% sample rate to ensure recording
|
|
19434
19934
|
// The default replaySampling (0.1) is only for automatic/production sampling
|
|
19435
19935
|
const sampleRate = this.config.replay === true ? 1.0 : this.config.replaySampling;
|
|
19436
|
-
this.replayEngine = new SessionReplayEngine(this.sessionId, {
|
|
19936
|
+
this.replayEngine = new SessionReplayEngine(this.sessionId, this.backendVisitorId || 'unknown', {
|
|
19437
19937
|
sampleRate: sampleRate,
|
|
19938
|
+
inactivityTimeout: 30000,
|
|
19939
|
+
pauseOnInactive: true,
|
|
19438
19940
|
});
|
|
19439
19941
|
// Connect SDK instance for transport
|
|
19440
19942
|
this.replayEngine.setSDKInstance(this);
|
|
@@ -19469,6 +19971,29 @@
|
|
|
19469
19971
|
console.error("[Zaplier] Failed to initialize tracking engines:", error);
|
|
19470
19972
|
}
|
|
19471
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
|
+
}
|
|
19472
19997
|
/**
|
|
19473
19998
|
* Generate session ID
|
|
19474
19999
|
*/
|
|
@@ -20411,6 +20936,44 @@
|
|
|
20411
20936
|
globalInstance.replay.markConversion(data);
|
|
20412
20937
|
}
|
|
20413
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
|
+
},
|
|
20414
20977
|
/**
|
|
20415
20978
|
* Debug and utility functions
|
|
20416
20979
|
*/
|
|
@@ -20437,7 +21000,7 @@
|
|
|
20437
21000
|
/**
|
|
20438
21001
|
* Version info
|
|
20439
21002
|
*/
|
|
20440
|
-
version: '
|
|
21003
|
+
version: '1.6.0'
|
|
20441
21004
|
};
|
|
20442
21005
|
/**
|
|
20443
21006
|
* Auto-initialization from script tag data attributes
|