mixpanel-browser 2.45.0 → 2.47.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.
@@ -13,7 +13,7 @@ jobs:
13
13
 
14
14
  strategy:
15
15
  matrix:
16
- node-version: [14.x, 16.x]
16
+ node-version: [16.x, 18.x, 20.x]
17
17
 
18
18
  steps:
19
19
  - uses: actions/checkout@v2
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ **2.47.0** (27 Apr 2023)
2
+ - Collect richer marketing attribution properties for multi-touch attribution
3
+ - New implementation of previously-deprecated track_pageview() method and init option to send automatically
4
+ - Use performance.now when available for time-based entropy component of UUID-generation (thanks @adrianherd)
5
+ - looser API Host check for default JSON-payload sending to mipxanel.com hosts
6
+
7
+ **2.46.0** (20 Mar 2023)
8
+ - Updates for new identity management system
9
+ - More aggressive deduplication within batch sender
10
+
1
11
  **2.45.0** (17 Feb 2022)
2
12
  - Remove all code related to in-app messaging feature
3
13
  - Add `error_reporter` config option for user-configurable handling of errors
@@ -5,7 +15,7 @@
5
15
  - Fixes for some batch/retry edge cases where localStorage write failures resulted in duplicate sends
6
16
 
7
17
  **2.43.0** (5 Jan 2022)
8
- - Support plain JSON tracking payloads (no base64-encoding) and use as default when sendinig to *.mixpanel.com API hosts
18
+ - Support plain JSON tracking payloads (no base64-encoding) and use as default when sending to *.mixpanel.com API hosts
9
19
 
10
20
  **2.42.1** (20 Dec 2021)
11
21
  - Add new crawler user agents to blocked list (ahrefsbot, petalbot)
package/README.md CHANGED
@@ -72,7 +72,7 @@ Mixpanel production releases are tested against a large matrix of browsers and o
72
72
  ## Generating and publishing documentation
73
73
  - Create bundled source build: `npm run build-dist`
74
74
  - Generate Markdown: `npm run dox` (result is at `doc/readme.io/javascript-full-api-reference.md`)
