mixpanel-browser 2.63.0 → 2.65.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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  var Config = {
4
4
  DEBUG: false,
5
- LIB_VERSION: '2.63.0'
5
+ LIB_VERSION: '2.65.0'
6
6
  };
7
7
 
8
8
  // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
@@ -1870,6 +1870,9 @@ _.info = {
1870
1870
  return 'Microsoft Edge';
1871
1871
  } else if (_.includes(user_agent, 'FBIOS')) {
1872
1872
  return 'Facebook Mobile';
1873
+ } else if (_.includes(user_agent, 'Whale/')) {
1874
+ // https://user-agents.net/browsers/whale-browser
1875
+ return 'Whale Browser';
1873
1876
  } else if (_.includes(user_agent, 'Chrome')) {
1874
1877
  return 'Chrome';
1875
1878
  } else if (_.includes(user_agent, 'CriOS')) {
@@ -1921,7 +1924,8 @@ _.info = {
1921
1924
  'Android Mobile': /android\s(\d+(\.\d+)?)/,
1922
1925
  'Samsung Internet': /SamsungBrowser\/(\d+(\.\d+)?)/,
1923
1926
  'Internet Explorer': /(rv:|MSIE )(\d+(\.\d+)?)/,
1924
- 'Mozilla': /rv:(\d+(\.\d+)?)/
1927
+ 'Mozilla': /rv:(\d+(\.\d+)?)/,
1928
+ 'Whale Browser': /Whale\/(\d+(\.\d+)?)/
1925
1929
  };
1926
1930
  var regex = versionRegexs[browser];
1927
1931
  if (regex === undefined) {
@@ -2158,7 +2162,7 @@ var TRACKED_ATTRS = [
2158
2162
  'href', 'name', 'role', 'title', 'type'
2159
2163
  ];
2160
2164
 
2161
- var logger$3 = console_with_prefix('autocapture');
2165
+ var logger$4 = console_with_prefix('autocapture');
2162
2166
 
2163
2167
 
2164
2168
  function getClasses(el) {
@@ -2244,6 +2248,7 @@ function getPropsForDOMEvent(ev, config) {
2244
2248
  var blockSelectors = config.blockSelectors || [];
2245
2249
  var captureTextContent = config.captureTextContent || false;
2246
2250
  var captureExtraAttrs = config.captureExtraAttrs || [];
2251
+ var capturedForHeatMap = config.capturedForHeatMap || false;
2247
2252
 
2248
2253
  // convert array to set every time, as the config may have changed
2249
2254
  var blockAttrsSet = {};
@@ -2298,7 +2303,9 @@ function getPropsForDOMEvent(ev, config) {
2298
2303
  '$elements': elementsJson,
2299
2304
  '$el_attr__href': href,
2300
2305
  '$viewportHeight': Math.max(docElement['clientHeight'], win['innerHeight'] || 0),
2301
- '$viewportWidth': Math.max(docElement['clientWidth'], win['innerWidth'] || 0)
2306
+ '$viewportWidth': Math.max(docElement['clientWidth'], win['innerWidth'] || 0),
2307
+ '$pageHeight': document$1['body']['offsetHeight'] || 0,
2308
+ '$pageWidth': document$1['body']['offsetWidth'] || 0,
2302
2309
  };
2303
2310
  _.each(captureExtraAttrs, function(attr) {
2304
2311
  if (!blockAttrsSet[attr] && target.hasAttribute(attr)) {
@@ -2322,6 +2329,9 @@ function getPropsForDOMEvent(ev, config) {
2322
2329
  props['$' + prop] = ev[prop];
2323
2330
  }
2324
2331
  });
2332
+ if (capturedForHeatMap) {
2333
+ props['$captured_for_heatmap'] = true;
2334
+ }
2325
2335
  target = guessRealClickTarget(ev);
2326
2336
  }
2327
2337
  // prioritize text content from "real" click target if different from original target
@@ -2416,7 +2426,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
2416
2426
  return false;
2417
2427
  }
2418
2428
  } catch (err) {
2419
- logger$3.critical('Error while checking element in allowElementCallback', err);
2429
+ logger$4.critical('Error while checking element in allowElementCallback', err);
2420
2430
  return false;
2421
2431
  }
2422
2432
  }
@@ -2433,7 +2443,7 @@ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
2433
2443
  return true;
2434
2444
  }
