@devskin/browser-sdk 1.0.41 → 1.0.43

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.
@@ -13473,11 +13473,12 @@ class RRWebRecorder {
13473
13473
  },
13474
13474
  // Configuration options
13475
13475
  sampling: {
13476
- // Mouse interactions
13477
- mousemove: this.config.sampleRate !== undefined
13478
- ? Math.floor(100 / this.config.sampleRate)
13479
- : true,
13480
- // Mouse interactions
13476
+ // Mouse movement sampling - throttle to reduce bandwidth
13477
+ // e.g. 0.1 = capture 10% of mouse movements (Math.floor(1/0.1) = 10, meaning capture 1 every 10 events)
13478
+ mousemove: this.config.mouseMoveSampleRate !== undefined
13479
+ ? Math.max(1, Math.floor(1 / this.config.mouseMoveSampleRate))
13480
+ : 10, // Default: capture 1 every 10 mouse movements (10%)
13481
+ // Mouse interactions (clicks, etc) - always capture
13481
13482
  mouseInteraction: true,
13482
13483
  // Scroll events
13483
13484
  scroll: 150, // Throttle scroll events to every 150ms
@@ -13892,6 +13893,72 @@ class DevSkinSDK {
13892
13893
  // private sessionRecorder: SessionRecorder | null = null; // Replaced by RRWebRecorder
13893
13894
  this.rrwebRecorder = null;
13894
13895
  }
13896
+ /**
13897
+ * Detect if the current visitor is a bot/crawler
13898
+ */
13899
+ isBot() {
13900
+ if (typeof navigator === 'undefined')
13901
+ return true;
13902
+ const botPatterns = [
13903
+ /bot/i,
13904
+ /crawler/i,
13905
+ /spider/i,
13906
+ /crawling/i,
13907
+ /google/i,
13908
+ /bing/i,
13909
+ /yahoo/i,
13910
+ /duckduckgo/i,
13911
+ /baiduspider/i,
13912
+ /yandex/i,
13913
+ /facebookexternalhit/i,
13914
+ /twitterbot/i,
13915
+ /rogerbot/i,
13916
+ /linkedinbot/i,
13917
+ /embedly/i,
13918
+ /quora link preview/i,
13919
+ /showyoubot/i,
13920
+ /outbrain/i,
13921
+ /pinterest/i,
13922
+ /slackbot/i,
13923
+ /vkShare/i,
13924
+ /W3C_Validator/i,
13925
+ /redditbot/i,
13926
+ /Applebot/i,
13927
+ /WhatsApp/i,
13928
+ /flipboard/i,
13929
+ /tumblr/i,
13930
+ /bitlybot/i,
13931
+ /SkypeUriPreview/i,
13932
+ /nuzzel/i,
13933
+ /Discordbot/i,
13934
+ /Google Page Speed/i,
13935
+ /Qwantify/i,
13936
+ /pinterestbot/i,
13937
+ /Bitrix link preview/i,
13938
+ /XING-contenttabreceiver/i,
13939
+ /Chrome-Lighthouse/i,
13940
+ /telegrambot/i,
13941
+ /Lighthouse/i,
13942
+ /GTmetrix/i,
13943
+ /PageSpeed/i,
13944
+ /HeadlessChrome/i,
13945
+ /PhantomJS/i,
13946
+ ];
13947
+ const userAgent = navigator.userAgent;
13948
+ // Check user agent against bot patterns
13949
+ if (botPatterns.some(pattern => pattern.test(userAgent))) {
13950
+ return true;
13951
+ }
13952
+ // Check for headless browsers
13953
+ if ('webdriver' in navigator && navigator.webdriver === true) {
13954
+ return true;
13955
+ }
13956
+ // Check for headless Chrome
13957
+ if (userAgent.includes('HeadlessChrome')) {
13958
+ return true;
13959
+ }
13960
+ return false;
13961
+ }
13895
13962
  /**
13896
13963
  * Initialize the DevSkin SDK
13897
13964
  * Uses requestIdleCallback to defer heavy initialization without blocking the page
@@ -13901,6 +13968,14 @@ class DevSkinSDK {
13901
13968
  console.warn('[DevSkin] SDK already initialized or initializing');
13902
13969
  return;
13903
13970
  }
13971
+ // CRITICAL: Skip ALL initialization for bots/crawlers (SEO optimization)
13972
+ // This ensures ZERO performance impact on Google PageSpeed, Lighthouse, etc.
13973
+ if (this.isBot()) {
13974
+ if (config.debug) {
13975
+ console.log('[DevSkin] Bot/crawler detected - SDK disabled for SEO optimization');
13976
+ }
13977
+ return;
13978
+ }
13904
13979
  // Mark as initializing to prevent duplicate init() calls
13905
13980
  this.initializing = true;
13906
13981
  this.config = Object.assign({ debug: false, captureWebVitals: true, captureNetworkRequests: true, captureErrors: true, captureUserAgent: true, captureLocation: true, captureDevice: true, heatmapOptions: {
@@ -13924,7 +13999,7 @@ class DevSkinSDK {
13924
13999
  // Wait for session creation to complete before starting collectors
13925
14000
  this.startSession().then(() => {
13926
14001
  // Session created, now safe to start collectors that send data
13927
- var _a, _b;
14002
+ var _a, _b, _c;
13928
14003
  if (this.config.captureWebVitals) {
13929
14004
  this.performanceCollector = new PerformanceCollector(this.config, this.transport);
13930
14005
  this.performanceCollector.start();
@@ -13951,36 +14026,46 @@ class DevSkinSDK {
13951
14026
  }
13952
14027
  // Initialize session recording with rrweb
13953
14028
  if ((_a = this.config.sessionRecording) === null || _a === void 0 ? void 0 : _a.enabled) {
13954
- // Use RRWebRecorder for complete DOM recording
13955
- // Pass sessionStartTime to ensure timestamp continuity across page navigations
13956
- this.rrwebRecorder = new RRWebRecorder(this.sessionId, {
13957
- enabled: true,
13958
- sampleRate: this.config.sessionRecording.sampling || 0.5,
13959
- blockClass: 'rr-block',
13960
- ignoreClass: this.config.sessionRecording.ignoreClass || 'rr-ignore',
13961
- maskAllInputs: this.config.sessionRecording.maskAllInputs !== undefined
13962
- ? this.config.sessionRecording.maskAllInputs
13963
- : true,
13964
- maskInputOptions: {
13965
- password: true,
13966
- email: true,
13967
- tel: true,
13968
- },
13969
- recordCanvas: this.config.sessionRecording.recordCanvas || false,
13970
- collectFonts: true,
13971
- inlineStylesheet: true,
13972
- checkoutEveryNms: 5 * 60 * 1000, // Every 5 minutes
13973
- checkoutEveryNth: 200, // Every 200 events
13974
- }, (events) => {
13975
- var _a;
13976
- // Send rrweb events to backend
13977
- (_a = this.transport) === null || _a === void 0 ? void 0 : _a.sendRecordingEvents(this.sessionId, events);
13978
- }, this.sessionStartTime // Pass session start time for timestamp continuity
13979
- );
13980
- // Start recording immediately (session already created)
13981
- this.rrwebRecorder.start();
13982
- if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.debug) {
13983
- console.log('[DevSkin] RRWeb recording started for session:', this.sessionId);
14029
+ // Apply session sampling - decide if this session should be recorded
14030
+ const samplingRate = this.config.sessionRecording.sampling || 1.0;
14031
+ const shouldRecord = Math.random() < samplingRate;
14032
+ if (shouldRecord) {
14033
+ // Use RRWebRecorder for complete DOM recording
14034
+ // Pass sessionStartTime to ensure timestamp continuity across page navigations
14035
+ this.rrwebRecorder = new RRWebRecorder(this.sessionId, {
14036
+ enabled: true,
14037
+ mouseMoveSampleRate: 0.5, // Sample 50% of mouse movements to reduce bandwidth
14038
+ blockClass: 'rr-block',
14039
+ ignoreClass: this.config.sessionRecording.ignoreClass || 'rr-ignore',
14040
+ maskAllInputs: this.config.sessionRecording.maskAllInputs !== undefined
14041
+ ? this.config.sessionRecording.maskAllInputs
14042
+ : true,
14043
+ maskInputOptions: {
14044
+ password: true,
14045
+ email: true,
14046
+ tel: true,
14047
+ },
14048
+ recordCanvas: this.config.sessionRecording.recordCanvas || false,
14049
+ collectFonts: true,
14050
+ inlineStylesheet: true,
14051
+ checkoutEveryNms: 5 * 60 * 1000, // Every 5 minutes
14052
+ checkoutEveryNth: 200, // Every 200 events
14053
+ }, (events) => {
14054
+ var _a;
14055
+ // Send rrweb events to backend
14056
+ (_a = this.transport) === null || _a === void 0 ? void 0 : _a.sendRecordingEvents(this.sessionId, events);
14057
+ }, this.sessionStartTime // Pass session start time for timestamp continuity
14058
+ );
14059
+ // Start recording immediately (session already created)
14060
+ this.rrwebRecorder.start();
14061
+ if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.debug) {
14062
+ console.log(`[DevSkin] RRWeb recording started for session: ${this.sessionId} (sampling: ${samplingRate * 100}%)`);
14063
+ }
14064
+ }
14065
+ else {
14066
+ if ((_c = this.config) === null || _c === void 0 ? void 0 : _c.debug) {
14067
+ console.log(`[DevSkin] Session ${this.sessionId} not sampled for recording (sampling: ${samplingRate * 100}%)`);
14068
+ }
13984
14069
  }
13985
14070
  }
13986
14071
  // Track initial page view