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.
- package/.github/workflows/tests.yml +9 -10
- package/build.sh +2 -1
- package/dist/mixpanel-js-wrapper.js +3 -3
- package/dist/mixpanel-js-wrapper.min.js +1 -1
- package/dist/mixpanel-jslib-snippet.min.js +1 -1
- package/dist/mixpanel-jslib-snippet.min.test.js +1 -1
- package/dist/mixpanel-recorder.js +6499 -0
- package/dist/mixpanel-recorder.min.js +38 -0
- package/dist/mixpanel.amd.js +200 -143
- package/dist/mixpanel.cjs.js +199 -142
- package/dist/mixpanel.globals.js +200 -143
- package/dist/mixpanel.min.js +110 -108
- package/dist/mixpanel.umd.js +201 -144
- package/package.json +7 -2
- package/src/config.js +1 -1
- package/src/loaders/mixpanel-jslib-snippet.js +1 -1
- package/src/mixpanel-core.js +98 -39
- package/src/mixpanel-persistence.js +14 -43
- package/src/recorder/index.js +156 -0
- package/src/recorder/rollup.config.js +19 -0
- package/src/utils.js +4 -0
|
@@ -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
|
}
|
package/src/mixpanel-core.js
CHANGED
|
@@ -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':
|
|
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
|
-
//
|
|
362
|
-
//
|
|
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']
|
|
2044
|
-
MixpanelLib.prototype['reset']
|
|
2045
|
-
MixpanelLib.prototype['disable']
|
|
2046
|
-
MixpanelLib.prototype['time_event']
|
|
2047
|
-
MixpanelLib.prototype['track']
|
|
2048
|
-
MixpanelLib.prototype['track_links']
|
|
2049
|
-
MixpanelLib.prototype['track_forms']
|
|
2050
|
-
MixpanelLib.prototype['track_pageview']
|
|
2051
|
-
MixpanelLib.prototype['register']
|
|
2052
|
-
MixpanelLib.prototype['register_once']
|
|
2053
|
-
MixpanelLib.prototype['unregister']
|
|
2054
|
-
MixpanelLib.prototype['identify']
|
|
2055
|
-
MixpanelLib.prototype['alias']
|
|
2056
|
-
MixpanelLib.prototype['name_tag']
|
|
2057
|
-
MixpanelLib.prototype['set_config']
|
|
2058
|
-
MixpanelLib.prototype['get_config']
|
|
2059
|
-
MixpanelLib.prototype['get_property']
|
|
2060
|
-
MixpanelLib.prototype['get_distinct_id']
|
|
2061
|
-
MixpanelLib.prototype['toString']
|
|
2062
|
-
MixpanelLib.prototype['opt_out_tracking']
|
|
2063
|
-
MixpanelLib.prototype['opt_in_tracking']
|
|
2064
|
-
MixpanelLib.prototype['has_opted_out_tracking']
|
|
2065
|
-
MixpanelLib.prototype['has_opted_in_tracking']
|
|
2066
|
-
MixpanelLib.prototype['clear_opt_in_out_tracking']
|
|
2067
|
-
MixpanelLib.prototype['get_group']
|
|
2068
|
-
MixpanelLib.prototype['set_group']
|
|
2069
|
-
MixpanelLib.prototype['add_group']
|
|
2070
|
-
MixpanelLib.prototype['remove_group']
|
|
2071
|
-
MixpanelLib.prototype['track_with_groups']
|
|
2072
|
-
MixpanelLib.prototype['start_batch_senders']
|
|
2073
|
-
MixpanelLib.prototype['stop_batch_senders']
|
|
2074
|
-
MixpanelLib.prototype['
|
|
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(
|
|
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(
|
|
98
|
-
var
|
|
99
|
-
|
|
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,
|