mixpanel-browser 2.48.1 → 2.50.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/.eslintignore +2 -0
- package/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/bower.json +1 -1
- package/build.sh +14 -9
- package/dist/mixpanel-js-wrapper.js +247 -0
- package/dist/mixpanel-js-wrapper.min.js +5 -0
- package/dist/mixpanel-recorder.js +5940 -0
- package/dist/mixpanel-recorder.min.js +24 -0
- package/dist/mixpanel.amd.js +231 -66
- package/dist/mixpanel.cjs.js +230 -65
- package/dist/mixpanel.globals.js +231 -66
- package/dist/mixpanel.min.js +108 -103
- package/dist/mixpanel.umd.js +232 -67
- package/doc/readme.io/javascript-full-api-reference.md +107 -1
- package/package.json +7 -2
- package/src/config.js +1 -1
- package/src/loaders/loader-globals.js +4 -0
- package/src/{loader-module.js → loaders/loader-module.js} +1 -1
- package/src/loaders/mixpanel-js-wrapper.js +143 -0
- package/src/loaders/mixpanel-js-wrapper.md +114 -0
- package/src/mixpanel-core.js +146 -15
- package/src/mixpanel-people.js +0 -1
- package/src/recorder/index.js +153 -0
- package/src/recorder/rollup.config.js +19 -0
- package/src/utils.js +15 -3
- package/src/loader-globals.js +0 -4
- /package/{mixpanel-jslib-snippet.js → src/loaders/mixpanel-jslib-snippet.js} +0 -0
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
|
/*
|
|
@@ -106,10 +107,12 @@ var DEFAULT_CONFIG = {
|
|
|
106
107
|
'cookie_domain': '',
|
|
107
108
|
'cookie_name': '',
|
|
108
109
|
'loaded': NOOP_FUNC,
|
|
110
|
+
'mp_loader': null,
|
|
109
111
|
'track_marketing': true,
|
|
110
112
|
'track_pageview': false,
|
|
111
113
|
'skip_first_touch_marketing': false,
|
|
112
114
|
'store_google': true,
|
|
115
|
+
'stop_utm_persistence': false,
|
|
113
116
|
'save_referrer': true,
|
|
114
117
|
'test': false,
|
|
115
118
|
'verbose': false,
|
|
@@ -134,7 +137,12 @@ var DEFAULT_CONFIG = {
|
|
|
134
137
|
'batch_flush_interval_ms': 5000,
|
|
135
138
|
'batch_request_timeout_ms': 90000,
|
|
136
139
|
'batch_autostart': true,
|
|
137
|
-
'hooks': {}
|
|
140
|
+
'hooks': {},
|
|
141
|
+
'record_sessions_percent': 0,
|
|
142
|
+
'record_idle_timeout_ms': 30 * 60 * 1000, // 30 minutes
|
|
143
|
+
'record_max_ms': MAX_RECORDING_MS,
|
|
144
|
+
'record_mask_text_selector': '*',
|
|
145
|
+
'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js'
|
|
138
146
|
};
|
|
139
147
|
|
|
140
148
|
var DOM_LOADED = false;
|
|
@@ -343,8 +351,44 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
343
351
|
}, '');
|
|
344
352
|
}
|
|
345
353
|
|
|
346
|
-
|
|
347
|
-
|
|
354
|
+
var track_pageview_option = this.get_config('track_pageview');
|
|
355
|
+
if (track_pageview_option) {
|
|
356
|
+
this._init_url_change_tracking(track_pageview_option);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (this.get_config('record_sessions_percent') > 0 && Math.random() * 100 <= this.get_config('record_sessions_percent')) {
|
|
360
|
+
this.start_session_recording();
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
MixpanelLib.prototype.start_session_recording = addOptOutCheckMixpanelLib(function () {
|
|
365
|
+
if (!window['MutationObserver']) {
|
|
366
|
+
console.critical('Browser does not support MutationObserver; skipping session recording');
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
var handleLoadedRecorder = _.bind(function() {
|
|
371
|
+
this._recorder = this._recorder || new window['__mp_recorder'](this);
|
|
372
|
+
this._recorder['startRecording']();
|
|
373
|
+
}, this);
|
|
374
|
+
|
|
375
|
+
if (_.isUndefined(window['__mp_recorder'])) {
|
|
376
|
+
var scriptEl = document.createElement('script');
|
|
377
|
+
scriptEl.type = 'text/javascript';
|
|
378
|
+
scriptEl.async = true;
|
|
379
|
+
scriptEl.onload = handleLoadedRecorder;
|
|
380
|
+
scriptEl.src = this.get_config('recorder_src');
|
|
381
|
+
document.head.appendChild(scriptEl);
|
|
382
|
+
} else {
|
|
383
|
+
handleLoadedRecorder();
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
MixpanelLib.prototype.stop_session_recording = function () {
|
|
388
|
+
if (this._recorder) {
|
|
389
|
+
this._recorder['stopRecording']();
|
|
390
|
+
} else {
|
|
391
|
+
console.critical('Session recorder module not loaded');
|
|
348
392
|
}
|
|
349
393
|
};
|
|
350
394
|
|
|
@@ -353,12 +397,25 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
353
397
|
MixpanelLib.prototype._loaded = function() {
|
|
354
398
|
this.get_config('loaded')(this);
|
|
355
399
|
this._set_default_superprops();
|
|
400
|
+
this['people'].set_once(this['persistence'].get_referrer_info());
|
|
401
|
+
|
|
402
|
+
// The original 'store_google' functionality will be deprecated and the config will be
|
|
403
|
+
// used to clear previously managed UTM parameters from persistence.
|
|
404
|
+
// stop_utm_persistence is `false` by default now but will be default `true` in the future.
|
|
405
|
+
if (this.get_config('store_google') && this.get_config('stop_utm_persistence')) {
|
|
406
|
+
var utm_params = _.info.campaignParams(null);
|
|
407
|
+
_.each(utm_params, function(_utm_value, utm_key) {
|
|
408
|
+
// We need to unregister persisted UTM parameters so old values
|
|
409
|
+
// are not mixed with the new UTM parameters
|
|
410
|
+
this.unregister(utm_key);
|
|
411
|
+
}.bind(this));
|
|
412
|
+
}
|
|
356
413
|
};
|
|
357
414
|
|
|
358
415
|
// update persistence with info on referrer, UTM params, etc
|
|
359
416
|
MixpanelLib.prototype._set_default_superprops = function() {
|
|
360
417
|
this['persistence'].update_search_keyword(document.referrer);
|
|
361
|
-
if (this.get_config('store_google')) {
|
|
418
|
+
if (this.get_config('store_google') && !this.get_config('stop_utm_persistence')) {
|
|
362
419
|
this.register(_.info.campaignParams());
|
|
363
420
|
}
|
|
364
421
|
if (this.get_config('save_referrer')) {
|
|
@@ -396,6 +453,55 @@ MixpanelLib.prototype._track_dom = function(DomClass, args) {
|
|
|
396
453
|
return dt.track.apply(dt, args);
|
|
397
454
|
};
|
|
398
455
|
|
|
456
|
+
MixpanelLib.prototype._init_url_change_tracking = function(track_pageview_option) {
|
|
457
|
+
var previous_tracked_url = '';
|
|
458
|
+
var tracked = this.track_pageview();
|
|
459
|
+
if (tracked) {
|
|
460
|
+
previous_tracked_url = _.info.currentUrl();
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (_.include(['full-url', 'url-with-path-and-query-string', 'url-with-path'], track_pageview_option)) {
|
|
464
|
+
window.addEventListener('popstate', function() {
|
|
465
|
+
window.dispatchEvent(new Event('mp_locationchange'));
|
|
466
|
+
});
|
|
467
|
+
window.addEventListener('hashchange', function() {
|
|
468
|
+
window.dispatchEvent(new Event('mp_locationchange'));
|
|
469
|
+
});
|
|
470
|
+
var nativePushState = window.history.pushState;
|
|
471
|
+
if (typeof nativePushState === 'function') {
|
|
472
|
+
window.history.pushState = function(state, unused, url) {
|
|
473
|
+
nativePushState.call(window.history, state, unused, url);
|
|
474
|
+
window.dispatchEvent(new Event('mp_locationchange'));
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
var nativeReplaceState = window.history.replaceState;
|
|
478
|
+
if (typeof nativeReplaceState === 'function') {
|
|
479
|
+
window.history.replaceState = function(state, unused, url) {
|
|
480
|
+
nativeReplaceState.call(window.history, state, unused, url);
|
|
481
|
+
window.dispatchEvent(new Event('mp_locationchange'));
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
window.addEventListener('mp_locationchange', function() {
|
|
485
|
+
var current_url = _.info.currentUrl();
|
|
486
|
+
var should_track = false;
|
|
487
|
+
if (track_pageview_option === 'full-url') {
|
|
488
|
+
should_track = current_url !== previous_tracked_url;
|
|
489
|
+
} else if (track_pageview_option === 'url-with-path-and-query-string') {
|
|
490
|
+
should_track = current_url.split('#')[0] !== previous_tracked_url.split('#')[0];
|
|
491
|
+
} else if (track_pageview_option === 'url-with-path') {
|
|
492
|
+
should_track = current_url.split('#')[0].split('?')[0] !== previous_tracked_url.split('#')[0].split('?')[0];
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (should_track) {
|
|
496
|
+
var tracked = this.track_pageview();
|
|
497
|
+
if (tracked) {
|
|
498
|
+
previous_tracked_url = current_url;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}.bind(this));
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
|
|
399
505
|
/**
|
|
400
506
|
* _prepare_callback() should be called by callers of _send_request for use
|
|
401
507
|
* as the callback argument.
|
|
@@ -857,6 +963,13 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro
|
|
|
857
963
|
? _.info.marketingParams()
|
|
858
964
|
: {};
|
|
859
965
|
|
|
966
|
+
if (this._recorder) {
|
|
967
|
+
var replay_id = this._recorder['replayId'];
|
|
968
|
+
if (replay_id) {
|
|
969
|
+
properties['$mp_replay_id'] = replay_id;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
|
|
860
973
|
// note: extend writes to the first object, so lets make sure we
|
|
861
974
|
// don't write to the persistence properties object and info
|
|
862
975
|
// properties object by passing in a new object
|
|
@@ -864,7 +977,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro
|
|
|
864
977
|
// update properties with pageview info and super-properties
|
|
865
978
|
properties = _.extend(
|
|
866
979
|
{},
|
|
867
|
-
_.info.properties(),
|
|
980
|
+
_.info.properties({'mp_loader': this.get_config('mp_loader')}),
|
|
868
981
|
marketing_properties,
|
|
869
982
|
this['persistence'].properties(),
|
|
870
983
|
this.unpersisted_superprops,
|
|
@@ -1028,10 +1141,9 @@ MixpanelLib.prototype.get_group = function (group_key, group_id) {
|
|
|
1028
1141
|
|
|
1029
1142
|
/**
|
|
1030
1143
|
* Track a default Mixpanel page view event, which includes extra default event properties to
|
|
1031
|
-
* improve page view data.
|
|
1032
|
-
* may be turned on for tracking page loads automatically.
|
|
1144
|
+
* improve page view data.
|
|
1033
1145
|
*
|
|
1034
|
-
* ### Usage
|
|
1146
|
+
* ### Usage:
|
|
1035
1147
|
*
|
|
1036
1148
|
* // track a default $mp_web_page_view event
|
|
1037
1149
|
* mixpanel.track_pageview();
|
|
@@ -1048,6 +1160,23 @@ MixpanelLib.prototype.get_group = function (group_key, group_id) {
|
|
|
1048
1160
|
* // views on different products or internal applications that are considered completely separate
|
|
1049
1161
|
* mixpanel.track_pageview({'page': 'customer-search'}, {'event_name': '[internal] Admin Page View'});
|
|
1050
1162
|
*
|
|
1163
|
+
* ### Notes:
|
|
1164
|
+
*
|
|
1165
|
+
* The `config.track_pageview` option for <a href="#mixpanelinit">mixpanel.init()</a>
|
|
1166
|
+
* may be turned on for tracking page loads automatically.
|
|
1167
|
+
*
|
|
1168
|
+
* // track only page loads
|
|
1169
|
+
* mixpanel.init(PROJECT_TOKEN, {track_pageview: true});
|
|
1170
|
+
*
|
|
1171
|
+
* // track when the URL changes in any manner
|
|
1172
|
+
* mixpanel.init(PROJECT_TOKEN, {track_pageview: 'full-url'});
|
|
1173
|
+
*
|
|
1174
|
+
* // track when the URL changes, ignoring any changes in the hash part
|
|
1175
|
+
* mixpanel.init(PROJECT_TOKEN, {track_pageview: 'url-with-path-and-query-string'});
|
|
1176
|
+
*
|
|
1177
|
+
* // track when the path changes, ignoring any query parameter or hash changes
|
|
1178
|
+
* mixpanel.init(PROJECT_TOKEN, {track_pageview: 'url-with-path'});
|
|
1179
|
+
*
|
|
1051
1180
|
* @param {Object} [properties] An optional set of additional properties to send with the page view event
|
|
1052
1181
|
* @param {Object} [options] Page view tracking options
|
|
1053
1182
|
* @param {String} [options.event_name] - Alternate name for the tracking event
|
|
@@ -1798,7 +1927,7 @@ MixpanelLib.prototype._gdpr_call_func = function(func, options) {
|
|
|
1798
1927
|
/**
|
|
1799
1928
|
* Opt the user in to data tracking and cookies/localstorage for this Mixpanel instance
|
|
1800
1929
|
*
|
|
1801
|
-
* ### Usage
|
|
1930
|
+
* ### Usage:
|
|
1802
1931
|
*
|
|
1803
1932
|
* // opt user in
|
|
1804
1933
|
* mixpanel.opt_in_tracking();
|
|
@@ -1838,7 +1967,7 @@ MixpanelLib.prototype.opt_in_tracking = function(options) {
|
|
|
1838
1967
|
/**
|
|
1839
1968
|
* Opt the user out of data tracking and cookies/localstorage for this Mixpanel instance
|
|
1840
1969
|
*
|
|
1841
|
-
* ### Usage
|
|
1970
|
+
* ### Usage:
|
|
1842
1971
|
*
|
|
1843
1972
|
* // opt user out
|
|
1844
1973
|
* mixpanel.opt_out_tracking();
|
|
@@ -1879,7 +2008,7 @@ MixpanelLib.prototype.opt_out_tracking = function(options) {
|
|
|
1879
2008
|
/**
|
|
1880
2009
|
* Check whether the user has opted in to data tracking and cookies/localstorage for this Mixpanel instance
|
|
1881
2010
|
*
|
|
1882
|
-
* ### Usage
|
|
2011
|
+
* ### Usage:
|
|
1883
2012
|
*
|
|
1884
2013
|
* var has_opted_in = mixpanel.has_opted_in_tracking();
|
|
1885
2014
|
* // use has_opted_in value
|
|
@@ -1896,7 +2025,7 @@ MixpanelLib.prototype.has_opted_in_tracking = function(options) {
|
|
|
1896
2025
|
/**
|
|
1897
2026
|
* Check whether the user has opted out of data tracking and cookies/localstorage for this Mixpanel instance
|
|
1898
2027
|
*
|
|
1899
|
-
* ### Usage
|
|
2028
|
+
* ### Usage:
|
|
1900
2029
|
*
|
|
1901
2030
|
* var has_opted_out = mixpanel.has_opted_out_tracking();
|
|
1902
2031
|
* // use has_opted_out value
|
|
@@ -1913,7 +2042,7 @@ MixpanelLib.prototype.has_opted_out_tracking = function(options) {
|
|
|
1913
2042
|
/**
|
|
1914
2043
|
* Clear the user's opt in/out status of data tracking and cookies/localstorage for this Mixpanel instance
|
|
1915
2044
|
*
|
|
1916
|
-
* ### Usage
|
|
2045
|
+
* ### Usage:
|
|
1917
2046
|
*
|
|
1918
2047
|
* // clear user's opt-in/out status
|
|
1919
2048
|
* mixpanel.clear_opt_in_out_tracking();
|
|
@@ -1990,6 +2119,8 @@ MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remov
|
|
|
1990
2119
|
MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups;
|
|
1991
2120
|
MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders;
|
|
1992
2121
|
MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders;
|
|
2122
|
+
MixpanelLib.prototype['start_session_recording'] = MixpanelLib.prototype.start_session_recording;
|
|
2123
|
+
MixpanelLib.prototype['stop_session_recording'] = MixpanelLib.prototype.stop_session_recording;
|
|
1993
2124
|
MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES;
|
|
1994
2125
|
|
|
1995
2126
|
// MixpanelPersistence Exports
|
package/src/mixpanel-people.js
CHANGED
|
@@ -57,7 +57,6 @@ MixpanelPeople.prototype.set = addOptOutCheckMixpanelPeople(function(prop, to, c
|
|
|
57
57
|
data[SET_ACTION] = _.extend(
|
|
58
58
|
{},
|
|
59
59
|
_.info.people_properties(),
|
|
60
|
-
this._mixpanel['persistence'].get_referrer_info(),
|
|
61
60
|
data[SET_ACTION]
|
|
62
61
|
);
|
|
63
62
|
return this._send_request(data, callback);
|
|
@@ -0,0 +1,153 @@
|
|
|
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
|
+
});
|
|
71
|
+
|
|
72
|
+
resetIdleTimeout();
|
|
73
|
+
|
|
74
|
+
this.sendBatchId = setInterval(_.bind(this.flushEventsWithOptOut, this), 10000);
|
|
75
|
+
this.maxTimeoutId = setTimeout(_.bind(this.resetRecording, this), this.recordMaxMs);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
MixpanelRecorder.prototype.resetRecording = function () {
|
|
79
|
+
this.stopRecording();
|
|
80
|
+
this.startRecording();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
MixpanelRecorder.prototype.stopRecording = function () {
|
|
84
|
+
if (this._stopRecording !== null) {
|
|
85
|
+
this._stopRecording();
|
|
86
|
+
this._stopRecording = null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this._flushEvents(); // flush any remaining events
|
|
90
|
+
this.replayId = null;
|
|
91
|
+
|
|
92
|
+
clearInterval(this.sendBatchId);
|
|
93
|
+
clearTimeout(this.idleTimeoutId);
|
|
94
|
+
clearTimeout(this.maxTimeoutId);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Flushes the current batch of events to the server, but passes an opt-out callback to make sure
|
|
99
|
+
* we stop recording and dump any queued events if the user has opted out.
|
|
100
|
+
*/
|
|
101
|
+
MixpanelRecorder.prototype.flushEventsWithOptOut = function () {
|
|
102
|
+
this._flushEvents(_.bind(this._onOptOut, this));
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
MixpanelRecorder.prototype._onOptOut = function (code) {
|
|
106
|
+
// addOptOutCheckMixpanelLib invokes this function with code=0 when the user has opted out
|
|
107
|
+
if (code === 0) {
|
|
108
|
+
this.recEvents = [];
|
|
109
|
+
this.stopRecording();
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @api private
|
|
115
|
+
* Private method, flushes the current batch of events to the server.
|
|
116
|
+
*/
|
|
117
|
+
MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function() {
|
|
118
|
+
var numEvents = this.recEvents.length;
|
|
119
|
+
if (numEvents > 0) {
|
|
120
|
+
var reqBody = {
|
|
121
|
+
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
122
|
+
'events': this.recEvents,
|
|
123
|
+
'seq': this.seqNo++,
|
|
124
|
+
'batch_start_time': this.batchStartTime / 1000,
|
|
125
|
+
'replay_id': this.replayId,
|
|
126
|
+
'replay_length_ms': this.replayLengthMs,
|
|
127
|
+
'replay_start_time': this.replayStartTime / 1000
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// send ID management props if they exist
|
|
131
|
+
var deviceId = this._mixpanel.get_property('$device_id');
|
|
132
|
+
if (deviceId) {
|
|
133
|
+
reqBody['$device_id'] = deviceId;
|
|
134
|
+
}
|
|
135
|
+
var userId = this._mixpanel.get_property('$user_id');
|
|
136
|
+
if (userId) {
|
|
137
|
+
reqBody['$user_id'] = userId;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
window['fetch'](this.get_config('api_host') + '/' + this.get_config('api_routes')['record'], {
|
|
141
|
+
'method': 'POST',
|
|
142
|
+
'headers': {
|
|
143
|
+
'Authorization': 'Basic ' + btoa(this.get_config('token') + ':'),
|
|
144
|
+
'Content-Type': 'application/json'
|
|
145
|
+
},
|
|
146
|
+
'body': _.JSONEncode(reqBody)
|
|
147
|
+
});
|
|
148
|
+
this.recEvents = this.recEvents.slice(numEvents);
|
|
149
|
+
this.batchStartTime = new Date().getTime();
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
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.
|
|
@@ -899,6 +902,7 @@ _.UUID = (function() {
|
|
|
899
902
|
// sending false tracking data
|
|
900
903
|
var BLOCKED_UA_STRS = [
|
|
901
904
|
'ahrefsbot',
|
|
905
|
+
'ahrefssiteaudit',
|
|
902
906
|
'baiduspider',
|
|
903
907
|
'bingbot',
|
|
904
908
|
'bingpreview',
|
|
@@ -1619,7 +1623,14 @@ _.info = {
|
|
|
1619
1623
|
return '';
|
|
1620
1624
|
},
|
|
1621
1625
|
|
|
1622
|
-
|
|
1626
|
+
currentUrl: function() {
|
|
1627
|
+
return win.location.href;
|
|
1628
|
+
},
|
|
1629
|
+
|
|
1630
|
+
properties: function(extra_props) {
|
|
1631
|
+
if (typeof extra_props !== 'object') {
|
|
1632
|
+
extra_props = {};
|
|
1633
|
+
}
|
|
1623
1634
|
return _.extend(_.strip_empty_properties({
|
|
1624
1635
|
'$os': _.info.os(),
|
|
1625
1636
|
'$browser': _.info.browser(userAgent, navigator.vendor, windowOpera),
|
|
@@ -1627,7 +1638,7 @@ _.info = {
|
|
|
1627
1638
|
'$referring_domain': _.info.referringDomain(document.referrer),
|
|
1628
1639
|
'$device': _.info.device(userAgent)
|
|
1629
1640
|
}), {
|
|
1630
|
-
'$current_url':
|
|
1641
|
+
'$current_url': _.info.currentUrl(),
|
|
1631
1642
|
'$browser_version': _.info.browserVersion(userAgent, navigator.vendor, windowOpera),
|
|
1632
1643
|
'$screen_height': screen.height,
|
|
1633
1644
|
'$screen_width': screen.width,
|
|
@@ -1635,7 +1646,7 @@ _.info = {
|
|
|
1635
1646
|
'$lib_version': Config.LIB_VERSION,
|
|
1636
1647
|
'$insert_id': cheap_guid(),
|
|
1637
1648
|
'time': _.timestamp() / 1000 // epoch time in seconds
|
|
1638
|
-
});
|
|
1649
|
+
}, _.strip_empty_properties(extra_props));
|
|
1639
1650
|
},
|
|
1640
1651
|
|
|
1641
1652
|
people_properties: function() {
|
|
@@ -1713,6 +1724,7 @@ _['info']['browserVersion'] = _.info.browserVersion;
|
|
|
1713
1724
|
_['info']['properties'] = _.info.properties;
|
|
1714
1725
|
|
|
1715
1726
|
export {
|
|
1727
|
+
MAX_RECORDING_MS,
|
|
1716
1728
|
_,
|
|
1717
1729
|
userAgent,
|
|
1718
1730
|
console,
|
package/src/loader-globals.js
DELETED
|
File without changes
|