mixpanel-browser 2.54.1 → 2.55.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/CHANGELOG.md +9 -0
- package/README.md +20 -29
- package/build.sh +1 -0
- package/dist/mixpanel-core.cjs.js +21 -6
- package/dist/mixpanel-recorder.js +55 -19
- package/dist/mixpanel-recorder.min.js +9 -9
- package/dist/mixpanel-with-async-recorder.cjs.js +21 -6
- package/dist/mixpanel.amd.js +56 -19
- package/dist/mixpanel.cjs.js +56 -19
- package/dist/mixpanel.globals.js +21 -6
- package/dist/mixpanel.min.js +98 -97
- package/dist/mixpanel.module.js +11168 -0
- package/dist/mixpanel.umd.js +56 -19
- package/package.json +2 -1
- package/src/config.js +1 -1
- package/src/mixpanel-core.js +1 -0
- package/src/recorder/index.js +34 -14
- package/src/request-batcher.js +7 -2
- package/src/utils.js +26 -13
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
5
|
+
LIB_VERSION: '2.55.1'
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -14,7 +14,7 @@ if (typeof(window) === 'undefined') {
|
|
|
14
14
|
hostname: ''
|
|
15
15
|
};
|
|
16
16
|
win = {
|
|
17
|
-
navigator: { userAgent: '' },
|
|
17
|
+
navigator: { userAgent: '', onLine: true },
|
|
18
18
|
document: {
|
|
19
19
|
location: loc,
|
|
20
20
|
referrer: ''
|
|
@@ -968,7 +968,7 @@ _.HTTPBuildQuery = function(formdata, arg_separator) {
|
|
|
968
968
|
_.getQueryParam = function(url, param) {
|
|
969
969
|
// Expects a raw URL
|
|
970
970
|
|
|
971
|
-
param = param.replace(/[[]
|
|
971
|
+
param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]');
|
|
972
972
|
var regexS = '[\\?&]' + param + '=([^&#]*)',
|
|
973
973
|
regex = new RegExp(regexS),
|
|
974
974
|
results = regex.exec(url);
|
|
@@ -1425,8 +1425,8 @@ _.dom_query = (function() {
|
|
|
1425
1425
|
};
|
|
1426
1426
|
})();
|
|
1427
1427
|
|
|
1428
|
-
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
|
|
1429
|
-
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid'];
|
|
1428
|
+
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic'];
|
|
1429
|
+
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid'];
|
|
1430
1430
|
|
|
1431
1431
|
_.info = {
|
|
1432
1432
|
campaignParams: function(default_value) {
|
|
@@ -1708,6 +1708,15 @@ var extract_domain = function(hostname) {
|
|
|
1708
1708
|
return matches ? matches[0] : '';
|
|
1709
1709
|
};
|
|
1710
1710
|
|
|
1711
|
+
/**
|
|
1712
|
+
* Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE)
|
|
1713
|
+
* @returns {boolean}
|
|
1714
|
+
*/
|
|
1715
|
+
var isOnline = function() {
|
|
1716
|
+
var onLine = win.navigator['onLine'];
|
|
1717
|
+
return _.isUndefined(onLine) || onLine;
|
|
1718
|
+
};
|
|
1719
|
+
|
|
1711
1720
|
var JSONStringify = null, JSONParse = null;
|
|
1712
1721
|
if (typeof JSON !== 'undefined') {
|
|
1713
1722
|
JSONStringify = JSON.stringify;
|
|
@@ -2523,7 +2532,12 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
2523
2532
|
this.flush();
|
|
2524
2533
|
} else if (
|
|
2525
2534
|
_.isObject(res) &&
|
|
2526
|
-
(
|
|
2535
|
+
(
|
|
2536
|
+
res.httpStatusCode >= 500
|
|
2537
|
+
|| res.httpStatusCode === 429
|
|
2538
|
+
|| (res.httpStatusCode <= 0 && !isOnline())
|
|
2539
|
+
|| res.error === 'timeout'
|
|
2540
|
+
)
|
|
2527
2541
|
) {
|
|
2528
2542
|
// network or API error, or 429 Too Many Requests, retry
|
|
2529
2543
|
var retryMS = this.flushInterval * 2;
|
|
@@ -4247,6 +4261,7 @@ var DEFAULT_CONFIG = {
|
|
|
4247
4261
|
'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
|
|
4248
4262
|
'record_mask_text_selector': '*',
|
|
4249
4263
|
'record_max_ms': MAX_RECORDING_MS,
|
|
4264
|
+
'record_min_ms': 0,
|
|
4250
4265
|
'record_sessions_percent': 0,
|
|
4251
4266
|
'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js'
|
|
4252
4267
|
};
|
package/dist/mixpanel.amd.js
CHANGED
|
@@ -4509,7 +4509,7 @@ define((function () { 'use strict';
|
|
|
4509
4509
|
|
|
4510
4510
|
var Config = {
|
|
4511
4511
|
DEBUG: false,
|
|
4512
|
-
LIB_VERSION: '2.
|
|
4512
|
+
LIB_VERSION: '2.55.1'
|
|
4513
4513
|
};
|
|
4514
4514
|
|
|
4515
4515
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -4521,7 +4521,7 @@ define((function () { 'use strict';
|
|
|
4521
4521
|
hostname: ''
|
|
4522
4522
|
};
|
|
4523
4523
|
win = {
|
|
4524
|
-
navigator: { userAgent: '' },
|
|
4524
|
+
navigator: { userAgent: '', onLine: true },
|
|
4525
4525
|
document: {
|
|
4526
4526
|
location: loc,
|
|
4527
4527
|
referrer: ''
|
|
@@ -4535,6 +4535,8 @@ define((function () { 'use strict';
|
|
|
4535
4535
|
|
|
4536
4536
|
// Maximum allowed session recording length
|
|
4537
4537
|
var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
4538
|
+
// Maximum allowed value for minimum session recording length
|
|
4539
|
+
var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds
|
|
4538
4540
|
|
|
4539
4541
|
/*
|
|
4540
4542
|
* Saved references to long variable names, so that closure compiler can
|
|
@@ -5475,7 +5477,7 @@ define((function () { 'use strict';
|
|
|
5475
5477
|
_.getQueryParam = function(url, param) {
|
|
5476
5478
|
// Expects a raw URL
|
|
5477
5479
|
|
|
5478
|
-
param = param.replace(/[[]
|
|
5480
|
+
param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]');
|
|
5479
5481
|
var regexS = '[\\?&]' + param + '=([^&#]*)',
|
|
5480
5482
|
regex = new RegExp(regexS),
|
|
5481
5483
|
results = regex.exec(url);
|
|
@@ -5932,8 +5934,8 @@ define((function () { 'use strict';
|
|
|
5932
5934
|
};
|
|
5933
5935
|
})();
|
|
5934
5936
|
|
|
5935
|
-
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
|
|
5936
|
-
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid'];
|
|
5937
|
+
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic'];
|
|
5938
|
+
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid'];
|
|
5937
5939
|
|
|
5938
5940
|
_.info = {
|
|
5939
5941
|
campaignParams: function(default_value) {
|
|
@@ -6215,6 +6217,15 @@ define((function () { 'use strict';
|
|
|
6215
6217
|
return matches ? matches[0] : '';
|
|
6216
6218
|
};
|
|
6217
6219
|
|
|
6220
|
+
/**
|
|
6221
|
+
* Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE)
|
|
6222
|
+
* @returns {boolean}
|
|
6223
|
+
*/
|
|
6224
|
+
var isOnline = function() {
|
|
6225
|
+
var onLine = win.navigator['onLine'];
|
|
6226
|
+
return _.isUndefined(onLine) || onLine;
|
|
6227
|
+
};
|
|
6228
|
+
|
|
6218
6229
|
var JSONStringify = null, JSONParse = null;
|
|
6219
6230
|
if (typeof JSON !== 'undefined') {
|
|
6220
6231
|
JSONStringify = JSON.stringify;
|
|
@@ -7178,7 +7189,12 @@ define((function () { 'use strict';
|
|
|
7178
7189
|
this.flush();
|
|
7179
7190
|
} else if (
|
|
7180
7191
|
_.isObject(res) &&
|
|
7181
|
-
(
|
|
7192
|
+
(
|
|
7193
|
+
res.httpStatusCode >= 500
|
|
7194
|
+
|| res.httpStatusCode === 429
|
|
7195
|
+
|| (res.httpStatusCode <= 0 && !isOnline())
|
|
7196
|
+
|| res.error === 'timeout'
|
|
7197
|
+
)
|
|
7182
7198
|
) {
|
|
7183
7199
|
// network or API error, or 429 Too Many Requests, retry
|
|
7184
7200
|
var retryMS = this.flushInterval * 2;
|
|
@@ -7329,6 +7345,7 @@ define((function () { 'use strict';
|
|
|
7329
7345
|
this.maxTimeoutId = null;
|
|
7330
7346
|
|
|
7331
7347
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
7348
|
+
this.recordMinMs = 0;
|
|
7332
7349
|
this._initBatcher();
|
|
7333
7350
|
};
|
|
7334
7351
|
|
|
@@ -7360,16 +7377,24 @@ define((function () { 'use strict';
|
|
|
7360
7377
|
logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
7361
7378
|
}
|
|
7362
7379
|
|
|
7380
|
+
this.recordMinMs = this.get_config('record_min_ms');
|
|
7381
|
+
if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
7382
|
+
this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
7383
|
+
logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
7384
|
+
}
|
|
7385
|
+
|
|
7363
7386
|
this.recEvents = [];
|
|
7364
7387
|
this.seqNo = 0;
|
|
7365
|
-
this.replayStartTime =
|
|
7388
|
+
this.replayStartTime = new Date().getTime();
|
|
7366
7389
|
|
|
7367
7390
|
this.replayId = _.UUID();
|
|
7368
7391
|
|
|
7369
|
-
if (shouldStopBatcher) {
|
|
7370
|
-
//
|
|
7392
|
+
if (shouldStopBatcher || this.recordMinMs > 0) {
|
|
7393
|
+
// the primary case for shouldStopBatcher is when we're starting recording after a reset
|
|
7371
7394
|
// and don't want to send anything over the network until there's
|
|
7372
7395
|
// actual user activity
|
|
7396
|
+
// this also applies if the minimum recording length has not been hit yet
|
|
7397
|
+
// so that we don't send data until we know the recording will be long enough
|
|
7373
7398
|
this.batcher.stop();
|
|
7374
7399
|
} else {
|
|
7375
7400
|
this.batcher.start();
|
|
@@ -7383,11 +7408,16 @@ define((function () { 'use strict';
|
|
|
7383
7408
|
}, this), this.get_config('record_idle_timeout_ms'));
|
|
7384
7409
|
}, this);
|
|
7385
7410
|
|
|
7411
|
+
var blockSelector = this.get_config('record_block_selector');
|
|
7412
|
+
if (blockSelector === '' || blockSelector === null) {
|
|
7413
|
+
blockSelector = undefined;
|
|
7414
|
+
}
|
|
7415
|
+
|
|
7386
7416
|
this._stopRecording = record({
|
|
7387
7417
|
'emit': _.bind(function (ev) {
|
|
7388
7418
|
this.batcher.enqueue(ev);
|
|
7389
7419
|
if (isUserEvent(ev)) {
|
|
7390
|
-
if (this.batcher.stopped) {
|
|
7420
|
+
if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
|
|
7391
7421
|
// start flushing again after user activity
|
|
7392
7422
|
this.batcher.start();
|
|
7393
7423
|
}
|
|
@@ -7395,7 +7425,7 @@ define((function () { 'use strict';
|
|
|
7395
7425
|
}
|
|
7396
7426
|
}, this),
|
|
7397
7427
|
'blockClass': this.get_config('record_block_class'),
|
|
7398
|
-
'blockSelector':
|
|
7428
|
+
'blockSelector': blockSelector,
|
|
7399
7429
|
'collectFonts': this.get_config('record_collect_fonts'),
|
|
7400
7430
|
'inlineImages': this.get_config('record_inline_images'),
|
|
7401
7431
|
'maskAllInputs': true,
|
|
@@ -7449,14 +7479,14 @@ define((function () { 'use strict';
|
|
|
7449
7479
|
}
|
|
7450
7480
|
};
|
|
7451
7481
|
|
|
7452
|
-
MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) {
|
|
7482
|
+
MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
|
|
7453
7483
|
var onSuccess = _.bind(function (response, responseBody) {
|
|
7454
7484
|
// Increment sequence counter only if the request was successful to guarantee ordering.
|
|
7455
7485
|
// RequestBatcher will always flush the next batch after the previous one succeeds.
|
|
7456
|
-
if
|
|
7486
|
+
// extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay
|
|
7487
|
+
if (response.status === 200 && this.replayId === currentReplayId) {
|
|
7457
7488
|
this.seqNo++;
|
|
7458
7489
|
}
|
|
7459
|
-
|
|
7460
7490
|
callback({
|
|
7461
7491
|
status: 0,
|
|
7462
7492
|
httpStatusCode: response.status,
|
|
@@ -7479,7 +7509,7 @@ define((function () { 'use strict';
|
|
|
7479
7509
|
callback({error: error});
|
|
7480
7510
|
});
|
|
7481
7511
|
}).catch(function (error) {
|
|
7482
|
-
callback({error: error});
|
|
7512
|
+
callback({error: error, httpStatusCode: 0});
|
|
7483
7513
|
});
|
|
7484
7514
|
};
|
|
7485
7515
|
|
|
@@ -7487,9 +7517,15 @@ define((function () { 'use strict';
|
|
|
7487
7517
|
const numEvents = data.length;
|
|
7488
7518
|
|
|
7489
7519
|
if (numEvents > 0) {
|
|
7520
|
+
var replayId = this.replayId;
|
|
7490
7521
|
// each rrweb event has a timestamp - leverage those to get time properties
|
|
7491
7522
|
var batchStartTime = data[0].timestamp;
|
|
7492
|
-
if (this.seqNo === 0) {
|
|
7523
|
+
if (this.seqNo === 0 || !this.replayStartTime) {
|
|
7524
|
+
// extra safety net so that we don't send a null replay start time
|
|
7525
|
+
if (this.seqNo !== 0) {
|
|
7526
|
+
this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
|
|
7527
|
+
}
|
|
7528
|
+
|
|
7493
7529
|
this.replayStartTime = batchStartTime;
|
|
7494
7530
|
}
|
|
7495
7531
|
var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime;
|
|
@@ -7498,7 +7534,7 @@ define((function () { 'use strict';
|
|
|
7498
7534
|
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
7499
7535
|
'seq': this.seqNo,
|
|
7500
7536
|
'batch_start_time': batchStartTime / 1000,
|
|
7501
|
-
'replay_id':
|
|
7537
|
+
'replay_id': replayId,
|
|
7502
7538
|
'replay_length_ms': replayLengthMs,
|
|
7503
7539
|
'replay_start_time': this.replayStartTime / 1000
|
|
7504
7540
|
};
|
|
@@ -7521,11 +7557,11 @@ define((function () { 'use strict';
|
|
|
7521
7557
|
.blob()
|
|
7522
7558
|
.then(_.bind(function(compressedBlob) {
|
|
7523
7559
|
reqParams['format'] = 'gzip';
|
|
7524
|
-
this._sendRequest(reqParams, compressedBlob, callback);
|
|
7560
|
+
this._sendRequest(replayId, reqParams, compressedBlob, callback);
|
|
7525
7561
|
}, this));
|
|
7526
7562
|
} else {
|
|
7527
7563
|
reqParams['format'] = 'body';
|
|
7528
|
-
this._sendRequest(reqParams, eventsJson, callback);
|
|
7564
|
+
this._sendRequest(replayId, reqParams, eventsJson, callback);
|
|
7529
7565
|
}
|
|
7530
7566
|
}
|
|
7531
7567
|
});
|
|
@@ -9013,6 +9049,7 @@ define((function () { 'use strict';
|
|
|
9013
9049
|
'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
|
|
9014
9050
|
'record_mask_text_selector': '*',
|
|
9015
9051
|
'record_max_ms': MAX_RECORDING_MS,
|
|
9052
|
+
'record_min_ms': 0,
|
|
9016
9053
|
'record_sessions_percent': 0,
|
|
9017
9054
|
'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js'
|
|
9018
9055
|
};
|
package/dist/mixpanel.cjs.js
CHANGED
|
@@ -4509,7 +4509,7 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {
|
|
|
4509
4509
|
|
|
4510
4510
|
var Config = {
|
|
4511
4511
|
DEBUG: false,
|
|
4512
|
-
LIB_VERSION: '2.
|
|
4512
|
+
LIB_VERSION: '2.55.1'
|
|
4513
4513
|
};
|
|
4514
4514
|
|
|
4515
4515
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -4521,7 +4521,7 @@ if (typeof(window) === 'undefined') {
|
|
|
4521
4521
|
hostname: ''
|
|
4522
4522
|
};
|
|
4523
4523
|
win = {
|
|
4524
|
-
navigator: { userAgent: '' },
|
|
4524
|
+
navigator: { userAgent: '', onLine: true },
|
|
4525
4525
|
document: {
|
|
4526
4526
|
location: loc,
|
|
4527
4527
|
referrer: ''
|
|
@@ -4535,6 +4535,8 @@ if (typeof(window) === 'undefined') {
|
|
|
4535
4535
|
|
|
4536
4536
|
// Maximum allowed session recording length
|
|
4537
4537
|
var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
4538
|
+
// Maximum allowed value for minimum session recording length
|
|
4539
|
+
var MAX_VALUE_FOR_MIN_RECORDING_MS = 8 * 1000; // 8 seconds
|
|
4538
4540
|
|
|
4539
4541
|
/*
|
|
4540
4542
|
* Saved references to long variable names, so that closure compiler can
|
|
@@ -5475,7 +5477,7 @@ _.HTTPBuildQuery = function(formdata, arg_separator) {
|
|
|
5475
5477
|
_.getQueryParam = function(url, param) {
|
|
5476
5478
|
// Expects a raw URL
|
|
5477
5479
|
|
|
5478
|
-
param = param.replace(/[[]
|
|
5480
|
+
param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]');
|
|
5479
5481
|
var regexS = '[\\?&]' + param + '=([^&#]*)',
|
|
5480
5482
|
regex = new RegExp(regexS),
|
|
5481
5483
|
results = regex.exec(url);
|
|
@@ -5932,8 +5934,8 @@ _.dom_query = (function() {
|
|
|
5932
5934
|
};
|
|
5933
5935
|
})();
|
|
5934
5936
|
|
|
5935
|
-
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
|
|
5936
|
-
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid'];
|
|
5937
|
+
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic'];
|
|
5938
|
+
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid'];
|
|
5937
5939
|
|
|
5938
5940
|
_.info = {
|
|
5939
5941
|
campaignParams: function(default_value) {
|
|
@@ -6215,6 +6217,15 @@ var extract_domain = function(hostname) {
|
|
|
6215
6217
|
return matches ? matches[0] : '';
|
|
6216
6218
|
};
|
|
6217
6219
|
|
|
6220
|
+
/**
|
|
6221
|
+
* Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE)
|
|
6222
|
+
* @returns {boolean}
|
|
6223
|
+
*/
|
|
6224
|
+
var isOnline = function() {
|
|
6225
|
+
var onLine = win.navigator['onLine'];
|
|
6226
|
+
return _.isUndefined(onLine) || onLine;
|
|
6227
|
+
};
|
|
6228
|
+
|
|
6218
6229
|
var JSONStringify = null, JSONParse = null;
|
|
6219
6230
|
if (typeof JSON !== 'undefined') {
|
|
6220
6231
|
JSONStringify = JSON.stringify;
|
|
@@ -7178,7 +7189,12 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
7178
7189
|
this.flush();
|
|
7179
7190
|
} else if (
|
|
7180
7191
|
_.isObject(res) &&
|
|
7181
|
-
(
|
|
7192
|
+
(
|
|
7193
|
+
res.httpStatusCode >= 500
|
|
7194
|
+
|| res.httpStatusCode === 429
|
|
7195
|
+
|| (res.httpStatusCode <= 0 && !isOnline())
|
|
7196
|
+
|| res.error === 'timeout'
|
|
7197
|
+
)
|
|
7182
7198
|
) {
|
|
7183
7199
|
// network or API error, or 429 Too Many Requests, retry
|
|
7184
7200
|
var retryMS = this.flushInterval * 2;
|
|
@@ -7329,6 +7345,7 @@ var MixpanelRecorder = function(mixpanelInstance) {
|
|
|
7329
7345
|
this.maxTimeoutId = null;
|
|
7330
7346
|
|
|
7331
7347
|
this.recordMaxMs = MAX_RECORDING_MS;
|
|
7348
|
+
this.recordMinMs = 0;
|
|
7332
7349
|
this._initBatcher();
|
|
7333
7350
|
};
|
|
7334
7351
|
|
|
@@ -7360,16 +7377,24 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
7360
7377
|
logger.critical('record_max_ms cannot be greater than ' + MAX_RECORDING_MS + 'ms. Capping value.');
|
|
7361
7378
|
}
|
|
7362
7379
|
|
|
7380
|
+
this.recordMinMs = this.get_config('record_min_ms');
|
|
7381
|
+
if (this.recordMinMs > MAX_VALUE_FOR_MIN_RECORDING_MS) {
|
|
7382
|
+
this.recordMinMs = MAX_VALUE_FOR_MIN_RECORDING_MS;
|
|
7383
|
+
logger.critical('record_min_ms cannot be greater than ' + MAX_VALUE_FOR_MIN_RECORDING_MS + 'ms. Capping value.');
|
|
7384
|
+
}
|
|
7385
|
+
|
|
7363
7386
|
this.recEvents = [];
|
|
7364
7387
|
this.seqNo = 0;
|
|
7365
|
-
this.replayStartTime =
|
|
7388
|
+
this.replayStartTime = new Date().getTime();
|
|
7366
7389
|
|
|
7367
7390
|
this.replayId = _.UUID();
|
|
7368
7391
|
|
|
7369
|
-
if (shouldStopBatcher) {
|
|
7370
|
-
//
|
|
7392
|
+
if (shouldStopBatcher || this.recordMinMs > 0) {
|
|
7393
|
+
// the primary case for shouldStopBatcher is when we're starting recording after a reset
|
|
7371
7394
|
// and don't want to send anything over the network until there's
|
|
7372
7395
|
// actual user activity
|
|
7396
|
+
// this also applies if the minimum recording length has not been hit yet
|
|
7397
|
+
// so that we don't send data until we know the recording will be long enough
|
|
7373
7398
|
this.batcher.stop();
|
|
7374
7399
|
} else {
|
|
7375
7400
|
this.batcher.start();
|
|
@@ -7383,11 +7408,16 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
7383
7408
|
}, this), this.get_config('record_idle_timeout_ms'));
|
|
7384
7409
|
}, this);
|
|
7385
7410
|
|
|
7411
|
+
var blockSelector = this.get_config('record_block_selector');
|
|
7412
|
+
if (blockSelector === '' || blockSelector === null) {
|
|
7413
|
+
blockSelector = undefined;
|
|
7414
|
+
}
|
|
7415
|
+
|
|
7386
7416
|
this._stopRecording = record({
|
|
7387
7417
|
'emit': _.bind(function (ev) {
|
|
7388
7418
|
this.batcher.enqueue(ev);
|
|
7389
7419
|
if (isUserEvent(ev)) {
|
|
7390
|
-
if (this.batcher.stopped) {
|
|
7420
|
+
if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
|
|
7391
7421
|
// start flushing again after user activity
|
|
7392
7422
|
this.batcher.start();
|
|
7393
7423
|
}
|
|
@@ -7395,7 +7425,7 @@ MixpanelRecorder.prototype.startRecording = function (shouldStopBatcher) {
|
|
|
7395
7425
|
}
|
|
7396
7426
|
}, this),
|
|
7397
7427
|
'blockClass': this.get_config('record_block_class'),
|
|
7398
|
-
'blockSelector':
|
|
7428
|
+
'blockSelector': blockSelector,
|
|
7399
7429
|
'collectFonts': this.get_config('record_collect_fonts'),
|
|
7400
7430
|
'inlineImages': this.get_config('record_inline_images'),
|
|
7401
7431
|
'maskAllInputs': true,
|
|
@@ -7449,14 +7479,14 @@ MixpanelRecorder.prototype._onOptOut = function (code) {
|
|
|
7449
7479
|
}
|
|
7450
7480
|
};
|
|
7451
7481
|
|
|
7452
|
-
MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback) {
|
|
7482
|
+
MixpanelRecorder.prototype._sendRequest = function(currentReplayId, reqParams, reqBody, callback) {
|
|
7453
7483
|
var onSuccess = _.bind(function (response, responseBody) {
|
|
7454
7484
|
// Increment sequence counter only if the request was successful to guarantee ordering.
|
|
7455
7485
|
// RequestBatcher will always flush the next batch after the previous one succeeds.
|
|
7456
|
-
if
|
|
7486
|
+
// extra check to see if the replay ID has changed so that we don't increment the seqNo on the wrong replay
|
|
7487
|
+
if (response.status === 200 && this.replayId === currentReplayId) {
|
|
7457
7488
|
this.seqNo++;
|
|
7458
7489
|
}
|
|
7459
|
-
|
|
7460
7490
|
callback({
|
|
7461
7491
|
status: 0,
|
|
7462
7492
|
httpStatusCode: response.status,
|
|
@@ -7479,7 +7509,7 @@ MixpanelRecorder.prototype._sendRequest = function(reqParams, reqBody, callback)
|
|
|
7479
7509
|
callback({error: error});
|
|
7480
7510
|
});
|
|
7481
7511
|
}).catch(function (error) {
|
|
7482
|
-
callback({error: error});
|
|
7512
|
+
callback({error: error, httpStatusCode: 0});
|
|
7483
7513
|
});
|
|
7484
7514
|
};
|
|
7485
7515
|
|
|
@@ -7487,9 +7517,15 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
7487
7517
|
const numEvents = data.length;
|
|
7488
7518
|
|
|
7489
7519
|
if (numEvents > 0) {
|
|
7520
|
+
var replayId = this.replayId;
|
|
7490
7521
|
// each rrweb event has a timestamp - leverage those to get time properties
|
|
7491
7522
|
var batchStartTime = data[0].timestamp;
|
|
7492
|
-
if (this.seqNo === 0) {
|
|
7523
|
+
if (this.seqNo === 0 || !this.replayStartTime) {
|
|
7524
|
+
// extra safety net so that we don't send a null replay start time
|
|
7525
|
+
if (this.seqNo !== 0) {
|
|
7526
|
+
this.reportError('Replay start time not set but seqNo is not 0. Using current batch start time as a fallback.');
|
|
7527
|
+
}
|
|
7528
|
+
|
|
7493
7529
|
this.replayStartTime = batchStartTime;
|
|
7494
7530
|
}
|
|
7495
7531
|
var replayLengthMs = data[numEvents - 1].timestamp - this.replayStartTime;
|
|
@@ -7498,7 +7534,7 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
7498
7534
|
'distinct_id': String(this._mixpanel.get_distinct_id()),
|
|
7499
7535
|
'seq': this.seqNo,
|
|
7500
7536
|
'batch_start_time': batchStartTime / 1000,
|
|
7501
|
-
'replay_id':
|
|
7537
|
+
'replay_id': replayId,
|
|
7502
7538
|
'replay_length_ms': replayLengthMs,
|
|
7503
7539
|
'replay_start_time': this.replayStartTime / 1000
|
|
7504
7540
|
};
|
|
@@ -7521,11 +7557,11 @@ MixpanelRecorder.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
|
|
|
7521
7557
|
.blob()
|
|
7522
7558
|
.then(_.bind(function(compressedBlob) {
|
|
7523
7559
|
reqParams['format'] = 'gzip';
|
|
7524
|
-
this._sendRequest(reqParams, compressedBlob, callback);
|
|
7560
|
+
this._sendRequest(replayId, reqParams, compressedBlob, callback);
|
|
7525
7561
|
}, this));
|
|
7526
7562
|
} else {
|
|
7527
7563
|
reqParams['format'] = 'body';
|
|
7528
|
-
this._sendRequest(reqParams, eventsJson, callback);
|
|
7564
|
+
this._sendRequest(replayId, reqParams, eventsJson, callback);
|
|
7529
7565
|
}
|
|
7530
7566
|
}
|
|
7531
7567
|
});
|
|
@@ -9013,6 +9049,7 @@ var DEFAULT_CONFIG = {
|
|
|
9013
9049
|
'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
|
|
9014
9050
|
'record_mask_text_selector': '*',
|
|
9015
9051
|
'record_max_ms': MAX_RECORDING_MS,
|
|
9052
|
+
'record_min_ms': 0,
|
|
9016
9053
|
'record_sessions_percent': 0,
|
|
9017
9054
|
'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js'
|
|
9018
9055
|
};
|
package/dist/mixpanel.globals.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var Config = {
|
|
5
5
|
DEBUG: false,
|
|
6
|
-
LIB_VERSION: '2.
|
|
6
|
+
LIB_VERSION: '2.55.1'
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
hostname: ''
|
|
16
16
|
};
|
|
17
17
|
win = {
|
|
18
|
-
navigator: { userAgent: '' },
|
|
18
|
+
navigator: { userAgent: '', onLine: true },
|
|
19
19
|
document: {
|
|
20
20
|
location: loc,
|
|
21
21
|
referrer: ''
|
|
@@ -969,7 +969,7 @@
|
|
|
969
969
|
_.getQueryParam = function(url, param) {
|
|
970
970
|
// Expects a raw URL
|
|
971
971
|
|
|
972
|
-
param = param.replace(/[[]
|
|
972
|
+
param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]');
|
|
973
973
|
var regexS = '[\\?&]' + param + '=([^&#]*)',
|
|
974
974
|
regex = new RegExp(regexS),
|
|
975
975
|
results = regex.exec(url);
|
|
@@ -1426,8 +1426,8 @@
|
|
|
1426
1426
|
};
|
|
1427
1427
|
})();
|
|
1428
1428
|
|
|
1429
|
-
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
|
|
1430
|
-
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid'];
|
|
1429
|
+
var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic'];
|
|
1430
|
+
var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid'];
|
|
1431
1431
|
|
|
1432
1432
|
_.info = {
|
|
1433
1433
|
campaignParams: function(default_value) {
|
|
@@ -1709,6 +1709,15 @@
|
|
|
1709
1709
|
return matches ? matches[0] : '';
|
|
1710
1710
|
};
|
|
1711
1711
|
|
|
1712
|
+
/**
|
|
1713
|
+
* Check whether we have network connection. default to true for browsers that don't support navigator.onLine (IE)
|
|
1714
|
+
* @returns {boolean}
|
|
1715
|
+
*/
|
|
1716
|
+
var isOnline = function() {
|
|
1717
|
+
var onLine = win.navigator['onLine'];
|
|
1718
|
+
return _.isUndefined(onLine) || onLine;
|
|
1719
|
+
};
|
|
1720
|
+
|
|
1712
1721
|
var JSONStringify = null, JSONParse = null;
|
|
1713
1722
|
if (typeof JSON !== 'undefined') {
|
|
1714
1723
|
JSONStringify = JSON.stringify;
|
|
@@ -2524,7 +2533,12 @@
|
|
|
2524
2533
|
this.flush();
|
|
2525
2534
|
} else if (
|
|
2526
2535
|
_.isObject(res) &&
|
|
2527
|
-
(
|
|
2536
|
+
(
|
|
2537
|
+
res.httpStatusCode >= 500
|
|
2538
|
+
|| res.httpStatusCode === 429
|
|
2539
|
+
|| (res.httpStatusCode <= 0 && !isOnline())
|
|
2540
|
+
|| res.error === 'timeout'
|
|
2541
|
+
)
|
|
2528
2542
|
) {
|
|
2529
2543
|
// network or API error, or 429 Too Many Requests, retry
|
|
2530
2544
|
var retryMS = this.flushInterval * 2;
|
|
@@ -4248,6 +4262,7 @@
|
|
|
4248
4262
|
'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
|
|
4249
4263
|
'record_mask_text_selector': '*',
|
|
4250
4264
|
'record_max_ms': MAX_RECORDING_MS,
|
|
4265
|
+
'record_min_ms': 0,
|
|
4251
4266
|
'record_sessions_percent': 0,
|
|
4252
4267
|
'recorder_src': 'https://cdn.mxpnl.com/libs/mixpanel-recorder.min.js'
|
|
4253
4268
|
};
|