2435
2445
  } catch (err) {
2436
- logger$3.critical('Error while checking selector: ' + sel, err);
2446
+ logger$4.critical('Error while checking selector: ' + sel, err);
2437
2447
  }
2438
2448
  }
2439
2449
  return false;
@@ -2448,7 +2458,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
2448
2458
  return true;
2449
2459
  }
2450
2460
  } catch (err) {
2451
- logger$3.critical('Error while checking element in blockElementCallback', err);
2461
+ logger$4.critical('Error while checking element in blockElementCallback', err);
2452
2462
  return true;
2453
2463
  }
2454
2464
  }
@@ -2462,7 +2472,7 @@ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
2462
2472
  return true;
2463
2473
  }
2464
2474
  } catch (err) {
2465
- logger$3.critical('Error while checking selector: ' + sel, err);
2475
+ logger$4.critical('Error while checking selector: ' + sel, err);
2466
2476
  }
2467
2477
  }
2468
2478
  }
@@ -2668,22 +2678,22 @@ var CONFIG_TRACK_PAGEVIEW = 'pageview';
2668
2678
  var CONFIG_TRACK_SCROLL = 'scroll';
2669
2679
  var CONFIG_TRACK_SUBMIT = 'submit';
2670
2680
 
2671
- var CONFIG_DEFAULTS = {};
2672
- CONFIG_DEFAULTS[CONFIG_ALLOW_SELECTORS] = [];
2673
- CONFIG_DEFAULTS[CONFIG_ALLOW_URL_REGEXES] = [];
2674
- CONFIG_DEFAULTS[CONFIG_BLOCK_ATTRS] = [];
2675
- CONFIG_DEFAULTS[CONFIG_BLOCK_ELEMENT_CALLBACK] = null;
2676
- CONFIG_DEFAULTS[CONFIG_BLOCK_SELECTORS] = [];
2677
- CONFIG_DEFAULTS[CONFIG_BLOCK_URL_REGEXES] = [];
2678
- CONFIG_DEFAULTS[CONFIG_CAPTURE_EXTRA_ATTRS] = [];
2679
- CONFIG_DEFAULTS[CONFIG_CAPTURE_TEXT_CONTENT] = false;
2680
- CONFIG_DEFAULTS[CONFIG_SCROLL_CAPTURE_ALL] = false;
2681
- CONFIG_DEFAULTS[CONFIG_SCROLL_CHECKPOINTS] = [25, 50, 75, 100];
2682
- CONFIG_DEFAULTS[CONFIG_TRACK_CLICK] = true;
2683
- CONFIG_DEFAULTS[CONFIG_TRACK_INPUT] = true;
2684
- CONFIG_DEFAULTS[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
2685
- CONFIG_DEFAULTS[CONFIG_TRACK_SCROLL] = true;
2686
- CONFIG_DEFAULTS[CONFIG_TRACK_SUBMIT] = true;
2681
+ var CONFIG_DEFAULTS$1 = {};
2682
+ CONFIG_DEFAULTS$1[CONFIG_ALLOW_SELECTORS] = [];
2683
+ CONFIG_DEFAULTS$1[CONFIG_ALLOW_URL_REGEXES] = [];
2684
+ CONFIG_DEFAULTS$1[CONFIG_BLOCK_ATTRS] = [];
2685
+ CONFIG_DEFAULTS$1[CONFIG_BLOCK_ELEMENT_CALLBACK] = null;
2686
+ CONFIG_DEFAULTS$1[CONFIG_BLOCK_SELECTORS] = [];
2687
+ CONFIG_DEFAULTS$1[CONFIG_BLOCK_URL_REGEXES] = [];
2688
+ CONFIG_DEFAULTS$1[CONFIG_CAPTURE_EXTRA_ATTRS] = [];
2689
+ CONFIG_DEFAULTS$1[CONFIG_CAPTURE_TEXT_CONTENT] = false;
2690
+ CONFIG_DEFAULTS$1[CONFIG_SCROLL_CAPTURE_ALL] = false;
2691
+ CONFIG_DEFAULTS$1[CONFIG_SCROLL_CHECKPOINTS] = [25, 50, 75, 100];
2692
+ CONFIG_DEFAULTS$1[CONFIG_TRACK_CLICK] = true;
2693
+ CONFIG_DEFAULTS$1[CONFIG_TRACK_INPUT] = true;
2694
+ CONFIG_DEFAULTS$1[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
2695
+ CONFIG_DEFAULTS$1[CONFIG_TRACK_SCROLL] = true;
2696
+ CONFIG_DEFAULTS$1[CONFIG_TRACK_SUBMIT] = true;
2687
2697
 
2688
2698
  var DEFAULT_PROPS = {
2689
2699
  '$mp_autocapture': true
@@ -2704,7 +2714,7 @@ var Autocapture = function(mp) {
2704
2714
 
2705
2715
  Autocapture.prototype.init = function() {
2706
2716
  if (!minDOMApisSupported()) {
2707
- logger$3.critical('Autocapture unavailable: missing required DOM APIs');
2717
+ logger$4.critical('Autocapture unavailable: missing required DOM APIs');
2708
2718
  return;
2709
2719
  }
2710
2720
 
@@ -2721,10 +2731,10 @@ Autocapture.prototype.getFullConfig = function() {
2721
2731
  // Autocapture is completely off
2722
2732
  return {};
2723
2733
  } else if (_.isObject(autocaptureConfig)) {
2724
- return _.extend({}, CONFIG_DEFAULTS, autocaptureConfig);
2734
+ return _.extend({}, CONFIG_DEFAULTS$1, autocaptureConfig);
2725
2735
  } else {
2726
2736
  // Autocapture config is non-object truthy value, return default
2727
- return CONFIG_DEFAULTS;
2737
+ return CONFIG_DEFAULTS$1;
2728
2738
  }
2729
2739
  };
2730
2740
 
@@ -2748,7 +2758,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
2748
2758
  break;
2749
2759
  }
2750
2760
  } catch (err) {
2751
- logger$3.critical('Error while checking block URL regex: ' + allowRegex, err);
2761
+ logger$4.critical('Error while checking block URL regex: ' + allowRegex, err);
2752
2762
  return true;
2753
2763
  }
2754
2764
  }
@@ -2769,7 +2779,7 @@ Autocapture.prototype.currentUrlBlocked = function() {
2769
2779
  return true;
2770
2780
  }
2771
2781
  } catch (err) {
2772
- logger$3.critical('Error while checking block URL regex: ' + blockUrlRegexes[i], err);
2782
+ logger$4.critical('Error while checking block URL regex: ' + blockUrlRegexes[i], err);
2773
2783
  return true;
2774
2784
  }
