mixpanel-browser 2.49.0 → 2.51.0

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.
@@ -53,7 +53,7 @@ var MIXPANEL_LIB_URL = '//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js';
53
53
 
54
54
  // create shallow clone of the public mixpanel interface
55
55
  // Note: only supports 1 additional level atm, e.g. mixpanel.people.set, not mixpanel.people.set.do_something_else.
56
- functions = "disable time_event track track_pageview track_links track_forms track_with_groups add_group set_group remove_group register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking start_batch_senders people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user people.remove".split(' ');
56
+ functions = "disable time_event track track_pageview track_links track_forms track_with_groups add_group set_group remove_group register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking start_batch_senders start_session_recording stop_session_recording people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user people.remove".split(' ');
57
57
  for (i = 0; i < functions.length; i++) {
58
58
  _set_and_defer(target, functions[i]);
59
59
  }
@@ -1,6 +1,6 @@
1
1
  /* eslint camelcase: "off" */
2
2
  import Config from './config';
3
- import { _, console, userAgent, window, document, navigator, slice } from './utils';
3
+ import { MAX_RECORDING_MS, _, console, userAgent, window, document, navigator, slice } from './utils';
4
4
  import { FormTracker, LinkTracker } from './dom-trackers';
5
5
  import { RequestBatcher } from './request-batcher';
6
6
  import { MixpanelGroup } from './mixpanel-group';
