mixpanel-browser 2.66.0 → 2.68.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/dependabot.yml +7 -0
- package/CHANGELOG.md +12 -0
- package/dist/mixpanel-core.cjs.js +162 -42
- package/dist/mixpanel-recorder.js +36 -12
- package/dist/mixpanel-recorder.min.js +1 -1
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +162 -42
- package/dist/mixpanel-with-recorder.js +197 -53
- package/dist/mixpanel-with-recorder.min.js +1 -1
- package/dist/mixpanel.amd.js +197 -53
- package/dist/mixpanel.cjs.js +197 -53
- package/dist/mixpanel.globals.js +162 -42
- package/dist/mixpanel.min.js +150 -148
- package/dist/mixpanel.module.js +197 -53
- package/dist/mixpanel.umd.js +197 -53
- package/package.json +1 -1
- package/src/autocapture/index.js +59 -1
- package/src/autocapture/rageclick.js +38 -0
- package/src/config.js +1 -1
- package/src/flags/index.js +51 -8
- package/src/index.d.ts +18 -0
- package/src/mixpanel-core.js +20 -32
- package/src/recorder/session-recording.js +35 -11
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.68.0'
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
@@ -2655,6 +2655,38 @@
|
|
|
2655
2655
|
return true;
|
|
2656
2656
|
}
|
|
2657
2657
|
|
|
2658
|
+
/** @const */ var DEFAULT_RAGE_CLICK_THRESHOLD_PX = 30;
|
|
2659
|
+
/** @const */ var DEFAULT_RAGE_CLICK_TIMEOUT_MS = 1000;
|
|
2660
|
+
/** @const */ var DEFAULT_RAGE_CLICK_CLICK_COUNT = 4;
|
|
2661
|
+
|
|
2662
|
+
function RageClickTracker() {
|
|
2663
|
+
this.clicks = [];
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
RageClickTracker.prototype.isRageClick = function(x, y, options) {
|
|
2667
|
+
options = options || {};
|
|
2668
|
+
var thresholdPx = options['threshold_px'] || DEFAULT_RAGE_CLICK_THRESHOLD_PX;
|
|
2669
|
+
var timeoutMs = options['timeout_ms'] || DEFAULT_RAGE_CLICK_TIMEOUT_MS;
|
|
2670
|
+
var clickCount = options['click_count'] || DEFAULT_RAGE_CLICK_CLICK_COUNT;
|
|
2671
|
+
var timestamp = Date.now();
|
|
2672
|
+
|
|
2673
|
+
var lastClick = this.clicks[this.clicks.length - 1];
|
|
2674
|
+
if (
|
|
2675
|
+
lastClick &&
|
|
2676
|
+
timestamp - lastClick.timestamp < timeoutMs &&
|
|
2677
|
+
Math.sqrt(Math.pow(x - lastClick.x, 2) + Math.pow(y - lastClick.y, 2)) < thresholdPx
|
|
2678
|
+
) {
|
|
2679
|
+
this.clicks.push({ x: x, y: y, timestamp: timestamp });
|
|
2680
|
+
if (this.clicks.length >= clickCount) {
|
|
2681
|
+
this.clicks = [];
|
|
2682
|
+
return true;
|
|
2683
|
+
}
|
|
2684
|
+
} else {
|
|
2685
|
+
this.clicks = [{ x: x, y: y, timestamp: timestamp }];
|
|
2686
|
+
}
|
|
2687
|
+
return false;
|
|
2688
|
+
};
|
|
2689
|
+
|
|
2658
2690
|
var AUTOCAPTURE_CONFIG_KEY = 'autocapture';
|
|
2659
2691
|
var LEGACY_PAGEVIEW_CONFIG_KEY = 'track_pageview';
|
|
2660
2692
|
|
|
@@ -2676,6 +2708,7 @@
|
|
|
2676
2708
|
var CONFIG_TRACK_CLICK = 'click';
|
|
2677
2709
|
var CONFIG_TRACK_INPUT = 'input';
|
|
2678
2710
|
var CONFIG_TRACK_PAGEVIEW = 'pageview';
|
|
2711
|
+
var CONFIG_TRACK_RAGE_CLICK = 'rage_click';
|
|
2679
2712
|
var CONFIG_TRACK_SCROLL = 'scroll';
|
|
2680
2713
|
var CONFIG_TRACK_SUBMIT = 'submit';
|
|
2681
2714
|
|
|
@@ -2693,6 +2726,7 @@
|
|
|
2693
2726
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_CLICK] = true;
|
|
2694
2727
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_INPUT] = true;
|
|
2695
2728
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
|
|
2729
|
+
CONFIG_DEFAULTS$1[CONFIG_TRACK_RAGE_CLICK] = true;
|
|
2696
2730
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_SCROLL] = true;
|
|
2697
2731
|
CONFIG_DEFAULTS$1[CONFIG_TRACK_SUBMIT] = true;
|
|
2698
2732
|
|
|
@@ -2702,6 +2736,7 @@
|
|
|
2702
2736
|
|
|
2703
2737
|
var MP_EV_CLICK = '$mp_click';
|
|
2704
2738
|
var MP_EV_INPUT = '$mp_input_change';
|
|
2739
|
+
var MP_EV_RAGE_CLICK = '$mp_rage_click';
|
|
2705
2740
|
var MP_EV_SCROLL = '$mp_scroll';
|
|
2706
2741
|
var MP_EV_SUBMIT = '$mp_submit';
|
|
2707
2742
|
|
|
@@ -2724,6 +2759,7 @@
|
|
|
2724
2759
|
this.initInputTracking();
|
|
2725
2760
|
this.initScrollTracking();
|
|
2726
2761
|
this.initSubmitTracking();
|
|
2762
|
+
this.initRageClickTracking();
|
|
2727
2763
|
};
|
|
2728
2764
|
|
|
2729
2765
|
Autocapture.prototype.getFullConfig = function() {
|
|
@@ -2802,6 +2838,11 @@
|
|
|
2802
2838
|
return;
|
|
2803
2839
|
}
|
|
2804
2840
|
|
|
2841
|
+
var isCapturedForHeatMap = this.mp.is_recording_heatmap_data() && (
|
|
2842
|
+
(mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK)) ||
|
|
2843
|
+
(mpEventName === MP_EV_RAGE_CLICK && !this._getRageClickConfig())
|
|
2844
|
+
);
|
|
2845
|
+
|
|
2805
2846
|
var props = getPropsForDOMEvent(ev, {
|
|
2806
2847
|
allowElementCallback: this.getConfig(CONFIG_ALLOW_ELEMENT_CALLBACK),
|
|
2807
2848
|
allowSelectors: this.getConfig(CONFIG_ALLOW_SELECTORS),
|
|
@@ -2810,7 +2851,7 @@
|
|
|
2810
2851
|
blockSelectors: this.getConfig(CONFIG_BLOCK_SELECTORS),
|
|
2811
2852
|
captureExtraAttrs: this.getConfig(CONFIG_CAPTURE_EXTRA_ATTRS),
|
|
2812
2853
|
captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT),
|
|
2813
|
-
capturedForHeatMap:
|
|
2854
|
+
capturedForHeatMap: isCapturedForHeatMap,
|
|
2814
2855
|
});
|
|
2815
2856
|
if (props) {
|
|
2816
2857
|
_.extend(props, DEFAULT_PROPS);
|
|
@@ -2818,6 +2859,24 @@
|
|
|
2818
2859
|
}
|
|
2819
2860
|
};
|
|
2820
2861
|
|
|
2862
|
+
Autocapture.prototype._getRageClickConfig = function() {
|
|
2863
|
+
var config = this.getConfig(CONFIG_TRACK_RAGE_CLICK);
|
|
2864
|
+
|
|
2865
|
+
if (!config) {
|
|
2866
|
+
return null; // rage click tracking disabled
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
if (config === true) {
|
|
2870
|
+
return {}; // use defaults
|
|
2871
|
+
}
|
|
2872
|
+
|
|
2873
|
+
if (typeof config === 'object') {
|
|
2874
|
+
return config; // use custom configuration
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2877
|
+
return {}; // fallback to defaults for any other truthy value
|
|
2878
|
+
};
|
|
2879
|
+
|
|
2821
2880
|
Autocapture.prototype.initClickTracking = function() {
|
|
2822
2881
|
win.removeEventListener(EV_CLICK, this.listenerClick);
|
|
2823
2882
|
|
|
@@ -2919,6 +2978,36 @@
|
|
|
2919
2978
|
}.bind(this)));
|
|
2920
2979
|
};
|
|
2921
2980
|
|
|
2981
|
+
Autocapture.prototype.initRageClickTracking = function() {
|
|
2982
|
+
win.removeEventListener(EV_CLICK, this.listenerRageClick);
|
|
2983
|
+
|
|
2984
|
+
var rageClickConfig = this._getRageClickConfig();
|
|
2985
|
+
if (!rageClickConfig && !this.mp.get_config('record_heatmap_data')) {
|
|
2986
|
+
return;
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
logger$4.log('Initializing rage click tracking');
|
|
2990
|
+
if (!this._rageClickTracker) {
|
|
2991
|
+
this._rageClickTracker = new RageClickTracker();
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2994
|
+
this.listenerRageClick = function(ev) {
|
|
2995
|
+
var currentRageClickConfig = this._getRageClickConfig();
|
|
2996
|
+
if (!currentRageClickConfig && !this.mp.is_recording_heatmap_data()) {
|
|
2997
|
+
return;
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
if (this.currentUrlBlocked()) {
|
|
3001
|
+
return;
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
if (this._rageClickTracker.isRageClick(ev['pageX'], ev['pageY'], currentRageClickConfig)) {
|
|
3005
|
+
this.trackDomEvent(ev, MP_EV_RAGE_CLICK);
|
|
3006
|
+
}
|
|
3007
|
+
}.bind(this);
|
|
3008
|
+
win.addEventListener(EV_CLICK, this.listenerRageClick);
|
|
3009
|
+
};
|
|
3010
|
+
|
|
2922
3011
|
Autocapture.prototype.initScrollTracking = function() {
|
|
2923
3012
|
win.removeEventListener(EV_SCROLLEND, this.listenerScroll);
|
|
2924
3013
|
|
|
@@ -3003,8 +3092,10 @@
|
|
|
3003
3092
|
* @constructor
|
|
3004
3093
|
*/
|
|
3005
3094
|
var FeatureFlagManager = function(initOptions) {
|
|
3095
|
+
this.getFullApiRoute = initOptions.getFullApiRoute;
|
|
3006
3096
|
this.getMpConfig = initOptions.getConfigFunc;
|
|
3007
|
-
this.
|
|
3097
|
+
this.setMpConfig = initOptions.setConfigFunc;
|
|
3098
|
+
this.getMpProperty = initOptions.getPropertyFunc;
|
|
3008
3099
|
this.track = initOptions.trackingFunc;
|
|
3009
3100
|
};
|
|
3010
3101
|
|
|
@@ -3041,6 +3132,23 @@
|
|
|
3041
3132
|
return !!this.getMpConfig(FLAGS_CONFIG_KEY);
|
|
3042
3133
|
};
|
|
3043
3134
|
|
|
3135
|
+
FeatureFlagManager.prototype.updateContext = function(newContext, options) {
|
|
3136
|
+
if (!this.isSystemEnabled()) {
|
|
3137
|
+
logger$3.critical('Feature Flags not enabled, cannot update context');
|
|
3138
|
+
return Promise.resolve();
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
var ffConfig = this.getMpConfig(FLAGS_CONFIG_KEY);
|
|
3142
|
+
if (!_.isObject(ffConfig)) {
|
|
3143
|
+
ffConfig = {};
|
|
3144
|
+
}
|
|
3145
|
+
var oldContext = (options && options['replace']) ? {} : this.getConfig(CONFIG_CONTEXT);
|
|
3146
|
+
ffConfig[CONFIG_CONTEXT] = _.extend({}, oldContext, newContext);
|
|
3147
|
+
|
|
3148
|
+
this.setMpConfig(FLAGS_CONFIG_KEY, ffConfig);
|
|
3149
|
+
return this.fetchFlags();
|
|
3150
|
+
};
|
|
3151
|
+
|
|
3044
3152
|
FeatureFlagManager.prototype.areFlagsReady = function() {
|
|
3045
3153
|
if (!this.isSystemEnabled()) {
|
|
3046
3154
|
logger$3.error('Feature Flags not enabled');
|
|
@@ -3050,15 +3158,17 @@
|
|
|
3050
3158
|
|
|
3051
3159
|
FeatureFlagManager.prototype.fetchFlags = function() {
|
|
3052
3160
|
if (!this.isSystemEnabled()) {
|
|
3053
|
-
return;
|
|
3161
|
+
return Promise.resolve();
|
|
3054
3162
|
}
|
|
3055
3163
|
|
|
3056
|
-
var distinctId = this.
|
|
3164
|
+
var distinctId = this.getMpProperty('distinct_id');
|
|
3165
|
+
var deviceId = this.getMpProperty('$device_id');
|
|
3057
3166
|
logger$3.log('Fetching flags for distinct ID: ' + distinctId);
|
|
3058
3167
|
var reqParams = {
|
|
3059
|
-
'context': _.extend({'distinct_id': distinctId}, this.getConfig(CONFIG_CONTEXT))
|
|
3168
|
+
'context': _.extend({'distinct_id': distinctId, 'device_id': deviceId}, this.getConfig(CONFIG_CONTEXT))
|
|
3060
3169
|
};
|
|
3061
|
-
this.
|
|
3170
|
+
this._fetchInProgressStartTime = Date.now();
|
|
3171
|
+
this.fetchPromise = win['fetch'](this.getFullApiRoute(), {
|
|
3062
3172
|
'method': 'POST',
|
|
3063
3173
|
'headers': {
|
|
3064
3174
|
'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
|
|
@@ -3066,6 +3176,7 @@
|
|
|
3066
3176
|
},
|
|
3067
3177
|
'body': JSON.stringify(reqParams)
|
|
3068
3178
|
}).then(function(response) {
|
|
3179
|
+
this.markFetchComplete();
|
|
3069
3180
|
return response.json().then(function(responseBody) {
|
|
3070
3181
|
var responseFlags = responseBody['flags'];
|
|
3071
3182
|
if (!responseFlags) {
|
|
@@ -3080,9 +3191,26 @@
|
|
|
3080
3191
|
});
|
|
3081
3192
|
this.flags = flags;
|
|
3082
3193
|
}.bind(this)).catch(function(error) {
|
|
3194
|
+
this.markFetchComplete();
|
|
3083
3195
|
logger$3.error(error);
|
|
3084
|
-
});
|
|
3085
|
-
}.bind(this)).catch(function() {
|
|
3196
|
+
}.bind(this));
|
|
3197
|
+
}.bind(this)).catch(function(error) {
|
|
3198
|
+
this.markFetchComplete();
|
|
3199
|
+
logger$3.error(error);
|
|
3200
|
+
}.bind(this));
|
|
3201
|
+
|
|
3202
|
+
return this.fetchPromise;
|
|
3203
|
+
};
|
|
3204
|
+
|
|
3205
|
+
FeatureFlagManager.prototype.markFetchComplete = function() {
|
|
3206
|
+
if (!this._fetchInProgressStartTime) {
|
|
3207
|
+
logger$3.error('Fetch in progress started time not set, cannot mark fetch complete');
|
|
3208
|
+
return;
|
|
3209
|
+
}
|
|
3210
|
+
this._fetchStartTime = this._fetchInProgressStartTime;
|
|
3211
|
+
this._fetchCompleteTime = Date.now();
|
|
3212
|
+
this._fetchLatency = this._fetchCompleteTime - this._fetchStartTime;
|
|
3213
|
+
this._fetchInProgressStartTime = null;
|
|
3086
3214
|
};
|
|
3087
3215
|
|
|
3088
3216
|
FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
|
|
@@ -3161,7 +3289,10 @@
|
|
|
3161
3289
|
this.track('$experiment_started', {
|
|
3162
3290
|
'Experiment name': featureName,
|
|
3163
3291
|
'Variant name': feature['key'],
|
|
3164
|
-
'$experiment_type': 'feature_flag'
|
|
3292
|
+
'$experiment_type': 'feature_flag',
|
|
3293
|
+
'Variant fetch start time': new Date(this._fetchStartTime).toISOString(),
|
|
3294
|
+
'Variant fetch complete time': new Date(this._fetchCompleteTime).toISOString(),
|
|
3295
|
+
'Variant fetch latency (ms)': this._fetchLatency
|
|
3165
3296
|
});
|
|
3166
3297
|
};
|
|
3167
3298
|
|
|
@@ -3181,6 +3312,7 @@
|
|
|
3181
3312
|
FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
|
|
3182
3313
|
FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
|
|
3183
3314
|
FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
|
|
3315
|
+
FeatureFlagManager.prototype['update_context'] = FeatureFlagManager.prototype.updateContext;
|
|
3184
3316
|
|
|
3185
3317
|
// Deprecated method
|
|
3186
3318
|
FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
|
|
@@ -5952,7 +6084,7 @@
|
|
|
5952
6084
|
'batch_autostart': true,
|
|
5953
6085
|
'hooks': {},
|
|
5954
6086
|
'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
|
|
5955
|
-
'record_block_selector': 'img, video',
|
|
6087
|
+
'record_block_selector': 'img, video, audio',
|
|
5956
6088
|
'record_canvas': false,
|
|
5957
6089
|
'record_collect_fonts': false,
|
|
5958
6090
|
'record_heatmap_data': false,
|
|
@@ -6172,8 +6304,12 @@
|
|
|
6172
6304
|
}
|
|
6173
6305
|
|
|
6174
6306
|
this.flags = new FeatureFlagManager({
|
|
6307
|
+
getFullApiRoute: _.bind(function() {
|
|
6308
|
+
return this.get_api_host('flags') + '/' + this.get_config('api_routes')['flags'];
|
|
6309
|
+
}, this),
|
|
6175
6310
|
getConfigFunc: _.bind(this.get_config, this),
|
|
6176
|
-
|
|
6311
|
+
setConfigFunc: _.bind(this.set_config, this),
|
|
6312
|
+
getPropertyFunc: _.bind(this.get_property, this),
|
|
6177
6313
|
trackingFunc: _.bind(this.track, this)
|
|
6178
6314
|
});
|
|
6179
6315
|
this.flags.init();
|
|
@@ -6659,11 +6795,10 @@
|
|
|
6659
6795
|
|
|
6660
6796
|
MixpanelLib.prototype.get_batcher_configs = function() {
|
|
6661
6797
|
var queue_prefix = '__mpq_' + this.get_config('token');
|
|
6662
|
-
var api_routes = this.get_config('api_routes');
|
|
6663
6798
|
this._batcher_configs = this._batcher_configs || {
|
|
6664
|
-
events: {type: 'events',
|
|
6665
|
-
people: {type: 'people',
|
|
6666
|
-
groups: {type: 'groups',
|
|
6799
|
+
events: {type: 'events', api_name: 'track', queue_key: queue_prefix + '_ev'},
|
|
6800
|
+
people: {type: 'people', api_name: 'engage', queue_key: queue_prefix + '_pp'},
|
|
6801
|
+
groups: {type: 'groups', api_name: 'groups', queue_key: queue_prefix + '_gr'}
|
|
6667
6802
|
};
|
|
6668
6803
|
return this._batcher_configs;
|
|
6669
6804
|
};
|
|
@@ -6677,8 +6812,9 @@
|
|
|
6677
6812
|
libConfig: this['config'],
|
|
6678
6813
|
errorReporter: this.get_config('error_reporter'),
|
|
6679
6814
|
sendRequestFunc: _.bind(function(data, options, cb) {
|
|
6815
|
+
var api_routes = this.get_config('api_routes');
|
|
6680
6816
|
this._send_request(
|
|
6681
|
-
this.
|
|
6817
|
+
this.get_api_host(attrs.api_name) + '/' + api_routes[attrs.api_name],
|
|
6682
6818
|
this._encode_data_for_request(data),
|
|
6683
6819
|
options,
|
|
6684
6820
|
this._prepare_callback(cb, data)
|
|
@@ -7406,31 +7542,15 @@
|
|
|
7406
7542
|
* Useful for clearing data when a user logs out.
|
|
7407
7543
|
*/
|
|
7408
7544
|
MixpanelLib.prototype.reset = function() {
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
}, '');
|
|
7419
|
-
};
|
|
7420
|
-
|
|
7421
|
-
if (self._recorder) {
|
|
7422
|
-
self.stop_session_recording()
|
|
7423
|
-
.then(function () {
|
|
7424
|
-
reset();
|
|
7425
|
-
self._check_and_start_session_recording();
|
|
7426
|
-
})
|
|
7427
|
-
.catch(_.bind(function (err) {
|
|
7428
|
-
reset();
|
|
7429
|
-
this.report_error('Error restarting recording session', err);
|
|
7430
|
-
}, this));
|
|
7431
|
-
} else {
|
|
7432
|
-
reset();
|
|
7433
|
-
}
|
|
7545
|
+
this.stop_session_recording();
|
|
7546
|
+
this['persistence'].clear();
|
|
7547
|
+
this._flags.identify_called = false;
|
|
7548
|
+
var uuid = _.UUID();
|
|
7549
|
+
this.register_once({
|
|
7550
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
7551
|
+
'$device_id': uuid
|
|
7552
|
+
}, '');
|
|
7553
|
+
this._check_and_start_session_recording();
|
|
7434
7554
|
};
|
|
7435
7555
|
|
|
7436
7556
|
/**
|