75
- - Publish to readme.io via the [rdme](https://www.npmjs.com/package/rdme) util: `RDME_API_KEY=<API_KEY> npm run dox-publish`
75
+ - Publish to readme.io via the [rdme](https://www.npmjs.com/package/rdme) util: `RDME_API_KEY=<API_KEY> RDME_DOC_VERSION=<version> npm run dox-publish`
76
76
 
77
77
  ## Thanks
78
78
  For patches and support: @bohanyang, @dehau, @drubin, @D1plo1d, @feychenie, @mogstad, @pfhayes, @sandorfr, @stefansedich, @gfx, @pkaminski, @austince, @danielbaker, @mkdai, @wolever, @dpraul, @chriszamierowski, @JoaoGomesTW
package/build.sh CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/bin/bash
2
2
 
3
+ set -e
4
+
3
5
  # building with $DIST=1 also implies $FULL=1
4
6
  if [ ! -z "$DIST" ]; then
5
7
  export FULL=1
@@ -2,7 +2,7 @@ define(function () { 'use strict';
2
2
 
3
3
  var Config = {
4
4
  DEBUG: false,
5
- LIB_VERSION: '2.45.0'
5
+ LIB_VERSION: '2.47.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
@@ -1412,21 +1416,42 @@ define(function () { 'use strict';
1412
1416
  };
1413
1417
  })();
1414
1418
 
1419
+ var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
1420
+ var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'ttclid', 'twclid', 'wbraid'];
1421
+
1415
1422
  _.info = {
1416
- campaignParams: function() {
1417
- var campaign_keywords = 'utm_source utm_medium utm_campaign utm_content utm_term'.split(' '),
1418
- kw = '',
1423
+ campaignParams: function(default_value) {
1424
+ var kw = '',
1419
1425
  params = {};
1420
- _.each(campaign_keywords, function(kwkey) {
1426
+ _.each(CAMPAIGN_KEYWORDS, function(kwkey) {
1421
1427
  kw = _.getQueryParam(document$1.URL, kwkey);
1422
1428
  if (kw.length) {
1423
1429
  params[kwkey] = kw;
1430
+ } else if (default_value !== undefined) {
1431
+ params[kwkey] = default_value;
1432
+ }
1433
+ });
1434
+
1435
+ return params;
1436
+ },
1437
+
1438
+ clickParams: function() {
1439
+ var id = '',
1440
+ params = {};
1441
+ _.each(CLICK_IDS, function(idkey) {
1442
+ id = _.getQueryParam(document$1.URL, idkey);
1443
+ if (id.length) {
1444
+ params[idkey] = id;
1424
1445
  }
1425
1446
  });
1426
1447
 
1427
1448
  return params;
1428
1449
  },
1429
1450
 
1451
+ marketingParams: function() {
1452
+ return _.extend(_.info.campaignParams(), _.info.clickParams());
1453
+ },
1454
+
1430
1455
  searchEngine: function(referrer) {
1431
1456
  if (referrer.search('https?://(.*)google.([^/?]*)') === 0) {
1432
1457
  return 'google';
@@ -1623,12 +1648,13 @@ define(function () { 'use strict';
1623
1648
  });
1624
1649
  },
1625
1650
 
1626
- pageviewInfo: function(page) {
1651
+ mpPageViewProperties: function() {
1627
1652
  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()
1653
+ 'current_page_title': document$1.title,
1654
+ 'current_domain': window$1.location.hostname,
1655
+ 'current_url_path': window$1.location.pathname,
1656
+ 'current_url_protocol': window$1.location.protocol,
1657
+ 'current_url_search': window$1.location.search
1632
1658
  });
1633
1659
  }
1634
1660
  };
@@ -2295,6 +2321,9 @@ define(function () { 'use strict';
2295
2321
 
2296
2322
  this.stopped = !this.libConfig['batch_autostart'];
2297
2323
  this.consecutiveRemovalFailures = 0;
2324
+
2325
+ // extra client-side dedupe
2326
+ this.itemIdsSentSuccessfully = {};
2298
2327
  };
2299
2328
 
2300
2329
  /**
@@ -2387,7 +2416,34 @@ define(function () { 'use strict';
2387
2416
  payload = this.beforeSendHook(payload);
2388
2417
  }
2389
2418
  if (payload) {
2390
- dataForRequest.push(payload);
2419
+ // mp_sent_by_lib_version prop captures which lib version actually
2420
+ // sends each event (regardless of which version originally queued
2421
+ // it for sending)
2422
+ if (payload['event'] && payload['properties']) {
2423
+ payload['properties'] = _.extend(
2424
+ {},
2425
+ payload['properties'],
2426
+ {'mp_sent_by_lib_version': Config.LIB_VERSION}
2427
+ );
2428
+ }
2429
+ var addPayload = true;
2430
+ var itemId = item['id'];
2431
+ if (itemId) {
2432
+ if ((this.itemIdsSentSuccessfully[itemId] || 0) > 5) {
2433
+ this.reportError('[dupe] item ID sent too many times, not sending', {
2434
+ item: item,
2435
+ batchSize: batch.length,
2436
+ timesSent: this.itemIdsSentSuccessfully[itemId]
2437
+ });
2438
+ addPayload = false;
2439
+ }
2440
+ } else {
2441
+ this.reportError('[dupe] found item with no ID', {item: item});
2442
+ }
2443
+
2444
+ if (addPayload) {
2445
+ dataForRequest.push(payload);
2446
+ }
2391
2447
  }
2392
2448
  transformedItems[item['id']] = payload;
2393
2449
  }, this);
@@ -2470,6 +2526,24 @@ define(function () { 'use strict';
2470
2526
  }
2471
2527
  }, this)
2472
2528
  );
2529
+
2530
+ // client-side dedupe
2531
+ _.each(batch, _.bind(function(item) {
2532
+ var itemId = item['id'];
2533
+ if (itemId) {
2534
+ this.itemIdsSentSuccessfully[itemId] = this.itemIdsSentSuccessfully[itemId] || 0;
2535
+ this.itemIdsSentSuccessfully[itemId]++;
2536
+ if (this.itemIdsSentSuccessfully[itemId] > 5) {
2537
+ this.reportError('[dupe] item ID sent too many times', {
2538
+ item: item,
2539
+ batchSize: batch.length,
2540
+ timesSent: this.itemIdsSentSuccessfully[itemId]
2541
+ });
2542
+ }
2543
+ } else {
2544
+ this.reportError('[dupe] found item with no ID while removing', {item: item});
2545
+ }
2546
+ }, this));
2473
2547
  }
2474
2548
 
2475
2549
  } catch(err) {
@@ -3315,24 +3389,25 @@ define(function () { 'use strict';
3315
3389
  });
3316
3390
 
3317
3391
  /*
3318
- * Record that you have charged the current user a certain amount
3319
- * of money. Charges recorded with track_charge() will appear in the
3320
- * Mixpanel revenue report.
3321
- *
3322
- * ### Usage:
3323
- *
3324
- * // charge a user $50
3325
- * mixpanel.people.track_charge(50);
3326
- *
3327
- * // charge a user $30.50 on the 2nd of january
3328
- * mixpanel.people.track_charge(30.50, {
3329
- * '$time': new Date('jan 1 2012')
3330
- * });
3331
- *
3332
- * @param {Number} amount The amount of money charged to the current user
3333
- * @param {Object} [properties] An associative array of properties associated with the charge
3334
- * @param {Function} [callback] If provided, the callback will be called when the server responds
3335
- */
3392
+ * Record that you have charged the current user a certain amount
3393
+ * of money. Charges recorded with track_charge() will appear in the
3394
+ * Mixpanel revenue report.
3395
+ *
3396
+ * ### Usage:
3397
+ *
3398
+ * // charge a user $50
3399
+ * mixpanel.people.track_charge(50);
3400
+ *
3401
+ * // charge a user $30.50 on the 2nd of january
3402
+ * mixpanel.people.track_charge(30.50, {
3403
+ * '$time': new Date('jan 1 2012')
3404
+ * });
3405
+ *
3406
+ * @param {Number} amount The amount of money charged to the current user
3407
+ * @param {Object} [properties] An associative array of properties associated with the charge
3408
+ * @param {Function} [callback] If provided, the callback will be called when the server responds
3409
+ * @deprecated
3410
+ */
3336
3411
  MixpanelPeople.prototype.track_charge = addOptOutCheckMixpanelPeople(function(amount, properties, callback) {
3337
3412
  if (!_.isNumber(amount)) {
3338
3413
  amount = parseFloat(amount);
@@ -3348,15 +3423,16 @@ define(function () { 'use strict';
3348
3423
  });
3349
3424
 
3350
3425
  /*
3351
- * Permanently clear all revenue report transactions from the
3352
- * current user's people analytics profile.
3353
- *
3354
- * ### Usage:
3355
- *
3356
- * mixpanel.people.clear_charges();
3357
- *
3358
- * @param {Function} [callback] If provided, the callback will be called after tracking the event.
3359
- */
3426
+ * Permanently clear all revenue report transactions from the
3427
+ * current user's people analytics profile.
3428
+ *
3429
+ * ### Usage:
3430
+ *
3431
+ * mixpanel.people.clear_charges();
3432
+ *
3433
+ * @param {Function} [callback] If provided, the callback will be called after tracking the event.
3434
+ * @deprecated
3435
+ */
3360
3436
  MixpanelPeople.prototype.clear_charges = function(callback) {
3361
3437
  return this.set('$transactions', [], callback);
3362
3438
  };
@@ -3756,13 +3832,6 @@ define(function () { 'use strict';
3756
3832
  }
3757
3833
  };
3758
3834
 
3759
- MixpanelPersistence.prototype.update_campaign_params = function() {
3760
- if (!this.campaign_params_saved) {
3761
- this.register_once(_.info.campaignParams());
3762
- this.campaign_params_saved = true;
3763
- }
3764
- };
3765
-
3766
3835
  MixpanelPersistence.prototype.update_search_keyword = function(referrer) {
3767
3836
  this.register(_.info.searchInfo(referrer));
3768
3837
  };
@@ -4045,6 +4114,7 @@ define(function () { 'use strict';
4045
4114
  /** @const */ var PRIMARY_INSTANCE_NAME = 'mixpanel';
4046
4115
  /** @const */ var PAYLOAD_TYPE_BASE64 = 'base64';
4047
4116
  /** @const */ var PAYLOAD_TYPE_JSON = 'json';
4117
+ /** @const */ var DEVICE_ID_PREFIX = '$device:';
4048
4118
 
4049
4119
 
4050
4120
  /*
@@ -4086,6 +4156,9 @@ define(function () { 'use strict';
4086
4156
  'cookie_domain': '',
4087
4157
  'cookie_name': '',
4088
4158
  'loaded': NOOP_FUNC,
4159
+ 'track_marketing': true,
4160
+ 'track_pageview': false,
4161
+ 'skip_first_touch_marketing': false,
4089
4162
  'store_google': true,
4090
4163
  'save_referrer': true,
4091
4164
  'test': false,
@@ -4152,6 +4225,25 @@ define(function () { 'use strict';
4152
4225
  instance['people'] = new MixpanelPeople();
4153
4226
  instance['people']._init(instance);
4154
4227
 
4228
+ if (!instance.get_config('skip_first_touch_marketing')) {
4229
+ // We need null UTM params in the object because
4230
+ // UTM parameters act as a tuple. If any UTM param
4231
+ // is present, then we set all UTM params including
4232
+ // empty ones together
4233
+ var utm_params = _.info.campaignParams(null);
4234
+ var initial_utm_params = {};
4235
+ var has_utm = false;
4236
+ _.each(utm_params, function(utm_value, utm_key) {
4237
+ initial_utm_params['initial_' + utm_key] = utm_value;
4238
+ if (utm_value) {
4239
+ has_utm = true;
4240
+ }
4241
+ });
4242
+ if (has_utm) {
4243
+ instance['people'].set_once(initial_utm_params);
4244
+ }
4245
+ }
4246
+
4155
4247
  // if any instance on the page has debug = true, we set the
4156
4248
  // global debug to be true
4157
4249
  Config.DEBUG = Config.DEBUG || instance.get_config('debug');
@@ -4183,7 +4275,7 @@ define(function () { 'use strict';
4183
4275
  * mixpanel.library_name.track(...);
4184
4276
  *
4185
4277
  * @param {String} token Your Mixpanel API token
4186
- * @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>.
4278
+ * @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>.
4187
4279
  * @param {String} [name] The name for the new mixpanel instance that you want created
4188
4280
  */
4189
4281
  MixpanelLib.prototype.init = function (token, config, name) {
@@ -4221,7 +4313,7 @@ define(function () { 'use strict';
4221
4313
  // default to JSON payload for standard mixpanel.com API hosts
4222
4314
  if (!('api_payload_format' in config)) {
4223
4315
  var api_host = config['api_host'] || DEFAULT_CONFIG['api_host'];
4224
- if (api_host.match(/\.mixpanel\.com$/)) {
4316
+ if (api_host.match(/\.mixpanel\.com/)) {
4225
4317
  variable_features['api_payload_format'] = PAYLOAD_TYPE_JSON;
4226
4318
  }
4227
4319
  }
@@ -4292,10 +4384,14 @@ define(function () { 'use strict';
4292
4384
  // or the device id if something was already stored
4293
4385
  // in the persitence
4294
4386
  this.register_once({
4295
- 'distinct_id': uuid,
4387
+ 'distinct_id': DEVICE_ID_PREFIX + uuid,
4296
4388
  '$device_id': uuid
4297
4389
  }, '');
4298
4390
  }
4391
+
4392
+ if (this.get_config('track_pageview')) {
4393
+ this.track_pageview();
4394
+ }
4299
4395
  };
4300
4396
 
4301
4397
  // Private methods
@@ -4309,7 +4405,7 @@ define(function () { 'use strict';
4309
4405
  MixpanelLib.prototype._set_default_superprops = function() {
4310
4406
  this['persistence'].update_search_keyword(document$1.referrer);
4311
4407
  if (this.get_config('store_google')) {
4312
- this['persistence'].update_campaign_params();
4408
+ this.register(_.info.campaignParams(), {persistent: false});
4313
4409
  }
4314
4410
  if (this.get_config('save_referrer')) {
4315
4411
  this['persistence'].update_referrer_info(document$1.referrer);
@@ -4791,6 +4887,10 @@ define(function () { 'use strict';
4791
4887
 
4792
4888
  this._set_default_superprops();
4793
4889
 
4890
+ var marketing_properties = this.get_config('track_marketing')
4891
+ ? _.info.marketingParams()
4892
+ : {};
4893
+
4794
4894
  // note: extend writes to the first object, so lets make sure we
4795
4895
  // don't write to the persistence properties object and info
4796
4896
  // properties object by passing in a new object
@@ -4799,6 +4899,7 @@ define(function () { 'use strict';
4799
4899
  properties = _.extend(
4800
4900
  {},
4801
4901
  _.info.properties(),
4902
+ marketing_properties,
4802
4903
  this['persistence'].properties(),
4803
4904
  this.unpersisted_superprops,
4804
4905
  properties
@@ -4959,17 +5060,54 @@ define(function () { 'use strict';
4959
5060
  };
4960
5061
 
4961
5062
  /**
4962
- * Track mp_page_view event. This is now ignored by the server.
5063
+ * Track a default Mixpanel page view event, which includes extra default event properties to
5064
+ * improve page view data. The `config.track_pageview` option for <a href="#mixpanelinit">mixpanel.init()</a>
5065
+ * may be turned on for tracking page loads automatically.
4963
5066
  *
4964
- * @param {String} [page] The url of the page to record. If you don't include this, it defaults to the current url.
4965
- * @deprecated
5067
+ * ### Usage
5068
+ *
5069
+ * // track a default $mp_web_page_view event
5070
+ * mixpanel.track_pageview();
5071
+ *
5072
+ * // track a page view event with additional event properties
5073
+ * mixpanel.track_pageview({'ab_test_variant': 'card-layout-b'});
5074
+ *
5075
+ * // example approach to track page views on different page types as event properties
5076
+ * mixpanel.track_pageview({'page': 'pricing'});
5077
+ * mixpanel.track_pageview({'page': 'homepage'});
5078
+ *
5079
+ * // UNCOMMON: Tracking a page view event with a custom event_name option. NOT expected to be used for
5080
+ * // individual pages on the same site or product. Use cases for custom event_name may be page
5081
+ * // views on different products or internal applications that are considered completely separate
5082
+ * mixpanel.track_pageview({'page': 'customer-search'}, {'event_name': '[internal] Admin Page View'});
5083
+ *
5084
+ * @param {Object} [properties] An optional set of additional properties to send with the page view event
5085
+ * @param {Object} [options] Page view tracking options
5086
+ * @param {String} [options.event_name] - Alternate name for the tracking event
5087
+ * @returns {Boolean|Object} If the tracking request was successfully initiated/queued, an object
5088
+ * with the tracking payload sent to the API server is returned; otherwise false.
4966
5089
  */
4967
- MixpanelLib.prototype.track_pageview = function(page) {
4968
- if (_.isUndefined(page)) {
4969
- page = document$1.location.href;
5090
+ MixpanelLib.prototype.track_pageview = addOptOutCheckMixpanelLib(function(properties, options) {
5091
+ if (typeof properties !== 'object') {
5092
+ properties = {};
4970
5093
  }
4971
- this.track('mp_page_view', _.info.pageviewInfo(page));
4972
- };
5094
+ options = options || {};
5095
+ var event_name = options['event_name'] || '$mp_web_page_view';
5096
+
5097
+ var default_page_properties = _.extend(
5098
+ _.info.mpPageViewProperties(),
5099
+ _.info.campaignParams(),
5100
+ _.info.clickParams()
5101
+ );
5102
+
5103
+ var event_properties = _.extend(
5104
+ {},
5105
+ default_page_properties,
5106
+ properties
5107
+ );
5108
+
5109
+ return this.track(event_name, event_properties);
5110
+ });
4973
5111
 
4974
5112
  /**
4975
5113
  * Track clicks on a set of document elements. Selector must be a
@@ -5218,7 +5356,15 @@ define(function () { 'use strict';
5218
5356
  // _unset_callback:function A callback to be run if and when the People unset queue is flushed
5219
5357
 
5220
5358
  var previous_distinct_id = this.get_distinct_id();
5221
- this.register({'$user_id': new_distinct_id});
5359
+ if (new_distinct_id && previous_distinct_id !== new_distinct_id) {
5360
+ // we allow the following condition if previous distinct_id is same as new_distinct_id
5361
+ // so that you can force flush people updates for anonymous profiles.
5362
+ if (typeof new_distinct_id === 'string' && new_distinct_id.indexOf(DEVICE_ID_PREFIX) === 0) {
5363
+ this.report_error('distinct_id cannot have $device: prefix');
5364
+ return -1;
5365
+ }
5366
+ this.register({'$user_id': new_distinct_id});
5367
+ }
5222
5368
 
5223
5369
  if (!this.get_property('$device_id')) {
5224
5370
  // The persisted distinct id might not actually be a device id at all
@@ -5259,7 +5405,7 @@ define(function () { 'use strict';
5259
5405
  this._flags.identify_called = false;
5260
5406
  var uuid = _.UUID();
5261
5407
  this.register_once({
5262
- 'distinct_id': uuid,
5408
+ 'distinct_id': DEVICE_ID_PREFIX + uuid,
5263
5409
  '$device_id': uuid
5264
5410
  }, '');
5265
5411
  };
@@ -5384,8 +5530,8 @@ define(function () { 'use strict';
5384
5530
  * // batching or retry mechanisms.
5385
5531
  * api_transport: 'XHR'
5386
5532
  *
5387
- * // turn on request-batching/queueing/retry
5388
- * batch_requests: false,
5533
+ * // request-batching/queueing/retry
5534
+ * batch_requests: true,
5389
5535
  *
5390
5536
  * // maximum number of events/updates to send in a single
5391
5537
  * // network request
@@ -5457,10 +5603,20 @@ define(function () { 'use strict';
5457
5603
  * // secure, meaning they will only be transmitted over https
5458
5604
  * secure_cookie: false
5459
5605
  *
5606
+ * // disables enriching user profiles with first touch marketing data
5607
+ * skip_first_touch_marketing: false
5608
+ *
5460
5609
  * // the amount of time track_links will
5461
5610
  * // wait for Mixpanel's servers to respond
5462
5611
  * track_links_timeout: 300
5463
5612
  *
5613
+ * // adds any UTM parameters and click IDs present on the page to any events fired
5614
+ * track_marketing: true
5615
+ *
5616
+ * // enables automatic page view tracking using default page view events through
5617
+ * // the track_pageview() method
5618
+ * track_pageview: false
5619
+ *
5464
5620
  * // if you set upgrade to be true, the library will check for
5465
5621
  * // a cookie from our old js library and import super
5466
5622
  * // properties from it, then the old cookie is deleted