@shopgate/tracking-core 7.30.0-alpha.6 → 7.30.0-alpha.8
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/core/AppHandler.js +121 -19
- package/core/Core.js +337 -82
- package/helpers/events.js +46 -7
- package/helpers/formatHelpers.js +324 -49
- package/helpers/helper.js +247 -36
- package/helpers/optOut.js +114 -13
- package/helpers/urlMapping.js +110 -14
- package/package.json +3 -3
- package/plugins/Base.js +94 -17
- package/plugins/trackers/FbPixel.js +186 -17
- package/plugins/trackers/GaBase.js +250 -31
- package/plugins/trackers/GaClassic.js +93 -13
- package/plugins/trackers/GaUniversal.js +162 -16
- package/plugins/trackers/Unified.js +67 -11
- package/typedef.js +51 -17
package/plugins/Base.js
CHANGED
|
@@ -1,28 +1,72 @@
|
|
|
1
|
-
|
|
1
|
+
import SgTrackingCore from "../core/Core";
|
|
2
|
+
import SgTrackingAppHandler from "../core/AppHandler";
|
|
3
|
+
import dataFormatHelpers from "../helpers/formatHelpers";
|
|
4
|
+
import eventNames from "../helpers/events";
|
|
5
|
+
|
|
6
|
+
/**
|
|
2
7
|
* Parent class for all tracking plugins that contains common public functions
|
|
3
|
-
*/
|
|
8
|
+
*/
|
|
9
|
+
class Base {
|
|
10
|
+
/**
|
|
4
11
|
* Constructor
|
|
5
12
|
* @param {string} trackerName The name of the tracker that is represented by the plugin
|
|
6
13
|
* @param {Object} options Configuration for the plugin
|
|
7
14
|
* @param {Object} extendedDefaults Additional default options that are
|
|
8
15
|
* needed by the inherited class
|
|
9
|
-
*/
|
|
10
|
-
|
|
16
|
+
*/
|
|
17
|
+
constructor(trackerName, options = {}, extendedDefaults = {}) {
|
|
18
|
+
const defaults = {
|
|
19
|
+
overrideUnified: false,
|
|
20
|
+
useNativeSdk: false,
|
|
21
|
+
useNetPrices: false
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Create the options for the plugin
|
|
25
|
+
this.options = {
|
|
26
|
+
...defaults,
|
|
27
|
+
...extendedDefaults,
|
|
28
|
+
...options
|
|
29
|
+
};
|
|
30
|
+
this.trackingDisabled = false;
|
|
31
|
+
this.trackerName = trackerName || '';
|
|
32
|
+
this.trackingCore = SgTrackingCore;
|
|
33
|
+
this.appHandler = SgTrackingAppHandler;
|
|
34
|
+
|
|
35
|
+
/**
|
|
11
36
|
* Storage that contains functions to register callbacks for the different tracking events
|
|
12
37
|
* @type {Object}
|
|
13
|
-
*/
|
|
38
|
+
*/
|
|
39
|
+
this.register = {};
|
|
40
|
+
eventNames.forEach(eventName => {
|
|
41
|
+
/**
|
|
14
42
|
* Function to register a plugin for the event
|
|
15
43
|
*
|
|
16
44
|
* @param {Function} callback Function that is called if the event occurs
|
|
17
45
|
* @param {Object} [optionParam] Options that will be passed to the core
|
|
18
46
|
* @returns {RemoveListener} Function to remove the listener
|
|
19
|
-
*/
|
|
47
|
+
*/
|
|
48
|
+
this.register[eventName] = (callback, optionParam) => this.registerHelper(eventName, callback, optionParam);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
20
53
|
* Converts raw tracking event data into the unified data format
|
|
21
54
|
*
|
|
22
55
|
* @param {string} eventName Name of the tracking event
|
|
23
56
|
* @param {Object} rawData Raw data from the core
|
|
24
57
|
* @returns {*} The converted data
|
|
25
|
-
*/
|
|
58
|
+
*/
|
|
59
|
+
static formatData(eventName, rawData) {
|
|
60
|
+
// Check if a suitable conversion function is available
|
|
61
|
+
if (typeof dataFormatHelpers[eventName] !== 'function') {
|
|
62
|
+
return rawData;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Convert the raw data
|
|
66
|
+
return dataFormatHelpers[eventName](rawData);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
26
70
|
* Helper function to register a plugin for a specific event. Can be overwritten in the plugins.
|
|
27
71
|
*
|
|
28
72
|
* @param {string} eventName Name of the event
|
|
@@ -30,19 +74,52 @@ this.options=_extends({},defaults,{},extendedDefaults,{},options);this.trackingD
|
|
|
30
74
|
* @param {Object} options Additional options that will be passed to the core
|
|
31
75
|
* @returns {RemoveListener} Function to remove the listener
|
|
32
76
|
* @private
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
77
|
+
*/
|
|
78
|
+
registerHelper(eventName, callback, options) {
|
|
79
|
+
// Register the tracking event of the plugin at the core
|
|
80
|
+
return this.trackingCore.register[eventName]((data, scope, blacklist, state) => {
|
|
81
|
+
// Convert the tracking data into the unified format
|
|
82
|
+
const unifiedData = Base.formatData(eventName, data);
|
|
83
|
+
|
|
84
|
+
// Invoke the event callback of the plugin to enable it to extend the data
|
|
85
|
+
const finalData = callback(unifiedData, data, scope, state);
|
|
86
|
+
|
|
87
|
+
// If final data is explicitly false, it means further processing is up to the plugin only.
|
|
88
|
+
if (finalData === false) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (this.options.useNativeSdk && this.options.overrideUnified) {
|
|
92
|
+
// Send command to the app via the appHandler
|
|
93
|
+
this.appHandler[eventName](finalData, {
|
|
94
|
+
blacklist: false,
|
|
95
|
+
trackers: [this.trackerName]
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}, {
|
|
99
|
+
...options,
|
|
100
|
+
trackerName: this.trackerName,
|
|
101
|
+
options: this.options
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
39
106
|
* Disables the tracking for the plugin
|
|
40
107
|
*
|
|
41
108
|
* @returns {Base} The instance of the plugin
|
|
42
|
-
*/
|
|
109
|
+
*/
|
|
110
|
+
disableTracking() {
|
|
111
|
+
this.trackingDisabled = true;
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
43
116
|
* Enables the tracking for the plugin
|
|
44
117
|
*
|
|
45
118
|
* @returns {Base} The instance of the plugin
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
|
-
|
|
119
|
+
*/
|
|
120
|
+
enableTracking() {
|
|
121
|
+
this.trackingDisabled = false;
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export default Base;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/* global fbq */
|
|
2
|
+
import { logger } from '@shopgate/pwa-core/helpers';
|
|
3
|
+
import BasePlugin from "../Base";
|
|
4
|
+
|
|
5
|
+
/**
|
|
2
6
|
* Tracking plugin for Facebook
|
|
3
|
-
*/
|
|
7
|
+
*/
|
|
8
|
+
class FbPixel extends BasePlugin {
|
|
9
|
+
/**
|
|
4
10
|
* Constructor
|
|
5
11
|
*
|
|
6
12
|
* @param {Object} options Common Tracking Configuration
|
|
@@ -9,36 +15,199 @@ function _typeof(obj){if(typeof Symbol==="function"&&typeof Symbol.iterator==="s
|
|
|
9
15
|
* to the native sdk
|
|
10
16
|
* @param {Object} [options.config] Configuration for facebook pixel tracking
|
|
11
17
|
* @param {Array} [options.config.pixelIds] List of Facebook pixels
|
|
12
|
-
*/
|
|
18
|
+
*/
|
|
19
|
+
constructor(options) {
|
|
20
|
+
const trackerName = 'facebookPixel';
|
|
21
|
+
const extendedDefaults = {
|
|
22
|
+
config: {
|
|
23
|
+
pixelIds: []
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
super(trackerName, options, extendedDefaults);
|
|
27
|
+
if (this.options.useNativeSdk) {
|
|
28
|
+
logger.warn('SgFbPixelTracking: no native SDK support for this plugin');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!this.options.config.pixelIds.length) {
|
|
32
|
+
logger.warn('SgFbPixelTracking: pixels missing');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.initPlugin();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
13
39
|
* Initiate and setup the SDK
|
|
14
|
-
*/
|
|
15
|
-
|
|
40
|
+
*/
|
|
41
|
+
initPlugin() {
|
|
42
|
+
// Load the fb pixel tracking sdk
|
|
43
|
+
/* eslint-disable eslint-comments/no-unlimited-disable */
|
|
44
|
+
/* eslint-disable */
|
|
45
|
+
!function (f, b, e, v, n, t, s) {
|
|
46
|
+
if (f.fbq) return;
|
|
47
|
+
n = f.fbq = function () {
|
|
48
|
+
n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);
|
|
49
|
+
};
|
|
50
|
+
if (!f._fbq) f._fbq = n;
|
|
51
|
+
n.push = n;
|
|
52
|
+
n.loaded = !0;
|
|
53
|
+
n.version = '2.0';
|
|
54
|
+
n.queue = [];
|
|
55
|
+
t = b.createElement(e);
|
|
56
|
+
t.async = !0;
|
|
57
|
+
t.src = v;
|
|
58
|
+
s = b.getElementsByTagName(e)[0];
|
|
59
|
+
s.parentNode.insertBefore(t, s);
|
|
60
|
+
}(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
|
|
61
|
+
/* eslint-enable */
|
|
62
|
+
|
|
63
|
+
const pixelsForInit = this.options.config.pixelIds.slice(0);
|
|
64
|
+
const firstPixel = pixelsForInit.shift();
|
|
65
|
+
FbPixel.sendToFb(firstPixel.toString(), undefined, 'init');
|
|
66
|
+
|
|
67
|
+
/*
|
|
16
68
|
* Add multiple pixel Ids.
|
|
17
69
|
* Warning: This is not official supported by facebook, but seems to work
|
|
18
|
-
*/
|
|
70
|
+
*/
|
|
71
|
+
pixelsForInit.forEach(pixel => {
|
|
72
|
+
FbPixel.sendToFb(pixel.toString(), undefined, 'addPixelId');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
19
76
|
* The pixel tracking have a PageView und ViewContent Event. The PageView event should be called
|
|
20
77
|
* on every page. It has no params
|
|
21
|
-
*/
|
|
22
|
-
|
|
78
|
+
*/
|
|
79
|
+
FbPixel.sendToFb('PageView');
|
|
80
|
+
|
|
81
|
+
// Register for some events
|
|
82
|
+
/* eslint-disable camelcase */
|
|
83
|
+
this.register.completedRegistration(data => {
|
|
84
|
+
FbPixel.sendToFb('CompleteRegistration', {
|
|
85
|
+
content_name: data.registrationMethod
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
this.register.viewContent((data, rawData) => {
|
|
89
|
+
const fbParams = {
|
|
90
|
+
content_type: data.type
|
|
91
|
+
};
|
|
92
|
+
if (data.type === 'product' && typeof rawData !== 'undefined') {
|
|
93
|
+
fbParams.content_ids = [data.id];
|
|
94
|
+
fbParams.content_name = rawData.product.name;
|
|
95
|
+
fbParams.value = parseFloat(this.getPrice(rawData.product.amount));
|
|
96
|
+
fbParams.currency = rawData.product.amount.currency;
|
|
97
|
+
} else {
|
|
98
|
+
fbParams.content_ids = [data.id];
|
|
99
|
+
fbParams.content_name = data.name;
|
|
100
|
+
}
|
|
101
|
+
FbPixel.sendToFb('ViewContent', fbParams);
|
|
102
|
+
});
|
|
103
|
+
this.register.addedPaymentInfo(() => {
|
|
104
|
+
FbPixel.sendToFb('AddPaymentInfo');
|
|
105
|
+
});
|
|
106
|
+
this.register.purchase(data => {
|
|
107
|
+
const productIds = FbPixel.getProductIds(data.items);
|
|
108
|
+
const fbParams = {
|
|
109
|
+
content_ids: productIds,
|
|
110
|
+
content_type: data.type,
|
|
111
|
+
value: this.getPrice(data),
|
|
112
|
+
currency: data.currency
|
|
113
|
+
};
|
|
114
|
+
if (productIds.length === 1) {
|
|
115
|
+
fbParams.content_name = data.items[0].name;
|
|
116
|
+
}
|
|
117
|
+
FbPixel.sendToFb('Purchase', fbParams);
|
|
118
|
+
});
|
|
119
|
+
this.register.initiatedCheckout((data, rawData) => {
|
|
120
|
+
const productIds = FbPixel.getProductIds(rawData.cart.products);
|
|
121
|
+
const fbParams = {
|
|
122
|
+
content_ids: productIds,
|
|
123
|
+
content_type: 'product',
|
|
124
|
+
value: this.getPrice(data),
|
|
125
|
+
currency: data.currency,
|
|
126
|
+
num_items: data.numItems
|
|
127
|
+
};
|
|
128
|
+
if (productIds.length === 1) {
|
|
129
|
+
fbParams.content_name = rawData.cart.products[0].name;
|
|
130
|
+
}
|
|
131
|
+
FbPixel.sendToFb('InitiateCheckout', fbParams);
|
|
132
|
+
});
|
|
133
|
+
this.register.addToCart(data => {
|
|
134
|
+
FbPixel.sendToFb('AddToCart', this.getParamsForAddToCartAndWishlist(data));
|
|
135
|
+
});
|
|
136
|
+
this.register.addToWishlist(data => {
|
|
137
|
+
FbPixel.sendToFb('AddToWishlist', this.getParamsForAddToCartAndWishlist(data));
|
|
138
|
+
});
|
|
139
|
+
this.register.search((data, rawData) => {
|
|
140
|
+
const productIds = FbPixel.getProductIds(rawData.products);
|
|
141
|
+
const fbParams = {
|
|
142
|
+
content_ids: productIds,
|
|
143
|
+
content_type: data.type,
|
|
144
|
+
search_string: data.query
|
|
145
|
+
};
|
|
146
|
+
FbPixel.sendToFb('Search', fbParams);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
23
151
|
* Send data to the facebook tracker
|
|
24
152
|
* @param {string} eventName Name of the event
|
|
25
153
|
* @param {Object} [params] Params for the event
|
|
26
154
|
* @param {string} [typeParam] Type of the tracker call
|
|
27
155
|
* @returns {void}
|
|
28
|
-
*/
|
|
156
|
+
*/
|
|
157
|
+
static sendToFb(eventName, params, typeParam) {
|
|
158
|
+
const type = typeParam || 'track';
|
|
159
|
+
fbq(type, eventName, params);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Extract the product Ids from an array with products
|
|
164
|
+
*
|
|
165
|
+
* @param {Array} products Array with products
|
|
166
|
+
* @returns {Array} Array of product Ids
|
|
167
|
+
*/
|
|
168
|
+
static getProductIds(products) {
|
|
169
|
+
return products.map(product => product.productNumber || product.uid || product.id);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
29
173
|
* Returns the correct price net or gross price. Depending on this.options.useNetPrices
|
|
30
174
|
*
|
|
31
175
|
* @param {Object} amount Price Object
|
|
32
176
|
* @returns {number|string} net or gross price
|
|
33
|
-
*/
|
|
177
|
+
*/
|
|
178
|
+
getPrice(amount) {
|
|
179
|
+
if (this.options.useNetPrices) {
|
|
180
|
+
return amount.priceNet || amount.valueNet || amount.net || amount.revenueNet;
|
|
181
|
+
}
|
|
182
|
+
return amount.priceGross || amount.valueGross || amount.gross || amount.revenueGross;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
34
186
|
* Returns the params for the AddToCart and AddToWishlist events
|
|
35
187
|
*
|
|
36
188
|
* @param {Object} data Converted data from the parent plugin
|
|
37
189
|
* @returns {Object} Params for the fb event
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
190
|
+
*/
|
|
191
|
+
getParamsForAddToCartAndWishlist(data) {
|
|
192
|
+
const productIds = FbPixel.getProductIds(data.items);
|
|
193
|
+
let value = 0;
|
|
194
|
+
let currency = 'EUR';
|
|
195
|
+
data.items.forEach(item => {
|
|
196
|
+
value += this.getPrice(item);
|
|
197
|
+
currency = item.currency; // eslint-disable-line prefer-destructuring
|
|
198
|
+
});
|
|
199
|
+
const fbParams = {
|
|
200
|
+
content_ids: productIds,
|
|
201
|
+
content_type: data.type,
|
|
202
|
+
value,
|
|
203
|
+
currency
|
|
204
|
+
};
|
|
205
|
+
if (productIds.length === 1) {
|
|
206
|
+
fbParams.content_name = data.items[0].name;
|
|
207
|
+
}
|
|
208
|
+
return fbParams;
|
|
209
|
+
}
|
|
210
|
+
/* eslint-enable camelcase */
|
|
211
|
+
}
|
|
212
|
+
window.SgFbPixelTracking = FbPixel;
|
|
213
|
+
export default FbPixel;
|