2775
2785
  }
@@ -2798,7 +2808,8 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
2798
2808
  blockElementCallback: this.getConfig(CONFIG_BLOCK_ELEMENT_CALLBACK),
2799
2809
  blockSelectors: this.getConfig(CONFIG_BLOCK_SELECTORS),
2800
2810
  captureExtraAttrs: this.getConfig(CONFIG_CAPTURE_EXTRA_ATTRS),
2801
- captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT)
2811
+ captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT),
2812
+ capturedForHeatMap: mpEventName === MP_EV_CLICK && !this.getConfig(CONFIG_TRACK_CLICK) && this.mp.is_recording_heatmap_data(),
2802
2813
  });
2803
2814
  if (props) {
2804
2815
  _.extend(props, DEFAULT_PROPS);
@@ -2809,13 +2820,13 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
2809
2820
  Autocapture.prototype.initClickTracking = function() {
2810
2821
  win.removeEventListener(EV_CLICK, this.listenerClick);
2811
2822
 
2812
- if (!this.getConfig(CONFIG_TRACK_CLICK)) {
2823
+ if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.get_config('record_heatmap_data')) {
2813
2824
  return;
2814
2825
  }
2815
- logger$3.log('Initializing click tracking');
2826
+ logger$4.log('Initializing click tracking');
2816
2827
 
2817
2828
  this.listenerClick = win.addEventListener(EV_CLICK, function(ev) {
2818
- if (!this.getConfig(CONFIG_TRACK_CLICK)) {
2829
+ if (!this.getConfig(CONFIG_TRACK_CLICK) && !this.mp.is_recording_heatmap_data()) {
2819
2830
  return;
2820
2831
  }
2821
2832
  this.trackDomEvent(ev, MP_EV_CLICK);
@@ -2828,7 +2839,7 @@ Autocapture.prototype.initInputTracking = function() {
2828
2839
  if (!this.getConfig(CONFIG_TRACK_INPUT)) {
2829
2840
  return;
2830
2841
  }
2831
- logger$3.log('Initializing input tracking');
2842
+ logger$4.log('Initializing input tracking');
2832
2843
 
2833
2844
  this.listenerChange = win.addEventListener(EV_CHANGE, function(ev) {
2834
2845
  if (!this.getConfig(CONFIG_TRACK_INPUT)) {
@@ -2846,7 +2857,7 @@ Autocapture.prototype.initPageviewTracking = function() {
2846
2857
  if (!this.pageviewTrackingConfig()) {
2847
2858
  return;
2848
2859
  }
2849
- logger$3.log('Initializing pageview tracking');
2860
+ logger$4.log('Initializing pageview tracking');
2850
2861
 
2851
2862
  var previousTrackedUrl = '';
2852
2863
  var tracked = false;
@@ -2901,7 +2912,7 @@ Autocapture.prototype.initPageviewTracking = function() {
2901
2912
  }
2902
2913
  if (didPathChange) {
2903
2914
  this.lastScrollCheckpoint = 0;
2904
- logger$3.log('Path change: re-initializing scroll depth checkpoints');
2915
+ logger$4.log('Path change: re-initializing scroll depth checkpoints');
2905
2916
  }
2906
2917
  }
2907
2918
  }.bind(this)));
@@ -2913,7 +2924,7 @@ Autocapture.prototype.initScrollTracking = function() {
2913
2924
  if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
2914
2925
  return;
2915
2926
  }
2916
- logger$3.log('Initializing scroll tracking');
2927
+ logger$4.log('Initializing scroll tracking');
2917
2928
  this.lastScrollCheckpoint = 0;
2918
2929
 
2919
2930
  this.listenerScroll = win.addEventListener(EV_SCROLLEND, safewrap(function() {
@@ -2950,7 +2961,7 @@ Autocapture.prototype.initScrollTracking = function() {
2950
2961
  }
2951
2962
  }
2952
2963
  } catch (err) {
2953
- logger$3.critical('Error while calculating scroll percentage', err);
2964
+ logger$4.critical('Error while calculating scroll percentage', err);
2954
2965
  }
2955
2966
  if (shouldTrack) {
2956
2967
  this.mp.track(MP_EV_SCROLL, props);
@@ -2964,7 +2975,7 @@ Autocapture.prototype.initSubmitTracking = function() {
2964
2975
  if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
2965
2976
  return;
2966
2977
  }
2967
- logger$3.log('Initializing submit tracking');
2978
+ logger$4.log('Initializing submit tracking');
2968
2979
 
2969
2980
  this.listenerSubmit = win.addEventListener(EV_SUBMIT, function(ev) {
2970
2981
  if (!this.getConfig(CONFIG_TRACK_SUBMIT)) {
@@ -2977,6 +2988,202 @@ Autocapture.prototype.initSubmitTracking = function() {
2977
2988
  // TODO integrate error_reporter from mixpanel instance
2978
2989
  safewrapClass(Autocapture);
2979
2990
 
2991
+ var fetch = win['fetch'];
2992
+ var logger$3 = console_with_prefix('flags');
2993
+
2994
+ var FLAGS_CONFIG_KEY = 'flags';
2995
+
2996
+ var CONFIG_CONTEXT = 'context';
2997
+ var CONFIG_DEFAULTS = {};
2998
+ CONFIG_DEFAULTS[CONFIG_CONTEXT] = {};
2999
+
3000
+ /**
3001
+ * FeatureFlagManager: support for Mixpanel's feature flagging product
3002
+ * @constructor
3003
+ */
3004
+ var FeatureFlagManager = function(initOptions) {
3005
+ this.getMpConfig = initOptions.getConfigFunc;
3006
+ this.getDistinctId = initOptions.getDistinctIdFunc;
3007
+ this.track = initOptions.trackingFunc;
3008
+ };
3009
+
3010
+ FeatureFlagManager.prototype.init = function() {
3011
+ if (!minApisSupported()) {
3012
+ logger$3.critical('Feature Flags unavailable: missing minimum required APIs');
3013
+ return;
3014
+ }
3015
+
3016
+ this.flags = null;
3017
+ this.fetchFlags();
3018
+
3019
+ this.trackedFeatures = new Set();
3020
+ };
3021
+
3022
+ FeatureFlagManager.prototype.getFullConfig = function() {
3023
+ var ffConfig = this.getMpConfig(FLAGS_CONFIG_KEY);
3024
+ if (!ffConfig) {
3025
+ // flags are completely off
3026
+ return {};
3027
+ } else if (_.isObject(ffConfig)) {
3028
+ return _.extend({}, CONFIG_DEFAULTS, ffConfig);
3029
+ } else {
3030
+ // config is non-object truthy value, return default
3031
+ return CONFIG_DEFAULTS;
3032
+ }
3033
+ };
3034
+
3035
+ FeatureFlagManager.prototype.getConfig = function(key) {
3036
+ return this.getFullConfig()[key];
3037
+ };
3038
+
3039
+ FeatureFlagManager.prototype.isSystemEnabled = function() {
3040
+ return !!this.getMpConfig(FLAGS_CONFIG_KEY);
3041
+ };
3042
+
3043
+ FeatureFlagManager.prototype.areFlagsReady = function() {
3044
+ if (!this.isSystemEnabled()) {
3045
+ logger$3.error('Feature Flags not enabled');
3046
+ }
3047
+ return !!this.flags;
3048
+ };
3049
+
3050
+ FeatureFlagManager.prototype.fetchFlags = function() {
3051
+ if (!this.isSystemEnabled()) {
3052
+ return;
3053
+ }
3054
+
3055
+ var distinctId = this.getDistinctId();
3056
+ logger$3.log('Fetching flags for distinct ID: ' + distinctId);
3057
+ var reqParams = {
3058
+ 'context': _.extend({'distinct_id': distinctId}, this.getConfig(CONFIG_CONTEXT))
3059
+ };
3060
+ this.fetchPromise = win['fetch'](this.getMpConfig('api_host') + '/' + this.getMpConfig('api_routes')['flags'], {
3061
+ 'method': 'POST',
3062
+ 'headers': {
3063
+ 'Authorization': 'Basic ' + btoa(this.getMpConfig('token') + ':'),
3064
+ 'Content-Type': 'application/octet-stream'
3065
+ },
3066
+ 'body': JSON.stringify(reqParams)
3067
+ }).then(function(response) {
3068
+ return response.json().then(function(responseBody) {
3069
+ var responseFlags = responseBody['flags'];
3070
+ if (!responseFlags) {
3071
+ throw new Error('No flags in API response');
3072
+ }
3073
+ var flags = new Map();
3074
+ _.each(responseFlags, function(data, key) {
3075
+ flags.set(key, {
3076
+ 'key': data['variant_key'],
3077
+ 'value': data['variant_value']
3078
+ });
3079
+ });
3080
+ this.flags = flags;
3081
+ }.bind(this)).catch(function(error) {
3082
+ logger$3.error(error);
3083
+ });
3084
+ }.bind(this)).catch(function() {});
3085
+ };
3086
+
3087
+ FeatureFlagManager.prototype.getVariant = function(featureName, fallback) {
3088
+ if (!this.fetchPromise) {
3089
+ return new Promise(function(resolve) {
3090
+ logger$3.critical('Feature Flags not initialized');
3091
+ resolve(fallback);
3092
+ });
3093
+ }
3094
+
3095
+ return this.fetchPromise.then(function() {
3096
+ return this.getVariantSync(featureName, fallback);
3097
+ }.bind(this)).catch(function(error) {
3098
+ logger$3.error(error);
3099
+ return fallback;
3100
+ });
3101
+ };
3102
+
3103
+ FeatureFlagManager.prototype.getVariantSync = function(featureName, fallback) {
3104
+ if (!this.areFlagsReady()) {
3105
+ logger$3.log('Flags not loaded yet');
3106
+ return fallback;
3107
+ }
3108
+ var feature = this.flags.get(featureName);
3109
+ if (!feature) {
3110
+ logger$3.log('No flag found: "' + featureName + '"');
3111
+ return fallback;
3112
+ }
3113
+ this.trackFeatureCheck(featureName, feature);
3114
+ return feature;
3115
+ };
3116
+
3117
+ FeatureFlagManager.prototype.getVariantValue = function(featureName, fallbackValue) {
3118
+ return this.getVariant(featureName, {'value': fallbackValue}).then(function(feature) {
3119
+ return feature['value'];
3120
+ }).catch(function(error) {
3121
+ logger$3.error(error);
3122
+ return fallbackValue;
3123
+ });
3124
+ };
3125
+
3126
+ // TODO remove deprecated method
3127
+ FeatureFlagManager.prototype.getFeatureData = function(featureName, fallbackValue) {
3128
+ logger$3.critical('mixpanel.flags.get_feature_data() is deprecated and will be removed in a future release. Use mixpanel.flags.get_variant_value() instead.');
3129
+ return this.getVariantValue(featureName, fallbackValue);
3130
+ };
3131
+
3132
+ FeatureFlagManager.prototype.getVariantValueSync = function(featureName, fallbackValue) {
3133
+ return this.getVariantSync(featureName, {'value': fallbackValue})['value'];
3134
+ };
3135
+
3136
+ FeatureFlagManager.prototype.isEnabled = function(featureName, fallbackValue) {
3137
+ return this.getVariantValue(featureName).then(function() {
3138
+ return this.isEnabledSync(featureName, fallbackValue);
3139
+ }.bind(this)).catch(function(error) {
3140
+ logger$3.error(error);
3141
+ return fallbackValue;
3142
+ });
3143
+ };
3144
+
3145
+ FeatureFlagManager.prototype.isEnabledSync = function(featureName, fallbackValue) {
3146
+ fallbackValue = fallbackValue || false;
3147
+ var val = this.getVariantValueSync(featureName, fallbackValue);
3148
+ if (val !== true && val !== false) {
3149
+ logger$3.error('Feature flag "' + featureName + '" value: ' + val + ' is not a boolean; returning fallback value: ' + fallbackValue);
3150
+ val = fallbackValue;
3151
+ }
3152
+ return val;
3153
+ };
3154
+
3155
+ FeatureFlagManager.prototype.trackFeatureCheck = function(featureName, feature) {
3156
+ if (this.trackedFeatures.has(featureName)) {
3157
+ return;
3158
+ }
3159
+ this.trackedFeatures.add(featureName);
3160
+ this.track('$experiment_started', {
3161
+ 'Experiment name': featureName,
3162
+ 'Variant name': feature['key'],
3163
+ '$experiment_type': 'feature_flag'
3164
+ });
3165
+ };
3166
+
3167
+ function minApisSupported() {
3168
+ return !!fetch &&
3169
+ typeof Promise !== 'undefined' &&
3170
+ typeof Map !== 'undefined' &&
3171
+ typeof Set !== 'undefined';
3172
+ }
3173
+
3174
+ safewrapClass(FeatureFlagManager);
3175
+
3176
+ FeatureFlagManager.prototype['are_flags_ready'] = FeatureFlagManager.prototype.areFlagsReady;
3177
+ FeatureFlagManager.prototype['get_variant'] = FeatureFlagManager.prototype.getVariant;
3178
+ FeatureFlagManager.prototype['get_variant_sync'] = FeatureFlagManager.prototype.getVariantSync;
3179
+ FeatureFlagManager.prototype['get_variant_value'] = FeatureFlagManager.prototype.getVariantValue;
3180
+ FeatureFlagManager.prototype['get_variant_value_sync'] = FeatureFlagManager.prototype.getVariantValueSync;
3181
+ FeatureFlagManager.prototype['is_enabled'] = FeatureFlagManager.prototype.isEnabled;
3182
+ FeatureFlagManager.prototype['is_enabled_sync'] = FeatureFlagManager.prototype.isEnabledSync;
3183
+
3184
+ // Deprecated method
3185
+ FeatureFlagManager.prototype['get_feature_data'] = FeatureFlagManager.prototype.getFeatureData;
3186
+
2980
3187
  /* eslint camelcase: "off" */
2981
3188
 
2982
3189
 
@@ -4859,18 +5066,8 @@ MixpanelPeople.prototype.union = addOptOutCheckMixpanelPeople(function(list_name
4859
5066
  * @param {Function} [callback] If provided, the callback will be called when the server responds
4860
5067
  * @deprecated
4861
5068
  */
4862
- MixpanelPeople.prototype.track_charge = addOptOutCheckMixpanelPeople(function(amount, properties, callback) {
4863
- if (!_.isNumber(amount)) {
4864
- amount = parseFloat(amount);
4865
- if (isNaN(amount)) {
4866
- console.error('Invalid value passed to mixpanel.people.track_charge - must be a number');
4867
- return;
4868
- }
4869
- }
4870
-
4871
- return this.append('$transactions', _.extend({
4872
- '$amount': amount
4873
- }, properties), callback);
5069
+ MixpanelPeople.prototype.track_charge = addOptOutCheckMixpanelPeople(function() {
5070
+ console.error('mixpanel.people.track_charge() is deprecated and no longer has any effect.');
4874
5071
  });
4875
5072
 
4876
5073
  /*
@@ -5692,10 +5889,11 @@ if (navigator['sendBeacon']) {
5692
5889
  }
5693
5890
 
5694
5891
  var DEFAULT_API_ROUTES = {
5695
- 'track': 'track/',
5892
+ 'track': 'track/',
5696
5893
  'engage': 'engage/',
5697
5894
  'groups': 'groups/',
5698
- 'record': 'record/'
5895
+ 'record': 'record/',
5896
+ 'flags': 'flags/'
5699
5897
  };
5700
5898
 
5701
5899
  /*
@@ -5704,6 +5902,7 @@ var DEFAULT_API_ROUTES = {
5704
5902
  var DEFAULT_CONFIG = {
5705
5903
  'api_host': 'https://api-js.mixpanel.com',
5706
5904
  'api_routes': DEFAULT_API_ROUTES,
5905
+ 'api_extra_query_params': {},
5707
5906
  'api_method': 'POST',
5708
5907
  'api_transport': 'XHR',
5709
5908
  'api_payload_format': PAYLOAD_TYPE_BASE64,
@@ -5713,6 +5912,7 @@ var DEFAULT_CONFIG = {
5713
5912
  'cross_site_cookie': false,
5714
5913
  'cross_subdomain_cookie': true,
5715
5914
  'error_reporter': NOOP_FUNC,
5915
+ 'flags': false,
5716
5916
  'persistence': 'cookie',
5717
5917
  'persistence_name': '',
5718
5918
  'cookie_domain': '',
@@ -5753,6 +5953,7 @@ var DEFAULT_CONFIG = {
5753
5953
  'record_block_selector': 'img, video',
5754
5954
  'record_canvas': false,
5755
5955
  'record_collect_fonts': false,
5956
+ 'record_heatmap_data': false,
5756
5957
  'record_idle_timeout_ms': 30 * 60 * 1000, // 30 minutes
5757
5958
  'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
5758
5959
  'record_mask_text_selector': '*',
@@ -5968,6 +6169,14 @@ MixpanelLib.prototype._init = function(token, config, name) {
5968
6169
  }, '');
5969
6170
  }
5970
6171
 
6172
+ this.flags = new FeatureFlagManager({
6173
+ getConfigFunc: _.bind(this.get_config, this),
6174
+ getDistinctIdFunc: _.bind(this.get_distinct_id, this),
6175
+ trackingFunc: _.bind(this.track, this)
6176
+ });
6177
+ this.flags.init();
6178
+ this['flags'] = this.flags;
6179
+
5971
6180
  this.autocapture = new Autocapture(this);
5972
6181
  this.autocapture.init();
5973
6182
 
@@ -6093,6 +6302,10 @@ MixpanelLib.prototype.resume_session_recording = function () {
6093
6302
  }
6094
6303
  };
6095
6304
 
6305
+ MixpanelLib.prototype.is_recording_heatmap_data = function () {
6306
+ return this._get_session_replay_id() && this.get_config('record_heatmap_data');
6307
+ };
6308
+
6096
6309
  MixpanelLib.prototype.get_session_recording_properties = function () {
6097
6310
  var props = {};
6098
6311
  var replay_id = this._get_session_replay_id();
@@ -6277,6 +6490,8 @@ MixpanelLib.prototype._send_request = function(url, data, options, callback) {
6277
6490
  delete data['data'];
6278
6491
  }
6279
6492
 
6493
+ _.extend(data, this.get_config('api_extra_query_params'));
6494
+
6280
6495
  url += '?' + _.HTTPBuildQuery(data);
6281
6496
 
6282
6497
  var lib = this;
@@ -7174,6 +7389,11 @@ MixpanelLib.prototype.identify = function(
7174
7389
  '$anon_distinct_id': previous_distinct_id
7175
7390
  }, {skip_hooks: true});
7176
7391
  }
7392
+
7393
+ // check feature flags again if distinct id has changed
7394
+ if (new_distinct_id !== previous_distinct_id) {
7395
+ this.flags.fetchFlags();
7396
+ }
7177
7397
  };
7178
7398
 
7179
7399
  /**
@@ -7188,6 +7408,8 @@ MixpanelLib.prototype.reset = function() {
7188
7408
  'distinct_id': DEVICE_ID_PREFIX + uuid,
7189
7409
  '$device_id': uuid
7190
7410
  }, '');
7411
+ this.stop_session_recording();
7412
+ this._check_and_start_session_recording();
7191
7413
  };
7192
7414
 
7193
7415
  /**
@@ -7448,7 +7670,7 @@ MixpanelLib.prototype.set_config = function(config) {
7448
7670
  }
7449
7671
  Config.DEBUG = Config.DEBUG || this.get_config('debug');
7450
7672
 
7451
- if ('autocapture' in config && this.autocapture) {
7673
+ if (('autocapture' in config || 'record_heatmap_data' in config) && this.autocapture) {
7452
7674
  this.autocapture.init();
7453
7675
  }
7454
7676
  }