@@ -84,7 +84,8 @@ if (navigator['sendBeacon']) {
84
84
  var DEFAULT_API_ROUTES = {
85
85
  'track': 'track/',
86
86
  'engage': 'engage/',
87
- 'groups': 'groups/'
87
+ 'groups': 'groups/',
88
+ 'record': 'record/'
88
89
  };
89
90
 
90
91
  /*
@@ -111,7 +112,7 @@ var DEFAULT_CONFIG = {
111
112
  'track_pageview': false,
112
113
  'skip_first_touch_marketing': false,
113
114
  'store_google': true,
114
- 'stop_utm_persistence': false,
115
+ 'stop_utm_persistence': true,
115
116
  'save_referrer': true,
116
117
  'test': false,
117
118
  'verbose': false,
@@ -136,7 +137,15 @@ var DEFAULT_CONFIG = {
136
137
  'batch_flush_interval_ms': 5000,
137
138
  'batch_request_timeout_ms': 90000,
138
139
  'batch_autostart': true,
139
- 'hooks': {}
140
+ 'hooks': {},
141
+ 'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
142
+ 'record_block_selector': 'img, video',
143
+ 'record_idle_timeout_ms': 30 * 60 * 1000, // 30 minutes
144
+ 'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
145
+ 'record_mask_text_selector': '*',
146
+ 'record_max_ms': MAX_RECORDING_MS,
147
+ 'record_sessions_percent': 0,
148
+ 'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js'
140
149
  };
141
150
 
142
151
  var DOM_LOADED = false;
@@ -349,6 +358,52 @@ MixpanelLib.prototype._init = function(token, config, name) {
349
358
  if (track_pageview_option) {
350
359
  this._init_url_change_tracking(track_pageview_option);
351
360
  }
361
+
362
+ if (this.get_config('record_sessions_percent') > 0 && Math.random() * 100 <= this.get_config('record_sessions_percent')) {
363
+ this.start_session_recording();
364
+ }
365
+ };
366
+
367
+ MixpanelLib.prototype.start_session_recording = addOptOutCheckMixpanelLib(function () {
368
+ if (!window['MutationObserver']) {
369
+ console.critical('Browser does not support MutationObserver; skipping session recording');
370
+ return;
371
+ }
372
+
373
+ var handleLoadedRecorder = _.bind(function() {
374
+ this._recorder = this._recorder || new window['__mp_recorder'](this);
375
+ this._recorder['startRecording']();
376
+ }, this);
377
+
378
+ if (_.isUndefined(window['__mp_recorder'])) {
379
+ var scriptEl = document.createElement('script');
380
+ scriptEl.type = 'text/javascript';
381
+ scriptEl.async = true;
382
+ scriptEl.onload = handleLoadedRecorder;
383
+ scriptEl.src = this.get_config('recorder_src');
384
+ document.head.appendChild(scriptEl);
385
+ } else {
386
+ handleLoadedRecorder();
387
+ }
388
+ });
389
+
390
+ MixpanelLib.prototype.stop_session_recording = function () {
391
+ if (this._recorder) {
392
+ this._recorder['stopRecording']();
393
+ } else {
394
+ console.critical('Session recorder module not loaded');
395
+ }
396
+ };
397
+
398
+ MixpanelLib.prototype.get_session_recording_properties = function () {
399
+ var props = {};
400
+ if (this._recorder) {
401
+ var replay_id = this._recorder['replayId'];
402
+ if (replay_id) {
403
+ props['$mp_replay_id'] = replay_id;
404
+ }
405
+ }
406
+ return props;
352
407
  };
353
408
 
354
409
  // Private methods
@@ -358,9 +413,8 @@ MixpanelLib.prototype._loaded = function() {
358
413
  this._set_default_superprops();
359
414
  this['people'].set_once(this['persistence'].get_referrer_info());
360
415
 
361
- // The original 'store_google' functionality will be deprecated and the config will be
362
- // used to clear previously managed UTM parameters from persistence.
363
- // stop_utm_persistence is `false` by default now but will be default `true` in the future.
416
+ // `store_google` is now deprecated and previously stored UTM parameters are cleared
417
+ // from persistence by default.
364
418
  if (this.get_config('store_google') && this.get_config('stop_utm_persistence')) {
365
419
  var utm_params = _.info.campaignParams(null);
366
420
  _.each(utm_params, function(_utm_value, utm_key) {
@@ -374,6 +428,7 @@ MixpanelLib.prototype._loaded = function() {
374
428
  // update persistence with info on referrer, UTM params, etc
375
429
  MixpanelLib.prototype._set_default_superprops = function() {
376
430
  this['persistence'].update_search_keyword(document.referrer);
431
+ // Registering super properties for UTM persistence by 'store_google' is deprecated.
377
432
  if (this.get_config('store_google') && !this.get_config('stop_utm_persistence')) {
378
433
  this.register(_.info.campaignParams());
379
434
  }
@@ -933,6 +988,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro
933
988
  marketing_properties,
934
989
  this['persistence'].properties(),
935
990
  this.unpersisted_superprops,
991
+ this.get_session_recording_properties(),
936
992
  properties
937
993
  );
938
994
 
@@ -2040,38 +2096,41 @@ MixpanelLib.prototype.report_error = function(msg, err) {
2040
2096
  // EXPORTS (for closure compiler)
2041
2097
 
2042
2098
  // MixpanelLib Exports
2043
- MixpanelLib.prototype['init'] = MixpanelLib.prototype.init;
2044
- MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset;
2045
- MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable;
2046
- MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event;
2047
- MixpanelLib.prototype['track'] = MixpanelLib.prototype.track;
2048
- MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links;
2049
- MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms;
2050
- MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview;
2051
- MixpanelLib.prototype['register'] = MixpanelLib.prototype.register;
2052
- MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once;
2053
- MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister;
2054
- MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify;
2055
- MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias;
2056
- MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
2057
- MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
2058
- MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
2059
- MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
2060
- MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
2061
- MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
2062
- MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking;
2063
- MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking;
2064
- MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking;
2065
- MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking;
2066
- MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking;
2067
- MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group;
2068
- MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group;
2069
- MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group;
2070
- MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group;
2071
- MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups;
2072
- MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders;
2073
- MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders;
2074
- MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES;
2099
+ MixpanelLib.prototype['init'] = MixpanelLib.prototype.init;
2100
+ MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset;
2101
+ MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable;
2102
+ MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event;
2103
+ MixpanelLib.prototype['track'] = MixpanelLib.prototype.track;
2104
+ MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links;
2105
+ MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms;
2106
+ MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview;
2107
+ MixpanelLib.prototype['register'] = MixpanelLib.prototype.register;
2108
+ MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once;
2109
+ MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister;
2110
+ MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify;
2111
+ MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias;
2112
+ MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
2113
+ MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
2114
+ MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
2115
+ MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
2116
+ MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
2117
+ MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
2118
+ MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking;
2119
+ MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking;
2120
+ MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking;
2121
+ MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking;
2122
+ MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking;
2123
+ MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group;
2124
+ MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group;
2125
+ MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group;
2126
+ MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group;
2127
+ MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups;
2128
+ MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders;
2129
+ MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders;
2130
+ MixpanelLib.prototype['start_session_recording'] = MixpanelLib.prototype.start_session_recording;
2131
+ MixpanelLib.prototype['stop_session_recording'] = MixpanelLib.prototype.stop_session_recording;
2132
+ MixpanelLib.prototype['get_session_recording_properties'] = MixpanelLib.prototype.get_session_recording_properties;
2133
+ MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES;
2075
2134
 
2076
2135
  // MixpanelPersistence Exports
2077
2136
  MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties;
@@ -66,7 +66,7 @@ var MixpanelPersistence = function(config) {
66
66
 
67
67
  this.load();
68
68
  this.update_config(config);
69
- this.upgrade(config);
69
+ this.upgrade();
70
70
  this.save();
71
71
  };
72
72
 
@@ -94,49 +94,12 @@ MixpanelPersistence.prototype.load = function() {
94
94
  }
95
95
  };
96
96
 
97
- MixpanelPersistence.prototype.upgrade = function(config) {
98
- var upgrade_from_old_lib = config['upgrade'],
99
- old_cookie_name,
100
- old_cookie;
101
-
102
- if (upgrade_from_old_lib) {
103
- old_cookie_name = 'mp_super_properties';
104
- // Case where they had a custom cookie name before.
105
- if (typeof(upgrade_from_old_lib) === 'string') {
106
- old_cookie_name = upgrade_from_old_lib;
107
- }
108
-
109
- old_cookie = this.storage.parse(old_cookie_name);
110
-
111
- // remove the cookie
112
- this.storage.remove(old_cookie_name);
113
- this.storage.remove(old_cookie_name, true);
114
-
115
- if (old_cookie) {
116
- this['props'] = _.extend(
117
- this['props'],
118
- old_cookie['all'],
119
- old_cookie['events']
120
- );
121
- }
122
- }
123
-
124
- if (!config['cookie_name'] && config['name'] !== 'mixpanel') {
125
- // special case to handle people with cookies of the form
126
- // mp_TOKEN_INSTANCENAME from the first release of this library
127
- old_cookie_name = 'mp_' + config['token'] + '_' + config['name'];
128
- old_cookie = this.storage.parse(old_cookie_name);
129
-
130
- if (old_cookie) {
131
- this.storage.remove(old_cookie_name);
132
- this.storage.remove(old_cookie_name, true);
133
-
134
- // Save the prop values that were in the cookie from before -
135
- // this should only happen once as we delete the old one.
136
- this.register_once(old_cookie);
137
- }
138
- }
97
+ MixpanelPersistence.prototype.upgrade = function() {
98
+ var old_cookie,
99
+ old_localstorage;
139
100
 
101
+ // if transferring from cookie to localStorage or vice-versa, copy existing
102
+ // super properties over to new storage mode
140
103
  if (this.storage === _.localStorage) {
141
104
  old_cookie = _.cookie.parse(this.name);
142
105
 
@@ -146,6 +109,14 @@ MixpanelPersistence.prototype.upgrade = function(config) {
146
109
  if (old_cookie) {
147
110
  this.register_once(old_cookie);
148
111
  }
112
+ } else if (this.storage === _.cookie) {
113
+ old_localstorage = _.localStorage.parse(this.name);
114
+
115
+ _.localStorage.remove(this.name);
116
+
117
+ if (old_localstorage) {
118
+ this.register_once(old_localstorage);
119
+ }
149
120
  }
150
121
  };
151
122
 
@@ -0,0 +1,156 @@
1
+ import {default as record} from 'rrweb/es/rrweb/packages/rrweb/src/record/index.js';
2
+
3
+ import { MAX_RECORDING_MS, console_with_prefix, _ } from '../utils'; // eslint-disable-line camelcase
4
+ import { addOptOutCheckMixpanelLib } from '../gdpr-utils';
5
+
6
+ var logger = console_with_prefix('recorder');
7
+
8
+ var MixpanelRecorder = function(mixpanelInstance) {
9
+ this._mixpanel = mixpanelInstance;
10
+
11
+ // internal rrweb stopRecording function
12
+ this._stopRecording = null;
13
+
14
+ this.recEvents = [];
15
+ this.seqNo = 0;
16
+ this.replayId = null;
17
+ this.replayStartTime = null;
18
+ this.batchStartTime = null;
19
+ this.replayLengthMs = 0;
20
+ this.sendBatchId = null;
21
+
22
+ this.idleTimeoutId = null;
23
+ this.maxTimeoutId = null;
24
+
25
+ this.recordMaxMs = MAX_RECORDING_MS;
26
+ };
27
+
28
+ // eslint-disable-next-line camelcase
29
+ MixpanelRecorder.prototype.get_config = function(configVar) {
30
+ return this._mixpanel.get_config(configVar);
31
+ };
32
+
33
+ MixpanelRecorder.prototype.startRecording = function () {
34
+ if (this._stopRecording !== null) {
35
+ logger.log('Recording already in progress, skipping startRecording.');
36
+ return;
37
+ }
38
+
39
+ this.recordMaxMs = this.get_config('record_max_ms');
40
+ if (this.recordMaxMs > MAX_RECORDING_MS) {
41
+ this.recordMaxMs = MAX_RECORDING_MS;
42
+ logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
43
+ }
44
+
45
+ this.recEvents = [];
46
+ this.seqNo = 0;
47
+ this.startDate = new Date();
48
+ this.replayStartTime = this.startDate.getTime();
49
+ this.batchStartTime = this.replayStartTime;
50
+
51
+ this.replayId = _.UUID();
52
+ this.replayLengthMs = 0;
53
+
54
+ var resetIdleTimeout = _.bind(function () {
55
+ clearTimeout(this.idleTimeoutId);
56
+ this.idleTimeoutId = setTimeout(_.bind(function () {
57
+ logger.log('Idle timeout reached, restarting recording.');
58
+ this.resetRecording();
59
+ }, this), this.get_config('record_idle_timeout_ms'));
60
+ }, this);
61
+
62
+ this._stopRecording = record({
63
+ 'emit': _.bind(function (ev) {
64
+ this.recEvents.push(ev);
65
+ this.replayLengthMs = new Date().getTime() - this.replayStartTime;
66
+ resetIdleTimeout();
67
+ }, this),
68
+ 'maskAllInputs': true,
69
+ 'maskTextSelector': this.get_config('record_mask_text_selector'),
70
+ 'blockSelector': this.get_config('record_block_selector'),
71
+ 'maskTextClass': this.get_config('record_mask_text_class'),
72
+ 'blockClass': this.get_config('record_block_class'),
73
+ });
74
+
75
+ resetIdleTimeout();
76
+
77
+ this.sendBatchId = setInterval(_.bind(this.flushEventsWithOptOut, this), 10000);
78
+ this.maxTimeoutId = setTimeout(_.bind(this.resetRecording, this), this.recordMaxMs);
79
+ };
80
+
81
+ MixpanelRecorder.prototype.resetRecording = function () {
82
+ this.stopRecording();
83
+ this.startRecording();
84
+ };
85
+
86
+ MixpanelRecorder.prototype.stopRecording = function () {
87
+ if (this._stopRecording !== null) {
88
+ this._stopRecording();
89
+ this._stopRecording = null;
90
+ }
91
+
92
+ this._flushEvents(); // flush any remaining events
93
+ this.replayId = null;
94
+
95
+ clearInterval(this.sendBatchId);
96
+ clearTimeout(this.idleTimeoutId);
97
+ clearTimeout(this.maxTimeoutId);
98
+ };
99
+
100
+ /**
101
+ * Flushes the current batch of events to the server, but passes an opt-out callback to make sure
102
+ * we stop recording and dump any queued events if the user has opted out.
103
+ */
104
+ MixpanelRecorder.prototype.flushEventsWithOptOut = function () {
105
+ this._flushEvents(_.bind(this._onOptOut, this));
106
+ };
107
+
108
+ MixpanelRecorder.prototype._onOptOut = function (code) {
109
+ // addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
110
+ if (code === 0) {
111
+ this.recEvents = [];
112
+ this.stopRecording();
113
+ }
114
+ };
115
+
116
+ /**
117
+ * @api private
118
+ * Private method, flushes the current batch of events to the server.
119
+ */
120
+ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function() {
121
+ var numEvents = this.recEvents.length;
122
+ if (numEvents > 0) {
123
+ var reqBody = {
124
+ 'distinct_id': String(this._mixpanel.get_distinct_id()),
125
+ 'events': this.recEvents,
126
+ 'seq': this.seqNo++,
127
+ 'batch_start_time': this.batchStartTime / 1000,
128
+ 'replay_id': this.replayId,
129
+ 'replay_length_ms': this.replayLengthMs,
130
+ 'replay_start_time': this.replayStartTime / 1000
131
+ };
132
+
133
+ // send ID management props if they exist
134
+ var deviceId = this._mixpanel.get_property('$device_id');
135
+ if (deviceId) {
136
+ reqBody['$device_id'] = deviceId;
137
+ }
138
+ var userId = this._mixpanel.get_property('$user_id');
139
+ if (userId) {
140
+ reqBody['$user_id'] = userId;
141
+ }
142
+
143
+ window['fetch'](this.get_config('api_host') + '/' + this.get_config('api_routes')['record'], {
144
+ 'method': 'POST',
145
+ 'headers': {
146
+ 'Authorization': 'Basic ' + btoa(this.get_config('token') + ':'),
147
+ 'Content-Type': 'application/json'
148
+ },
149
+ 'body': _.JSONEncode(reqBody)
150
+ });
151
+ this.recEvents = this.recEvents.slice(numEvents);
152
+ this.batchStartTime = new Date().getTime();
153
+ }
154
+ });
155
+
156
+ window['__mp_recorder'] = MixpanelRecorder;
@@ -0,0 +1,19 @@
1
+ import esbuild from 'rollup-plugin-esbuild';
2
+ import { nodeResolve } from '@rollup/plugin-node-resolve';
3
+
4
+ export default {
5
+ input: 'index.js',
6
+ output: [
7
+ {
8
+ file: 'build/mixpanel-recorder.js',
9
+ format: 'esm'
10
+ },
11
+ {
12
+ file: 'build/mixpanel-recorder.min.js',
13
+ format: 'esm',
14
+ name: 'version',
15
+ plugins: [esbuild({minify: true})]
16
+ }
17
+ ],
18
+ plugins: [nodeResolve({browser: true})],
19
+ };
package/src/utils.js CHANGED
@@ -20,6 +20,9 @@ if (typeof(window) === 'undefined') {
20
20
  win = window;
21
21
  }
22
22
 
23
+ // Maximum allowed session recording length
24
+ var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours
25
+
23
26
  /*
24
27
  * Saved references to long variable names, so that closure compiler can
25
28
  * minimize file size.
@@ -1721,6 +1724,7 @@ _['info']['browserVersion'] = _.info.browserVersion;
1721
1724
  _['info']['properties'] = _.info.properties;
1722
1725
 
1723
1726
  export {
1727
+ MAX_RECORDING_MS,
1724
1728
  _,
1725
1729
  userAgent,
1726
1730
  console,