@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 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
- // CRITICAL: Ensure FullSnapshot is always first event
19046
- if (this.events.length === 0 && event.type !== 2) {
19047
- console.warn(`[Zaplier] First event is type ${event.type}, not FullSnapshot (2). Skipping until FullSnapshot.`);
19048
- return; // Skip non-FullSnapshot events if no FullSnapshot captured yet
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
- console.log("[Zaplier] Session replay started - simple mode");
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
- // Simple payload structure like official example
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() - (performance.timeOrigin || 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.3.7";
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: '3.0.0'
21001
+ version: '1.6.0'
20439
21002
  };
20440
21003
  /**
20441
21004
  * Auto-initialization from script tag data attributes