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