mixpanel-browser 2.46.0 → 2.48.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 @@ define(function () { 'use strict';
2
2
 
3
3
  var Config = {
4
4
  DEBUG: false,
5
- LIB_VERSION: '2.46.0'
5
+ LIB_VERSION: '2.48.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
@@ -832,20 +832,24 @@ define(function () { 'use strict';
832
832
 
833
833
  _.UUID = (function() {
834
834
 
835
- // Time/ticks information
836
- // 1*new Date() is a cross browser version of Date.now()
835
+ // Time-based entropy
837
836
  var T = function() {
838
- var d = 1 * new Date(),
839
- i = 0;
840
-
841
- // this while loop figures how many browser ticks go by
842
- // before 1*new Date() returns a new number, ie the amount
843
- // of ticks that go by per millisecond
844
- while (d == 1 * new Date()) {
845
- i++;
837
+ var time = 1 * new Date(); // cross-browser version of Date.now()
838
+ var ticks;
839
+ if (window$1.performance && window$1.performance.now) {
840
+ ticks = window$1.performance.now();
841
+ } else {
842
+ // fall back to busy loop
843
+ ticks = 0;
844
+
845
+ // this while loop figures how many browser ticks go by
846
+ // before 1*new Date() returns a new number, ie the amount
847
+ // of ticks that go by per millisecond
848
+ while (time == 1 * new Date()) {
849
+ ticks++;
850
+ }
846
851
  }
847
-
848
- return d.toString(16) + i.toString(16);
852
+ return time.toString(16) + Math.floor(ticks).toString(16);
849
853
  };
850
854
 
851
855
  // Math.Random entropy
@@ -900,6 +904,7 @@ define(function () { 'use strict';
900
904
  'baiduspider',
901
905
  'bingbot',
902
906
  'bingpreview',
907
+ 'chrome-lighthouse',
903
908
  'facebookexternal',
904
909
  'petalbot',
905
910
  'pinterest',
@@ -1412,21 +1417,42 @@ define(function () { 'use strict';
1412
1417
  };
1413
1418
  })();
1414
1419
 
1420
+ var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
1421
+ var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid'];
1422
+
1415
1423
  _.info = {
1416
- campaignParams: function() {
1417
- var campaign_keywords = 'utm_source utm_medium utm_campaign utm_content utm_term'.split(' '),
1418
- kw = '',
1424
+ campaignParams: function(default_value) {
1425
+ var kw = '',
1419
1426
  params = {};
1420
- _.each(campaign_keywords, function(kwkey) {
1427
+ _.each(CAMPAIGN_KEYWORDS, function(kwkey) {
1421
1428
  kw = _.getQueryParam(document$1.URL, kwkey);
1422
1429
  if (kw.length) {
1423
1430
  params[kwkey] = kw;
1431
+ } else if (default_value !== undefined) {
1432
+ params[kwkey] = default_value;
1433
+ }
1434
+ });
1435
+
1436
+ return params;
1437
+ },
1438
+
1439
+ clickParams: function() {
1440
+ var id = '',
1441
+ params = {};
1442
+ _.each(CLICK_IDS, function(idkey) {
1443
+ id = _.getQueryParam(document$1.URL, idkey);
1444
+ if (id.length) {
1445
+ params[idkey] = id;
1424
1446
  }
1425
1447
  });
1426
1448
 
1427
1449
  return params;
1428
1450
  },
1429
1451
 
1452
+ marketingParams: function() {
1453
+ return _.extend(_.info.campaignParams(), _.info.clickParams());
1454
+ },
1455
+
1430
1456
  searchEngine: function(referrer) {
1431
1457
  if (referrer.search('https?://(.*)google.([^/?]*)') === 0) {
1432
1458
  return 'google';
@@ -1623,12 +1649,13 @@ define(function () { 'use strict';
1623
1649
  });
1624
1650
  },
1625
1651
 
1626
- pageviewInfo: function(page) {
1652
+ mpPageViewProperties: function() {
1627
1653
  return _.strip_empty_properties({
1628
- 'mp_page': page,
1629
- 'mp_referrer': document$1.referrer,
1630
- 'mp_browser': _.info.browser(userAgent, navigator.vendor, windowOpera),
1631
- 'mp_platform': _.info.os()
1654
+ 'current_page_title': document$1.title,
1655
+ 'current_domain': window$1.location.hostname,
1656
+ 'current_url_path': window$1.location.pathname,
1657
+ 'current_url_protocol': window$1.location.protocol,
1658
+ 'current_url_search': window$1.location.search
1632
1659
  });
1633
1660
  }
1634
1661
  };
@@ -3106,7 +3133,7 @@ define(function () { 'use strict';
3106
3133
  return this._mixpanel._track_or_batch({
3107
3134
  type: 'groups',
3108
3135
  data: date_encoded_data,
3109
- endpoint: this._get_config('api_host') + '/groups/',
3136
+ endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['groups'],
3110
3137
  batcher: this._mixpanel.request_batchers.groups
3111
3138
  }, callback);
3112
3139
  };
@@ -3467,7 +3494,7 @@ define(function () { 'use strict';
3467
3494
  return this._mixpanel._track_or_batch({
3468
3495
  type: 'people',
3469
3496
  data: date_encoded_data,
3470
- endpoint: this._get_config('api_host') + '/engage/',
3497
+ endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['engage'],
3471
3498
  batcher: this._mixpanel.request_batchers.people
3472
3499
  }, callback);
3473
3500
  };
@@ -3503,11 +3530,12 @@ define(function () { 'use strict';
3503
3530
 
3504
3531
  MixpanelPeople.prototype._flush_one_queue = function(action, action_method, callback, queue_to_params_fn) {
3505
3532
  var _this = this;
3506
- var queued_data = _.extend({}, this._mixpanel['persistence']._get_queue(action));
3533
+ var queued_data = _.extend({}, this._mixpanel['persistence'].load_queue(action));
3507
3534
  var action_params = queued_data;
3508
3535
 
3509
3536
  if (!_.isUndefined(queued_data) && _.isObject(queued_data) && !_.isEmptyObject(queued_data)) {
3510
3537
  _this._mixpanel['persistence']._pop_from_people_queue(action, queued_data);
3538
+ _this._mixpanel['persistence'].save();
3511
3539
  if (queue_to_params_fn) {
3512
3540
  action_params = queue_to_params_fn(queued_data);
3513
3541
  }
@@ -3529,8 +3557,6 @@ define(function () { 'use strict';
3529
3557
  _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback
3530
3558
  ) {
3531
3559
  var _this = this;
3532
- var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION);
3533
- var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION);
3534
3560
 
3535
3561
  this._flush_one_queue(SET_ACTION, this.set, _set_callback);
3536
3562
  this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback);
@@ -3540,6 +3566,7 @@ define(function () { 'use strict';
3540
3566
 
3541
3567
  // we have to fire off each $append individually since there is
3542
3568
  // no concat method server side
3569
+ var $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION);
3543
3570
  if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) {
3544
3571
  var $append_item;
3545
3572
  var append_callback = function(response, data) {
@@ -3551,16 +3578,17 @@ define(function () { 'use strict';
3551
3578
  }
3552
3579
  };
3553
3580
  for (var i = $append_queue.length - 1; i >= 0; i--) {
3581
+ $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION);
3554
3582
  $append_item = $append_queue.pop();
3583
+ _this._mixpanel['persistence'].save();
3555
3584
  if (!_.isEmptyObject($append_item)) {
3556
3585
  _this.append($append_item, append_callback);
3557
3586
  }
3558
3587
  }
3559
- // Save the shortened append queue
3560
- _this._mixpanel['persistence'].save();
3561
3588
  }
3562
3589
 
3563
3590
  // same for $remove
3591
+ var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION);
3564
3592
  if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) {
3565
3593
  var $remove_item;
3566
3594
  var remove_callback = function(response, data) {
@@ -3572,12 +3600,13 @@ define(function () { 'use strict';
3572
3600
  }
3573
3601
  };
3574
3602
  for (var j = $remove_queue.length - 1; j >= 0; j--) {
3603
+ $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION);
3575
3604
  $remove_item = $remove_queue.pop();
3605
+ _this._mixpanel['persistence'].save();
3576
3606
  if (!_.isEmptyObject($remove_item)) {
3577
3607
  _this.remove($remove_item, remove_callback);
3578
3608
  }
3579
3609
  }
3580
- _this._mixpanel['persistence'].save();
3581
3610
  }
3582
3611
  };
3583
3612
 
@@ -3659,6 +3688,9 @@ define(function () { 'use strict';
3659
3688
 
3660
3689
  MixpanelPersistence.prototype.properties = function() {
3661
3690
  var p = {};
3691
+
3692
+ this.load();
3693
+
3662
3694
  // Filter out reserved properties
3663
3695
  _.each(this['props'], function(v, k) {
3664
3696
  if (!_.include(RESERVED_PROPERTIES, k)) {
@@ -3735,6 +3767,7 @@ define(function () { 'use strict';
3735
3767
 
3736
3768
  MixpanelPersistence.prototype.save = function() {
3737
3769
  if (this.disabled) { return; }
3770
+
3738
3771
  this.storage.set(
3739
3772
  this.name,
3740
3773
  _.JSONEncode(this['props']),
@@ -3746,6 +3779,11 @@ define(function () { 'use strict';
3746
3779
  );
3747
3780
  };
3748
3781
 
3782
+ MixpanelPersistence.prototype.load_prop = function(key) {
3783
+ this.load();
3784
+ return this['props'][key];
3785
+ };
3786
+
3749
3787
  MixpanelPersistence.prototype.remove = function() {
3750
3788
  // remove both domain and subdomain cookies
3751
3789
  this.storage.remove(this.name, false, this.cookie_domain);
@@ -3769,6 +3807,8 @@ define(function () { 'use strict';
3769
3807
  if (typeof(default_value) === 'undefined') { default_value = 'None'; }
3770
3808
  this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days;
3771
3809
 
3810
+ this.load();
3811
+
3772
3812
  _.each(props, function(val, prop) {
3773
3813
  if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) {
3774
3814
  this['props'][prop] = val;
@@ -3790,8 +3830,8 @@ define(function () { 'use strict';
3790
3830
  if (_.isObject(props)) {
3791
3831
  this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days;
3792
3832
 
3833
+ this.load();
3793
3834
  _.extend(this['props'], props);
3794
-
3795
3835
  this.save();
3796
3836
 
3797
3837
  return true;
@@ -3800,19 +3840,13 @@ define(function () { 'use strict';
3800
3840
  };
3801
3841
 
3802
3842
  MixpanelPersistence.prototype.unregister = function(prop) {
3843
+ this.load();
3803
3844
  if (prop in this['props']) {
3804
3845
  delete this['props'][prop];
3805
3846
  this.save();
3806
3847
  }
3807
3848
  };
3808
3849
 
3809
- MixpanelPersistence.prototype.update_campaign_params = function() {
3810
- if (!this.campaign_params_saved) {
3811
- this.register_once(_.info.campaignParams());
3812
- this.campaign_params_saved = true;
3813
- }
3814
- };
3815
-
3816
3850
  MixpanelPersistence.prototype.update_search_keyword = function(referrer) {
3817
3851
  this.register(_.info.searchInfo(referrer));
3818
3852
  };
@@ -3833,19 +3867,6 @@ define(function () { 'use strict';
3833
3867
  });
3834
3868
  };
3835
3869
 
3836
- // safely fills the passed in object with stored properties,
3837
- // does not override any properties defined in both
3838
- // returns the passed in object
3839
- MixpanelPersistence.prototype.safe_merge = function(props) {
3840
- _.each(this['props'], function(val, prop) {
3841
- if (!(prop in props)) {
3842
- props[prop] = val;
3843
- }
3844
- });
3845
-
3846
- return props;
3847
- };
3848
-
3849
3870
  MixpanelPersistence.prototype.update_config = function(config) {
3850
3871
  this.default_expiry = this.expire_days = config['cookie_expiration'];
3851
3872
  this.set_disabled(config['disable_persistence']);
@@ -3989,7 +4010,7 @@ define(function () { 'use strict';
3989
4010
  };
3990
4011
 
3991
4012
  MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) {
3992
- var q = this._get_queue(queue);
4013
+ var q = this['props'][this._get_queue_key(queue)];
3993
4014
  if (!_.isUndefined(q)) {
3994
4015
  _.each(data, function(v, k) {
3995
4016
  if (queue === APPEND_ACTION || queue === REMOVE_ACTION) {
@@ -4005,11 +4026,13 @@ define(function () { 'use strict';
4005
4026
  delete q[k];
4006
4027
  }
4007
4028
  }, this);
4008
-
4009
- this.save();
4010
4029
  }
4011
4030
  };
4012
4031
 
4032
+ MixpanelPersistence.prototype.load_queue = function(queue) {
4033
+ return this.load_prop(this._get_queue_key(queue));
4034
+ };
4035
+
4013
4036
  MixpanelPersistence.prototype._get_queue_key = function(queue) {
4014
4037
  if (queue === SET_ACTION) {
4015
4038
  return SET_QUEUE_KEY;
@@ -4030,25 +4053,21 @@ define(function () { 'use strict';
4030
4053
  }
4031
4054
  };
4032
4055
 
4033
- MixpanelPersistence.prototype._get_queue = function(queue) {
4034
- return this['props'][this._get_queue_key(queue)];
4035
- };
4036
4056
  MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) {
4037
4057
  var key = this._get_queue_key(queue);
4038
4058
  default_val = _.isUndefined(default_val) ? {} : default_val;
4039
-
4040
4059
  return this['props'][key] || (this['props'][key] = default_val);
4041
4060
  };
4042
4061
 
4043
4062
  MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) {
4044
- var timers = this['props'][EVENT_TIMERS_KEY] || {};
4063
+ var timers = this.load_prop(EVENT_TIMERS_KEY) || {};
4045
4064
  timers[event_name] = timestamp;
4046
4065
  this['props'][EVENT_TIMERS_KEY] = timers;
4047
4066
  this.save();
4048
4067
  };
4049
4068
 
4050
4069
  MixpanelPersistence.prototype.remove_event_timer = function(event_name) {
4051
- var timers = this['props'][EVENT_TIMERS_KEY] || {};
4070
+ var timers = this.load_prop(EVENT_TIMERS_KEY) || {};
4052
4071
  var timestamp = timers[event_name];
4053
4072
  if (!_.isUndefined(timestamp)) {
4054
4073
  delete this['props'][EVENT_TIMERS_KEY][event_name];
@@ -4119,11 +4138,18 @@ define(function () { 'use strict';
4119
4138
  };
4120
4139
  }
4121
4140
 
4141
+ var DEFAULT_API_ROUTES = {
4142
+ 'track': 'track/',
4143
+ 'engage': 'engage/',
4144
+ 'groups': 'groups/'
4145
+ };
4146
+
4122
4147
  /*
4123
4148
  * Module-level globals
4124
4149
  */
4125
4150
  var DEFAULT_CONFIG = {
4126
4151
  'api_host': 'https://api-js.mixpanel.com',
4152
+ 'api_routes': DEFAULT_API_ROUTES,
4127
4153
  'api_method': 'POST',
4128
4154
  'api_transport': 'XHR',
4129
4155
  'api_payload_format': PAYLOAD_TYPE_BASE64,
@@ -4137,6 +4163,9 @@ define(function () { 'use strict';
4137
4163
  'cookie_domain': '',
4138
4164
  'cookie_name': '',
4139
4165
  'loaded': NOOP_FUNC,
4166
+ 'track_marketing': true,
4167
+ 'track_pageview': false,
4168
+ 'skip_first_touch_marketing': false,
4140
4169
  'store_google': true,
4141
4170
  'save_referrer': true,
4142
4171
  'test': false,
@@ -4203,6 +4232,25 @@ define(function () { 'use strict';
4203
4232
  instance['people'] = new MixpanelPeople();
4204
4233
  instance['people']._init(instance);
4205
4234
 
4235
+ if (!instance.get_config('skip_first_touch_marketing')) {
4236
+ // We need null UTM params in the object because
4237
+ // UTM parameters act as a tuple. If any UTM param
4238
+ // is present, then we set all UTM params including
4239
+ // empty ones together
4240
+ var utm_params = _.info.campaignParams(null);
4241
+ var initial_utm_params = {};
4242
+ var has_utm = false;
4243
+ _.each(utm_params, function(utm_value, utm_key) {
4244
+ initial_utm_params['initial_' + utm_key] = utm_value;
4245
+ if (utm_value) {
4246
+ has_utm = true;
4247
+ }
4248
+ });
4249
+ if (has_utm) {
4250
+ instance['people'].set_once(initial_utm_params);
4251
+ }
4252
+ }
4253
+
4206
4254
  // if any instance on the page has debug = true, we set the
4207
4255
  // global debug to be true
4208
4256
  Config.DEBUG = Config.DEBUG || instance.get_config('debug');
@@ -4234,7 +4282,7 @@ define(function () { 'use strict';
4234
4282
  * mixpanel.library_name.track(...);
4235
4283
  *
4236
4284
  * @param {String} token Your Mixpanel API token
4237
- * @param {Object} [config] A dictionary of config options to override. <a href="https://github.com/mixpanel/mixpanel-js/blob/8b2e1f7b/src/mixpanel-core.js#L87-L110">See a list of default config options</a>.
4285
+ * @param {Object} [config] A dictionary of config options to override. <a href="https://github.com/mixpanel/mixpanel-js/blob/v2.46.0/src/mixpanel-core.js#L88-L127">See a list of default config options</a>.
4238
4286
  * @param {String} [name] The name for the new mixpanel instance that you want created
4239
4287
  */
4240
4288
  MixpanelLib.prototype.init = function (token, config, name) {
@@ -4272,7 +4320,7 @@ define(function () { 'use strict';
4272
4320
  // default to JSON payload for standard mixpanel.com API hosts
4273
4321
  if (!('api_payload_format' in config)) {
4274
4322
  var api_host = config['api_host'] || DEFAULT_CONFIG['api_host'];
4275
- if (api_host.match(/\.mixpanel\.com$/)) {
4323
+ if (api_host.match(/\.mixpanel\.com/)) {
4276
4324
  variable_features['api_payload_format'] = PAYLOAD_TYPE_JSON;
4277
4325
  }
4278
4326
  }
@@ -4300,6 +4348,10 @@ define(function () { 'use strict';
4300
4348
  if (!_.localStorage.is_supported(true) || !USE_XHR) {
4301
4349
  this._batch_requests = false;
4302
4350
  console.log('Turning off Mixpanel request-queueing; needs XHR and localStorage support');
4351
+ _.each(this.get_batcher_configs(), function(batcher_config) {
4352
+ console.log('Clearing batch queue ' + batcher_config.queue_key);
4353
+ _.localStorage.remove(batcher_config.queue_key);
4354
+ });
4303
4355
  } else {
4304
4356
  this.init_batchers();
4305
4357
  if (sendBeacon && window$1.addEventListener) {
@@ -4347,6 +4399,10 @@ define(function () { 'use strict';
4347
4399
  '$device_id': uuid
4348
4400
  }, '');
4349
4401
  }
4402
+
4403
+ if (this.get_config('track_pageview')) {
4404
+ this.track_pageview();
4405
+ }
4350
4406
  };
4351
4407
 
4352
4408
  // Private methods
@@ -4360,7 +4416,7 @@ define(function () { 'use strict';
4360
4416
  MixpanelLib.prototype._set_default_superprops = function() {
4361
4417
  this['persistence'].update_search_keyword(document$1.referrer);
4362
4418
  if (this.get_config('store_google')) {
4363
- this['persistence'].update_campaign_params();
4419
+ this.register(_.info.campaignParams(), {persistent: false});
4364
4420
  }
4365
4421
  if (this.get_config('save_referrer')) {
4366
4422
  this['persistence'].update_referrer_info(document$1.referrer);
@@ -4643,12 +4699,22 @@ define(function () { 'use strict';
4643
4699
  return !!this.request_batchers.events;
4644
4700
  };
4645
4701
 
4702
+ MixpanelLib.prototype.get_batcher_configs = function() {
4703
+ var queue_prefix = '__mpq_' + this.get_config('token');
4704
+ var api_routes = this.get_config('api_routes');
4705
+ this._batcher_configs = this._batcher_configs || {
4706
+ events: {type: 'events', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'},
4707
+ people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'},
4708
+ groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'}
4709
+ };
4710
+ return this._batcher_configs;
4711
+ };
4712
+
4646
4713
  MixpanelLib.prototype.init_batchers = function() {
4647
- var token = this.get_config('token');
4648
4714
  if (!this.are_batchers_initialized()) {
4649
4715
  var batcher_for = _.bind(function(attrs) {
4650
4716
  return new RequestBatcher(
4651
- '__mpq_' + token + attrs.queue_suffix,
4717
+ attrs.queue_key,
4652
4718
  {
4653
4719
  libConfig: this['config'],
4654
4720
  sendRequestFunc: _.bind(function(data, options, cb) {
@@ -4667,10 +4733,11 @@ define(function () { 'use strict';
4667
4733
  }
4668
4734
  );
4669
4735
  }, this);
4736
+ var batcher_configs = this.get_batcher_configs();
4670
4737
  this.request_batchers = {
4671
- events: batcher_for({type: 'events', endpoint: '/track/', queue_suffix: '_ev'}),
4672
- people: batcher_for({type: 'people', endpoint: '/engage/', queue_suffix: '_pp'}),
4673
- groups: batcher_for({type: 'groups', endpoint: '/groups/', queue_suffix: '_gr'})
4738
+ events: batcher_for(batcher_configs.events),
4739
+ people: batcher_for(batcher_configs.people),
4740
+ groups: batcher_for(batcher_configs.groups)
4674
4741
  };
4675
4742
  }
4676
4743
  if (this.get_config('batch_autostart')) {
@@ -4679,6 +4746,7 @@ define(function () { 'use strict';
4679
4746
  };
4680
4747
 
4681
4748
  MixpanelLib.prototype.start_batch_senders = function() {
4749
+ this._batchers_were_started = true;
4682
4750
  if (this.are_batchers_initialized()) {
4683
4751
  this._batch_requests = true;
4684
4752
  _.each(this.request_batchers, function(batcher) {
@@ -4830,7 +4898,7 @@ define(function () { 'use strict';
4830
4898
  }
4831
4899
 
4832
4900
  // set defaults
4833
- properties = properties || {};
4901
+ properties = _.extend({}, properties);
4834
4902
  properties['token'] = this.get_config('token');
4835
4903
 
4836
4904
  // set $duration if time_event was previously called for this event
@@ -4842,6 +4910,10 @@ define(function () { 'use strict';
4842
4910
 
4843
4911
  this._set_default_superprops();
4844
4912
 
4913
+ var marketing_properties = this.get_config('track_marketing')
4914
+ ? _.info.marketingParams()
4915
+ : {};
4916
+
4845
4917
  // note: extend writes to the first object, so lets make sure we
4846
4918
  // don't write to the persistence properties object and info
4847
4919
  // properties object by passing in a new object
@@ -4850,6 +4922,7 @@ define(function () { 'use strict';
4850
4922
  properties = _.extend(
4851
4923
  {},
4852
4924
  _.info.properties(),
4925
+ marketing_properties,
4853
4926
  this['persistence'].properties(),
4854
4927
  this.unpersisted_superprops,
4855
4928
  properties
@@ -4871,7 +4944,7 @@ define(function () { 'use strict';
4871
4944
  var ret = this._track_or_batch({
4872
4945
  type: 'events',
4873
4946
  data: data,
4874
- endpoint: this.get_config('api_host') + '/track/',
4947
+ endpoint: this.get_config('api_host') + '/' + this.get_config('api_routes')['track'],
4875
4948
  batcher: this.request_batchers.events,
4876
4949
  should_send_immediately: should_send_immediately,
4877
4950
  send_request_options: options
@@ -4917,13 +4990,14 @@ define(function () { 'use strict';
4917
4990
  */
4918
4991
  MixpanelLib.prototype.add_group = addOptOutCheckMixpanelLib(function(group_key, group_id, callback) {
4919
4992
  var old_values = this.get_property(group_key);
4993
+ var prop = {};
4920
4994
  if (old_values === undefined) {
4921
- var prop = {};
4922
4995
  prop[group_key] = [group_id];
4923
4996
  this.register(prop);
4924
4997
  } else {
4925
4998
  if (old_values.indexOf(group_id) === -1) {
4926
4999
  old_values.push(group_id);
5000
+ prop[group_key] = old_values;
4927
5001
  this.register(prop);
4928
5002
  }
4929
5003
  }
@@ -5010,17 +5084,54 @@ define(function () { 'use strict';
5010
5084
  };
5011
5085
 
5012
5086
  /**
5013
- * Track mp_page_view event. This is now ignored by the server.
5087
+ * Track a default Mixpanel page view event, which includes extra default event properties to
5088
+ * improve page view data. The `config.track_pageview` option for <a href="#mixpanelinit">mixpanel.init()</a>
5089
+ * may be turned on for tracking page loads automatically.
5014
5090
  *
5015
- * @param {String} [page] The url of the page to record. If you don't include this, it defaults to the current url.
5016
- * @deprecated
5091
+ * ### Usage
5092
+ *
5093
+ * // track a default $mp_web_page_view event
5094
+ * mixpanel.track_pageview();
5095
+ *
5096
+ * // track a page view event with additional event properties
5097
+ * mixpanel.track_pageview({'ab_test_variant': 'card-layout-b'});
5098
+ *
5099
+ * // example approach to track page views on different page types as event properties
5100
+ * mixpanel.track_pageview({'page': 'pricing'});
5101
+ * mixpanel.track_pageview({'page': 'homepage'});
5102
+ *
5103
+ * // UNCOMMON: Tracking a page view event with a custom event_name option. NOT expected to be used for
5104
+ * // individual pages on the same site or product. Use cases for custom event_name may be page
5105
+ * // views on different products or internal applications that are considered completely separate
5106
+ * mixpanel.track_pageview({'page': 'customer-search'}, {'event_name': '[internal] Admin Page View'});
5107
+ *
5108
+ * @param {Object} [properties] An optional set of additional properties to send with the page view event
5109
+ * @param {Object} [options] Page view tracking options
5110
+ * @param {String} [options.event_name] - Alternate name for the tracking event
5111
+ * @returns {Boolean|Object} If the tracking request was successfully initiated/queued, an object
5112
+ * with the tracking payload sent to the API server is returned; otherwise false.
5017
5113
  */
5018
- MixpanelLib.prototype.track_pageview = function(page) {
5019
- if (_.isUndefined(page)) {
5020
- page = document$1.location.href;
5114
+ MixpanelLib.prototype.track_pageview = addOptOutCheckMixpanelLib(function(properties, options) {
5115
+ if (typeof properties !== 'object') {
5116
+ properties = {};
5021
5117
  }
5022
- this.track('mp_page_view', _.info.pageviewInfo(page));
5023
- };
5118
+ options = options || {};
5119
+ var event_name = options['event_name'] || '$mp_web_page_view';
5120
+
5121
+ var default_page_properties = _.extend(
5122
+ _.info.mpPageViewProperties(),
5123
+ _.info.campaignParams(),
5124
+ _.info.clickParams()
5125
+ );
5126
+
5127
+ var event_properties = _.extend(
5128
+ {},
5129
+ default_page_properties,
5130
+ properties
5131
+ );
5132
+
5133
+ return this.track(event_name, event_properties);
5134
+ });
5024
5135
 
5025
5136
  /**
5026
5137
  * Track clicks on a set of document elements. Selector must be a
@@ -5431,6 +5542,16 @@ define(function () { 'use strict';
5431
5542
  * The default config is:
5432
5543
  *
5433
5544
  * {
5545
+ * // host for requests (customizable for e.g. a local proxy)
5546
+ * api_host: 'https://api-js.mixpanel.com',
5547
+ *
5548
+ * // endpoints for different types of requests
5549
+ * api_routes: {
5550
+ * track: 'track/',
5551
+ * engage: 'engage/',
5552
+ * groups: 'groups/',
5553
+ * }
5554
+ *
5434
5555
  * // HTTP method for tracking requests
5435
5556
  * api_method: 'POST'
5436
5557
  *
@@ -5516,10 +5637,20 @@ define(function () { 'use strict';
5516
5637
  * // secure, meaning they will only be transmitted over https
5517
5638
  * secure_cookie: false
5518
5639
  *
5640
+ * // disables enriching user profiles with first touch marketing data
5641
+ * skip_first_touch_marketing: false
5642
+ *
5519
5643
  * // the amount of time track_links will
5520
5644
  * // wait for Mixpanel's servers to respond
5521
5645
  * track_links_timeout: 300
5522
5646
  *
5647
+ * // adds any UTM parameters and click IDs present on the page to any events fired
5648
+ * track_marketing: true
5649
+ *
5650
+ * // enables automatic page view tracking using default page view events through
5651
+ * // the track_pageview() method
5652
+ * track_pageview: false
5653
+ *
5523
5654
  * // if you set upgrade to be true, the library will check for
5524
5655
  * // a cookie from our old js library and import super
5525
5656
  * // properties from it, then the old cookie is deleted
@@ -5604,7 +5735,7 @@ define(function () { 'use strict';
5604
5735
  * @param {String} property_name The name of the super property you want to retrieve
5605
5736
  */
5606
5737
  MixpanelLib.prototype.get_property = function(property_name) {
5607
- return this['persistence']['props'][property_name];
5738
+ return this['persistence'].load_prop([property_name]);
5608
5739
  };
5609
5740
 
5610
5741
  MixpanelLib.prototype.toString = function() {
@@ -5677,9 +5808,13 @@ define(function () { 'use strict';
5677
5808
  }
5678
5809
 
5679
5810
  if (disabled) {
5680
- _.each(this.request_batchers, function(batcher) {
5681
- batcher.clear();
5682
- });
5811
+ this.stop_batch_senders();
5812
+ } else {
5813
+ // only start batchers after opt-in if they have previously been started
5814
+ // in order to avoid unintentionally starting up batching for the first time
5815
+ if (this._batchers_were_started) {
5816
+ this.start_batch_senders();
5817
+ }
5683
5818
  }
5684
5819
  };
5685
5820
 
@@ -5881,37 +6016,38 @@ define(function () { 'use strict';
5881
6016
  // EXPORTS (for closure compiler)
5882
6017
 
5883
6018
  // MixpanelLib Exports
5884
- MixpanelLib.prototype['init'] = MixpanelLib.prototype.init;
5885
- MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset;
5886
- MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable;
5887
- MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event;
5888
- MixpanelLib.prototype['track'] = MixpanelLib.prototype.track;
5889
- MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links;
5890
- MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms;
5891
- MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview;
5892
- MixpanelLib.prototype['register'] = MixpanelLib.prototype.register;
5893
- MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once;
5894
- MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister;
5895
- MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify;
5896
- MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias;
5897
- MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
5898
- MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
5899
- MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
5900
- MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
5901
- MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
5902
- MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
5903
- MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking;
5904
- MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking;
5905
- MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking;
5906
- MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking;
5907
- MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking;
5908
- MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group;
5909
- MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group;
5910
- MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group;
5911
- MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group;
5912
- MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups;
5913
- MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders;
5914
- MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders;
6019
+ MixpanelLib.prototype['init'] = MixpanelLib.prototype.init;
6020
+ MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset;
6021
+ MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable;
6022
+ MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event;
6023
+ MixpanelLib.prototype['track'] = MixpanelLib.prototype.track;
6024
+ MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links;
6025
+ MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms;
6026
+ MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview;
6027
+ MixpanelLib.prototype['register'] = MixpanelLib.prototype.register;
6028
+ MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once;
6029
+ MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister;
6030
+ MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify;
6031
+ MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias;
6032
+ MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
6033
+ MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
6034
+ MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
6035
+ MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
6036
+ MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
6037
+ MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
6038
+ MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking;
6039
+ MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking;
6040
+ MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking;
6041
+ MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking;
6042
+ MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking;
6043
+ MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group;
6044
+ MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group;
6045
+ MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group;
6046
+ MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group;
6047
+ MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups;
6048
+ MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders;
6049
+ MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders;
6050
+ MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES;
5915
6051
 
5916
6052
  // MixpanelPersistence Exports
5917
6053
  MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties;