@techinasia/analytics.js-integration-google-analytics-4 0.0.3

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.
Files changed (3) hide show
  1. package/HISTORY.md +9 -0
  2. package/lib/index.js +312 -0
  3. package/package.json +58 -0
package/HISTORY.md ADDED
@@ -0,0 +1,9 @@
1
+ 0.0.2 / 2021-03-24
2
+ ==================
3
+
4
+ * Fix `set` command call.
5
+
6
+ 0.0.1 / 2021-03-24
7
+ ==================
8
+
9
+ * Initial commit :rocket:
package/lib/index.js ADDED
@@ -0,0 +1,312 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies.
5
+ */
6
+ var integration = require('@segment/analytics.js-integration');
7
+ var reject = require('reject');
8
+
9
+ /**
10
+ * GA4
11
+ */
12
+ var GA4 = (module.exports = integration('Google Analytics 4')
13
+ .global('gtag')
14
+ .global('ga4DataLayer')
15
+ .option('measurementIds', [])
16
+ .option('cookieDomainName', 'auto')
17
+ .option('cookiePrefix', '_ga')
18
+ .option('cookieExpiration', 63072000)
19
+ .option('cookieUpdate', true)
20
+ .option('cookieFlags', '')
21
+ .option('sendAutomaticPageViewEvent', false)
22
+ .option('allowAllAdvertisingFeatures', false)
23
+ .option('allowAdvertisingPersonalization', false)
24
+ .option('disableGoogleAnalytics', false)
25
+ .option('googleReportingIdentity', 'device')
26
+ .option('userProperties', {})
27
+ /**
28
+ * Custom Events and Parameters setting. This setting is used by the track
29
+ * handler to map Segment events and fields to Google analytics events and parameters.
30
+ *
31
+ * Example:
32
+ * [
33
+ * {
34
+ * "googleEvent": "new_episode",
35
+ * "parameters": [
36
+ * {
37
+ * "key": "properties.title",
38
+ * "value": "title"
39
+ * },
40
+ * {
41
+ * "key": "properties.genre",
42
+ * "value": "genre"
43
+ * }
44
+ * ],
45
+ * "segmentEvent": "Started Episode"
46
+ * }
47
+ * ]
48
+ */
49
+ .option('customEventsAndParameters', [])
50
+ .tag(
51
+ '<script src="//www.googletagmanager.com/gtag/js?id={{ measurementId }}&l=ga4DataLayer">'
52
+ ));
53
+
54
+ /**
55
+ * Initialize.
56
+ *
57
+ * https://developers.google.com/analytics/devguides/collection/ga4
58
+ *
59
+ * @api public
60
+ */
61
+ GA4.prototype.initialize = function() {
62
+ window.ga4DataLayer = window.ga4DataLayer || [];
63
+ window.gtag = function() {
64
+ window.ga4DataLayer.push(arguments);
65
+ };
66
+
67
+ /**
68
+ * This line is in all of the gtag examples but is not well documented. Research
69
+ * says that it is is related to deduplication.
70
+ * https://stackoverflow.com/questions/59256532/what-is-the-js-gtags-js-command
71
+ */
72
+ window.gtag('js', new Date());
73
+
74
+ var opts = this.options;
75
+ var measurementIds = opts.measurementIds;
76
+
77
+ /**
78
+ * Avoid loading and configuring gtag.js if any are true:
79
+ * - Disable Google Analytics setting is enabled
80
+ * - No measurement IDs are configured
81
+ */
82
+ if (!measurementIds.length || opts.disableGoogleAnalytics) {
83
+ return;
84
+ }
85
+
86
+ var config = {
87
+ /**
88
+ * Disable Google's Automatic Page View Measurement
89
+ * https://developers.google.com/analytics/devguides/collection/ga4/disable-page-view
90
+ */
91
+ send_page_view: opts.sendAutomaticPageViewEvent,
92
+
93
+ /**
94
+ * Cookie Update
95
+ * https://developers.google.com/analytics/devguides/collection/ga4/cookies-user-id#cookie_update_parameter
96
+ */
97
+ cookie_update: opts.cookieUpdate,
98
+
99
+ /**
100
+ * Cookie Domain Name
101
+ * https://developers.google.com/analytics/devguides/collection/ga4/cookies-user-id#cookie_domain_configuration
102
+ */
103
+ cookie_domain: opts.cookieDomainName,
104
+
105
+ /**
106
+ * Cookie Prefix
107
+ * https://developers.google.com/analytics/devguides/collection/ga4/cookies-user-id#cookie_prefix
108
+ */
109
+ cookie_prefix: opts.cookiePrefix,
110
+
111
+ /**
112
+ * Cookie Expiration
113
+ * https://developers.google.com/analytics/devguides/collection/ga4/cookies-user-id#cookie_expiration
114
+ */
115
+ cookie_expires: opts.cookieExpiration,
116
+ };
117
+
118
+ var sets = [
119
+ /**
120
+ * Cookie Flags
121
+ * https://developers.google.com/analytics/devguides/collection/ga4/cookies-user-id#cookie_flags
122
+ */
123
+ [{ cookie_flags: opts.cookieFlags }],
124
+
125
+ /**
126
+ * Disable All Advertising
127
+ * https://developers.google.com/analytics/devguides/collection/ga4/display-features#disable_all_advertising_features
128
+ */
129
+ ['allow_google_signals', opts.allowAllAdvertisingFeatures],
130
+
131
+ /**
132
+ * Disable Advertising Personalization
133
+ * https://developers.google.com/analytics/devguides/collection/ga4/display-features#disable_advertising_personalization
134
+ */
135
+ ['allow_ad_personalization_signals', opts.allowAdvertisingPersonalization]
136
+ ];
137
+
138
+ // Load gtag.js using the first measurement ID, then configure using the `config` commands built above.
139
+ var self = this;
140
+ this.load({ measurementId: measurementIds[0] }, function() {
141
+ /**
142
+ * Measurement IDs.
143
+ * The same configuration information is shared across all measurement IDs.
144
+ * https://developers.google.com/analytics/devguides/collection/ga4#add_an_additional_google_analytics_property_to_an_existing_tag
145
+ */
146
+ for (var i = 0; i < measurementIds.length; i++) {
147
+ window.gtag('config', measurementIds[i], config)
148
+
149
+ }
150
+
151
+ /**
152
+ * Set persistent values shared across all gtag.js usage.
153
+ * https://developers.google.com/gtagjs/reference/api#set
154
+ */
155
+ for (var i = 0; i < sets.length; i++) {
156
+ // Copy the set args and append the command before calling gtag.js.
157
+ var args = sets[i].slice(0)
158
+ args.unshift('set')
159
+ window.gtag.apply(null, args);
160
+ }
161
+
162
+ self.ready();
163
+ });
164
+ };
165
+
166
+ /**
167
+ * Loaded?
168
+ *
169
+ * @api private
170
+ * @return {boolean}
171
+ */
172
+ GA4.prototype.loaded = function() {
173
+ return !!(
174
+ window.ga4DataLayer && Array.prototype.push !== window.ga4DataLayer.push
175
+ );
176
+ };
177
+
178
+ /**
179
+ * Identify.
180
+ *
181
+ * @api public
182
+ * @param {Facade.Identify} event
183
+ */
184
+ GA4.prototype.identify = function(identify) {
185
+ var opts = this.options;
186
+ var userPropertyMappings = opts.userProperties;
187
+
188
+ var userProperties = {};
189
+
190
+ // Map all customer-defined user property mappings.
191
+ for (var eventField in userPropertyMappings) {
192
+ if (!userPropertyMappings.hasOwnProperty(eventField)) {
193
+ continue;
194
+ }
195
+
196
+ var userProp = userPropertyMappings[eventField];
197
+ var value = identify.proxy(eventField);
198
+
199
+ userProperties[userProp] = value;
200
+ }
201
+
202
+ /**
203
+ * Map the user_id property if the Google Reporting Identity is set one of:
204
+ * - By User ID, Google signals, then device (userIdSignalsAndDevice)
205
+ * - By User ID and Devicea (userIdAndDevice)
206
+ *
207
+ * Google's Reporting Identity: https://support.google.com/analytics/answer/9213390?hl=en
208
+ *
209
+ * Note that the user ID can be appended as part of the user_properties
210
+ * object instead of being configured by an explicit command.
211
+ * https://developers.google.com/analytics/devguides/collection/ga4/cookies-user-id#set_user_id
212
+ */
213
+ var userId = identify.userId();
214
+ var validReportingIdentity = opts.googleReportingIdentity === 'userIdSignalsAndDevice' || opts.googleReportingIdentity === 'userIdAndDevice'
215
+ if (userId && validReportingIdentity) {
216
+ userProperties.user_id = userId;
217
+ }
218
+
219
+ if (Object.keys(userProperties).length) {
220
+ window.gtag('set', 'user_properties', userProperties);
221
+ }
222
+ };
223
+
224
+ /**
225
+ * Group
226
+ *
227
+ * @api public
228
+ * @param {Facade.Group} group
229
+ */
230
+ GA4.prototype.group = function(group) {
231
+ window.gtag('event', 'join_group', {
232
+ group_id: group.groupId()
233
+ });
234
+ };
235
+
236
+ /**
237
+ * Page
238
+ *
239
+ * @api public
240
+ * @param {Facade.Page} page
241
+ */
242
+ GA4.prototype.page = function(page) {
243
+ // If the Send Google's Automatic Page View Measurement setting is set to true then
244
+ // don't handle page calls to avoid duplicate page_view events.
245
+ if (this.options.sendAutomaticPageViewEvent) {
246
+ return;
247
+ }
248
+
249
+ var props = page.properties();
250
+ var name = page.fullName();
251
+
252
+ var pageLocation = props.url;
253
+ var pageReferrer = page.referrer();
254
+ var pageTitle = name || props.title;
255
+
256
+ window.gtag('event', 'page_view', {
257
+ page_location: pageLocation,
258
+ page_referrer: pageReferrer,
259
+ page_title: pageTitle
260
+ });
261
+ };
262
+
263
+ /**
264
+ * Track
265
+ *
266
+ * @api public
267
+ * @param {Track} track
268
+ */
269
+
270
+ GA4.prototype.track = function(track) {
271
+
272
+ var mappings = this.options.customEventsAndParameters;
273
+
274
+ for (var i = 0; i < mappings.length; i++) {
275
+ var mapping = mappings[i];
276
+ if (typeof mapping !== 'object') {
277
+ continue;
278
+ }
279
+
280
+ var segmentEvent = mapping.segmentEvent;
281
+ var googleEvent = mapping.googleEvent;
282
+
283
+ if (!segmentEvent || !googleEvent || segmentEvent !== track.event()) {
284
+ continue;
285
+ }
286
+
287
+ var parameterMappings = mapping.parameters || [];
288
+ var parameters = {};
289
+
290
+ if (!(parameterMappings instanceof Array)) {
291
+ continue;
292
+ }
293
+
294
+ // Map Segment event fields to Google Event Parameters.
295
+ // Text map settings that are nested in a mixed settings take on a different shape
296
+ // than a top-level text map setting.
297
+ // eg; [{ key: 'properties.genre', value: 'primary_genre }]
298
+ //
299
+ for (var j = 0; j < parameterMappings.length; j++) {
300
+ var map = parameterMappings[j] || {};
301
+ if (typeof map !== 'object' || !map.key || !map.value) {
302
+ continue;
303
+ }
304
+
305
+ var param = map.value;
306
+ var value = track.proxy(map.key);
307
+ parameters[param] = value;
308
+ }
309
+
310
+ window.gtag('event', googleEvent, parameters);
311
+ }
312
+ };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@techinasia/analytics.js-integration-google-analytics-4",
3
+ "version": "0.0.3",
4
+ "description": "Segment Analytics.js integration for Google Analytics 4",
5
+ "main": "lib/index.js",
6
+ "directories": {
7
+ "lib": "lib",
8
+ "test": "test"
9
+ },
10
+ "scripts": {
11
+ "test": "karma start"
12
+ },
13
+ "author": "Tech in Asia",
14
+ "license": "MIT",
15
+ "homepage": "https://github.com/techinasia/segment-analytics.js-integration-google-analytics-4#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/techinasia/segment-analytics.js-integration-google-analytics-4/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/techinasia/segment-analytics.js-integration-google-analytics-4.git"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "dependencies": {
27
+ "@ndhoule/defaults": "^2.0.1",
28
+ "@segment/analytics.js-integration": "^3.1.0",
29
+ "component-each": "^0.2.6",
30
+ "extend": "^3.0.2",
31
+ "global-queue": "^1.0.1",
32
+ "is": "^3.1.0",
33
+ "lodash": "^4.17.4",
34
+ "obj-case": "^0.2.0",
35
+ "object-component": "0.0.3",
36
+ "reject": "0.0.1",
37
+ "segmentio-facade": "^3.2.7",
38
+ "use-https": "^0.1.1"
39
+ },
40
+ "devDependencies": {
41
+ "@segment/analytics.js-core": "^3.8.2",
42
+ "@segment/analytics.js-integration-tester": "^3.1.1",
43
+ "@segment/clear-env": "^2.1.1",
44
+ "browserify": "^16.2.3",
45
+ "eslint": "^5.16.0",
46
+ "karma": "^4.1.0",
47
+ "karma-browserify": "^6.0.0",
48
+ "karma-chrome-launcher": "^2.2.0",
49
+ "karma-mocha": "^1.3.0",
50
+ "karma-mocha-reporter": "^2.2.5",
51
+ "karma-sauce-launcher": "^2.0.2",
52
+ "karma-spec-reporter": "^0.0.32",
53
+ "karma-summary-reporter": "^1.6.0",
54
+ "mocha": "^6.1.4",
55
+ "to-array": "^0.1.4",
56
+ "watchify": "^3.7.0"
57
+ }
58
+ }