Skip to content

Commit 0a00eec

Browse files
authored
CC-6287 DEST-1710 Braze - Support new setting only track known u… (segmentio#437)
* DEST-1710 Braze - Support new setting only track known users * Bump version and add history info * update identify comment * appboyUtil.test.js cleanup * onlyTrackKnownUsersOnWeb gate access to window.appboy.initialize * gate segment methods on initialization, move internal functions to appboyUtil * beta right now * upgrade version * add some onlyTrackKnownUsersOnWeb specific tests, more to come * Improve test coverage * Make hasBeenInitialized check conditional on options.onlyTrackKnownUsersOnWeb * add Appboy.prototype.shouldHandleEvent
1 parent 5c2d77c commit 0a00eec

File tree

7 files changed

+486
-103
lines changed

7 files changed

+486
-103
lines changed

integrations/appboy/HISTORY.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
1.14.0 / 2020-03-02
2+
===================
3+
4+
* Add support for new setting `onlyTrackKnownUsersOnWeb`.
5+
* If enabled, this new setting delays calling of `window.appboy.initialize` until there is an `identify` call
6+
that supplies a valid `userId`.
7+
* This functionality was added to support customers who want to stop logging anonymous users to Braze.
8+
19
1.13.1 / 2019-11-27
210
===================
311

integrations/appboy/lib/appboyUtil.js

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
var appboyUtil = {
2+
/**
3+
* @param {string} userId
4+
* @param {object} options - integration options.
5+
* @returns {boolean} true if and only if should call window.appboy.openSession
6+
*/
7+
shouldOpenSession: function(userId, options) {
8+
return !!(userId || !options.onlyTrackKnownUsersOnWeb);
9+
},
10+
11+
getCustomEndpoint: function(options) {
12+
var customEndpoint;
13+
// Setup custom endpoints
14+
if (options.customEndpoint) {
15+
var endpoint = options.customEndpoint;
16+
var regex = new RegExp('^(http|https)://', 'i');
17+
customEndpoint =
18+
(regex.test(endpoint) ? endpoint : 'https://' + endpoint) + '/api/v3';
19+
} else if (options.datacenter === 'eu') {
20+
customEndpoint = 'https://sdk.fra-01.braze.eu/api/v3';
21+
}
22+
return customEndpoint;
23+
},
24+
25+
isVersionTwo: function(options) {
26+
return Number(options.version) === 2;
27+
},
28+
29+
getConfig: function(options) {
30+
var config = {};
31+
if (appboyUtil.isVersionTwo(options)) {
32+
// https://js.appboycdn.com/web-sdk/2.0/doc/module-appboy.html#.initialize
33+
config = {
34+
safariWebsitePushId: options.safariWebsitePushId,
35+
enableHtmlInAppMessages: options.enableHtmlInAppMessages,
36+
allowCrawlerActivity: options.allowCrawlerActivity,
37+
doNotLoadFontAwesome: options.doNotLoadFontAwesome,
38+
enableLogging: options.enableLogging,
39+
localization: options.localization,
40+
minimumIntervalBetweenTriggerActionsInSeconds:
41+
Number(options.minimumIntervalBetweenTriggerActionsInSeconds) || 30,
42+
openInAppMessagesInNewTab: options.openInAppMessagesInNewTab,
43+
openNewsFeedCardsInNewTab: options.openNewsFeedCardsInNewTab,
44+
requireExplicitInAppMessageDismissal:
45+
options.requireExplicitInAppMessageDismissal,
46+
serviceWorkerLocation: options.serviceWorkerLocation,
47+
sessionTimeoutInSeconds: Number(options.sessionTimeoutInSeconds) || 30
48+
};
49+
} else {
50+
var datacenterMappings = {
51+
us: 'https://sdk.iad-01.braze.com',
52+
us02: 'https://sdk.iad-02.braze.com',
53+
us03: 'https://sdk.iad-03.braze.com',
54+
eu: 'https://sdk.fra-01.braze.eu'
55+
};
56+
if (options.safariWebsitePushId)
57+
config.safariWebsitePushId = options.safariWebsitePushId;
58+
if (options.enableHtmlInAppMessages)
59+
config.enableHtmlInAppMessages = true;
60+
61+
// Setup custom endpoints
62+
if (options.customEndpoint) {
63+
var endpoint = options.customEndpoint;
64+
var regex = new RegExp('^(http|https)://', 'i');
65+
config.baseUrl =
66+
(regex.test(endpoint) ? endpoint : 'https://' + endpoint) + '/api/v3';
67+
} else {
68+
config.baseUrl =
69+
(datacenterMappings[options.datacenter] ||
70+
'https://sdk.iad-01.braze.com') + '/api/v3';
71+
}
72+
}
73+
var customEndpoint = appboyUtil.getCustomEndpoint(options);
74+
if (customEndpoint) config.baseUrl = customEndpoint;
75+
return config;
76+
}
77+
};
78+
79+
module.exports = appboyUtil;

integrations/appboy/lib/index.js

+72-102
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ var Track = require('segmentio-facade').Track;
99
var each = require('@ndhoule/each');
1010
var del = require('obj-case').del;
1111
var clone = require('@ndhoule/clone');
12+
var appboyUtil = require('./appboyUtil');
1213

1314
/**
1415
* Expose `Appboy` integration.
@@ -34,6 +35,7 @@ var Appboy = (module.exports = integration('Appboy')
3435
.option('customEndpoint', '')
3536
.option('version', 1)
3637
.option('logPurchaseWhenRevenuePresent', false)
38+
.option('onlyTrackKnownUsersOnWeb', false)
3739
.tag(
3840
'v1',
3941
'<script src="https://js.appboycdn.com/web-sdk/1.6/appboy.min.js">'
@@ -43,32 +45,25 @@ var Appboy = (module.exports = integration('Appboy')
4345
'<script src="https://js.appboycdn.com/web-sdk/2.4/appboy.min.js">'
4446
));
4547

46-
Appboy.prototype.initialize = function() {
47-
var options = this.options;
48-
var customEndpoint;
49-
// Setup custom endpoints
50-
if (options.customEndpoint) {
51-
var endpoint = options.customEndpoint;
52-
var regex = new RegExp('^(http|https)://', 'i');
53-
customEndpoint =
54-
(regex.test(endpoint) ? endpoint : 'https://' + endpoint) + '/api/v3';
55-
} else if (options.datacenter === 'eu') {
56-
customEndpoint = 'https://sdk.fra-01.braze.eu/api/v3';
57-
}
48+
Appboy.prototype.appboyInitialize = function(userId, options, config) {
49+
window.appboy.initialize(options.apiKey, config);
50+
51+
if (options.automaticallyDisplayMessages)
52+
window.appboy.display.automaticallyShowNewInAppMessages();
53+
if (userId) window.appboy.changeUser(userId);
54+
55+
window.appboy.openSession();
56+
};
5857

59-
if (Number(options.version) === 2) {
60-
this.initializeV2(customEndpoint);
58+
Appboy.prototype.initialize = function() {
59+
if (appboyUtil.isVersionTwo(this.options)) {
60+
this.initializeV2();
6161
} else {
62-
this.initializeV1(customEndpoint);
62+
this.initializeV1();
6363
}
6464
};
65-
/**
66-
* Initialize v1.
67-
*
68-
* @api public
69-
*/
7065

71-
Appboy.prototype.initializeV1 = function(customEndpoint) {
66+
Appboy.prototype.initializeV1 = function() {
7267
var options = this.options;
7368
var self = this;
7469
var userId = this.analytics.user().id();
@@ -79,7 +74,7 @@ Appboy.prototype.initializeV1 = function(customEndpoint) {
7974
window.appboy = {};
8075
for (
8176
var s = 'destroy toggleAppboyLogging setLogger openSession changeUser requestImmediateDataFlush requestFeedRefresh subscribeToFeedUpdates logCardImpressions logCardClick logFeedDisplayed requestInAppMessageRefresh logInAppMessageImpression logInAppMessageClick logInAppMessageButtonClick subscribeToNewInAppMessages removeSubscription removeAllSubscriptions logCustomEvent logPurchase isPushSupported isPushBlocked isPushGranted isPushPermissionGranted registerAppboyPushMessages unregisterAppboyPushMessages submitFeedback ab ab.User ab.User.Genders ab.User.NotificationSubscriptionTypes ab.User.prototype.getUserId ab.User.prototype.setFirstName ab.User.prototype.setLastName ab.User.prototype.setEmail ab.User.prototype.setGender ab.User.prototype.setDateOfBirth ab.User.prototype.setCountry ab.User.prototype.setHomeCity ab.User.prototype.setEmailNotificationSubscriptionType ab.User.prototype.setPushNotificationSubscriptionType ab.User.prototype.setPhoneNumber ab.User.prototype.setAvatarImageUrl ab.User.prototype.setLastKnownLocation ab.User.prototype.setUserAttribute ab.User.prototype.setCustomUserAttribute ab.User.prototype.addToCustomAttributeArray ab.User.prototype.removeFromCustomAttributeArray ab.User.prototype.incrementCustomUserAttribute ab.InAppMessage ab.InAppMessage.SlideFrom ab.InAppMessage.ClickAction ab.InAppMessage.DismissType ab.InAppMessage.OpenTarget ab.InAppMessage.ImageStyle ab.InAppMessage.Orientation ab.InAppMessage.CropType ab.InAppMessage.prototype.subscribeToClickedEvent ab.InAppMessage.prototype.subscribeToDismissedEvent ab.InAppMessage.prototype.removeSubscription ab.InAppMessage.prototype.removeAllSubscriptions ab.InAppMessage.Button ab.InAppMessage.Button.prototype.subscribeToClickedEvent ab.InAppMessage.Button.prototype.removeSubscription ab.InAppMessage.Button.prototype.removeAllSubscriptions ab.SlideUpMessage ab.ModalMessage ab.FullScreenMessage ab.ControlMessage ab.Feed ab.Feed.prototype.getUnreadCardCount ab.Card ab.ClassicCard ab.CaptionedImage ab.Banner ab.WindowUtils display display.automaticallyShowNewInAppMessages display.showInAppMessage display.showFeed display.destroyFeed display.toggleFeed sharedLib'.split(
82-
' '
77+
' '
8378
),
8479
i = 0;
8580
i < s.length;
@@ -93,9 +88,9 @@ Appboy.prototype.initializeV1 = function(customEndpoint) {
9388
}
9489
appboy.initialize = function() {
9590
console &&
96-
console.error(
97-
'Appboy cannot be loaded - this is usually due to strict corporate firewalls or ad blockers.'
98-
);
91+
console.error(
92+
'Appboy cannot be loaded - this is usually due to strict corporate firewalls or ad blockers.'
93+
);
9994
};
10095
appboy.getUser = function() {
10196
return new appboy.ab.User();
@@ -110,50 +105,18 @@ Appboy.prototype.initializeV1 = function(customEndpoint) {
110105
this._shim = window.appboy.initialize;
111106

112107
this.load('v1', function() {
113-
var config = {};
114-
var datacenterMappings = {
115-
us: 'https://sdk.iad-01.braze.com',
116-
us02: 'https://sdk.iad-02.braze.com',
117-
us03: 'https://sdk.iad-03.braze.com',
118-
eu: 'https://sdk.fra-01.braze.eu'
119-
};
120-
if (options.safariWebsitePushId)
121-
config.safariWebsitePushId = options.safariWebsitePushId;
122-
if (options.enableHtmlInAppMessages) config.enableHtmlInAppMessages = true;
123-
124-
// Setup custom endpoints
125-
if (options.customEndpoint) {
126-
var endpoint = options.customEndpoint;
127-
var regex = new RegExp('^(http|https)://', 'i');
128-
config.baseUrl =
129-
(regex.test(endpoint) ? endpoint : 'https://' + endpoint) + '/api/v3';
130-
} else {
131-
config.baseUrl =
132-
(datacenterMappings[options.datacenter] ||
133-
'https://sdk.iad-01.braze.com') + '/api/v3';
108+
if (appboyUtil.shouldOpenSession(userId, options)) {
109+
self.hasBeenInitialized = true;
110+
var config = appboyUtil.getConfig(options);
111+
self.initializeTester(options.apiKey, config);
112+
self.appboyInitialize(userId, options, config);
134113
}
135114

136-
if (customEndpoint) config.baseUrl = customEndpoint;
137-
138-
self.initializeTester(options.apiKey, config);
139-
window.appboy.initialize(options.apiKey, config);
140-
141-
if (options.automaticallyDisplayMessages)
142-
window.appboy.display.automaticallyShowNewInAppMessages();
143-
if (userId) window.appboy.changeUser(userId);
144-
145-
window.appboy.openSession();
146115
self.ready();
147116
});
148117
};
149118

150-
/**
151-
* Initialize v2.
152-
*
153-
* @api public
154-
*/
155-
156-
Appboy.prototype.initializeV2 = function(customEndpoint) {
119+
Appboy.prototype.initializeV2 = function() {
157120
var options = this.options;
158121
var userId = this.analytics.user().id();
159122

@@ -163,7 +126,7 @@ Appboy.prototype.initializeV2 = function(customEndpoint) {
163126
window.appboyQueue = [];
164127
for (
165128
var s = 'initialize destroy getDeviceId toggleAppboyLogging setLogger openSession changeUser requestImmediateDataFlush requestFeedRefresh subscribeToFeedUpdates logCardImpressions logCardClick logFeedDisplayed requestInAppMessageRefresh logInAppMessageImpression logInAppMessageClick logInAppMessageButtonClick logInAppMessageHtmlClick subscribeToNewInAppMessages removeSubscription removeAllSubscriptions logCustomEvent logPurchase isPushSupported isPushBlocked isPushGranted isPushPermissionGranted registerAppboyPushMessages unregisterAppboyPushMessages submitFeedback trackLocation stopWebTracking resumeWebTracking wipeData ab ab.User ab.User.Genders ab.User.NotificationSubscriptionTypes ab.User.prototype.getUserId ab.User.prototype.setFirstName ab.User.prototype.setLastName ab.User.prototype.setEmail ab.User.prototype.setGender ab.User.prototype.setDateOfBirth ab.User.prototype.setCountry ab.User.prototype.setHomeCity ab.User.prototype.setLanguage ab.User.prototype.setEmailNotificationSubscriptionType ab.User.prototype.setPushNotificationSubscriptionType ab.User.prototype.setPhoneNumber ab.User.prototype.setAvatarImageUrl ab.User.prototype.setLastKnownLocation ab.User.prototype.setUserAttribute ab.User.prototype.setCustomUserAttribute ab.User.prototype.addToCustomAttributeArray ab.User.prototype.removeFromCustomAttributeArray ab.User.prototype.incrementCustomUserAttribute ab.User.prototype.addAlias ab.InAppMessage ab.InAppMessage.SlideFrom ab.InAppMessage.ClickAction ab.InAppMessage.DismissType ab.InAppMessage.OpenTarget ab.InAppMessage.ImageStyle ab.InAppMessage.TextAlignment ab.InAppMessage.Orientation ab.InAppMessage.CropType ab.InAppMessage.prototype.subscribeToClickedEvent ab.InAppMessage.prototype.subscribeToDismissedEvent ab.InAppMessage.prototype.removeSubscription ab.InAppMessage.prototype.removeAllSubscriptions ab.InAppMessage.Button ab.InAppMessage.Button.prototype.subscribeToClickedEvent ab.InAppMessage.Button.prototype.removeSubscription ab.InAppMessage.Button.prototype.removeAllSubscriptions ab.SlideUpMessage ab.ModalMessage ab.FullScreenMessage ab.HtmlMessage ab.ControlMessage ab.Feed ab.Feed.prototype.getUnreadCardCount ab.Card ab.ClassicCard ab.CaptionedImage ab.Banner ab.WindowUtils display display.automaticallyShowNewInAppMessages display.showInAppMessage display.showFeed display.destroyFeed display.toggleFeed sharedLib'.split(
166-
' '
129+
' '
167130
),
168131
i = 0;
169132
i < s.length;
@@ -177,8 +140,8 @@ Appboy.prototype.initializeV2 = function(customEndpoint) {
177140
k = k[l[j]];
178141
k[l[j]] = new Function(
179142
'return function ' +
180-
m.replace(/\./g, '_') +
181-
'(){appboyQueue.push(arguments); return true}'
143+
m.replace(/\./g, '_') +
144+
'(){appboyQueue.push(arguments); return true}'
182145
)();
183146
}
184147
appboy.getUser = function() {
@@ -190,38 +153,23 @@ Appboy.prototype.initializeV2 = function(customEndpoint) {
190153
})(window, document, 'script');
191154
/* eslint-enable */
192155

193-
// https://js.appboycdn.com/web-sdk/2.0/doc/module-appboy.html#.initialize
194-
var config = {
195-
safariWebsitePushId: options.safariWebsitePushId,
196-
enableHtmlInAppMessages: options.enableHtmlInAppMessages,
197-
allowCrawlerActivity: options.allowCrawlerActivity,
198-
doNotLoadFontAwesome: options.doNotLoadFontAwesome,
199-
enableLogging: options.enableLogging,
200-
localization: options.localization,
201-
minimumIntervalBetweenTriggerActionsInSeconds:
202-
Number(options.minimumIntervalBetweenTriggerActionsInSeconds) || 30,
203-
openInAppMessagesInNewTab: options.openInAppMessagesInNewTab,
204-
openNewsFeedCardsInNewTab: options.openNewsFeedCardsInNewTab,
205-
requireExplicitInAppMessageDismissal:
206-
options.requireExplicitInAppMessageDismissal,
207-
serviceWorkerLocation: options.serviceWorkerLocation,
208-
sessionTimeoutInSeconds: Number(options.sessionTimeoutInSeconds) || 30
209-
};
210-
211-
if (customEndpoint) config.baseUrl = customEndpoint;
212-
213-
this.initializeTester(options.apiKey, config);
214-
window.appboy.initialize(options.apiKey, config);
215-
216-
if (options.automaticallyDisplayMessages)
217-
window.appboy.display.automaticallyShowNewInAppMessages();
218-
if (userId) window.appboy.changeUser(userId);
219-
220-
window.appboy.openSession();
156+
if (appboyUtil.shouldOpenSession(userId, options)) {
157+
this.hasBeenInitialized = true;
158+
var config = appboyUtil.getConfig(options);
159+
this.initializeTester(options.apiKey, config);
160+
this.appboyInitialize(userId, options, config);
161+
}
221162

222163
this.load('v2', this.ready);
223164
};
224165

166+
/**
167+
* @returns {boolean} true if integration should handle event.
168+
*/
169+
Appboy.prototype.shouldHandleEvent = function() {
170+
return !this.options.onlyTrackKnownUsersOnWeb || this.hasBeenInitialized;
171+
};
172+
225173
// This is used to test window.appboy.initialize
226174
Appboy.prototype.initializeTester = function() {};
227175

@@ -231,20 +179,12 @@ Appboy.prototype.initializeTester = function() {};
231179
* @api private
232180
* @return {boolean}
233181
*/
234-
235182
Appboy.prototype.loaded = function() {
236183
var options = this.options;
237184
if (Number(options.version) === 2) return window.appboyQueue === null;
238185
return window.appboy && window.appboy.initialize !== this._shim;
239186
};
240187

241-
/**
242-
* Identify.
243-
*
244-
* @api public
245-
* @param {Identify} identify
246-
*/
247-
248188
Appboy.prototype.identify = function(identify) {
249189
var userId = identify.userId();
250190
var address = identify.address();
@@ -257,6 +197,24 @@ Appboy.prototype.identify = function(identify) {
257197
var phone = identify.phone();
258198
var traits = clone(identify.traits());
259199

200+
var options = this.options;
201+
202+
if (
203+
this.options.onlyTrackKnownUsersOnWeb &&
204+
userId &&
205+
!this.hasBeenInitialized // To avoid calling this more than once.
206+
) {
207+
// Rerun initial initialization.
208+
this.hasBeenInitialized = true;
209+
var config = appboyUtil.getConfig(options);
210+
this.initializeTester(options.apiKey, config);
211+
this.appboyInitialize(userId, options, config);
212+
}
213+
214+
if (this.options.onlyTrackKnownUsersOnWeb && !this.hasBeenInitialized) {
215+
return;
216+
}
217+
260218
if (userId) {
261219
window.appboy.changeUser(userId);
262220
}
@@ -355,6 +313,9 @@ Appboy.prototype.identify = function(identify) {
355313
*/
356314

357315
Appboy.prototype.group = function(group) {
316+
if (!this.shouldHandleEvent()) {
317+
return;
318+
}
358319
var userId = group.userId();
359320
var groupIdKey = 'ab_segment_group_' + group.groupId();
360321

@@ -374,6 +335,9 @@ Appboy.prototype.group = function(group) {
374335
*/
375336

376337
Appboy.prototype.track = function(track) {
338+
if (!this.shouldHandleEvent()) {
339+
return;
340+
}
377341
var userId = track.userId();
378342
var eventName = track.event();
379343
var properties = track.properties();
@@ -408,6 +372,9 @@ Appboy.prototype.track = function(track) {
408372
*/
409373

410374
Appboy.prototype.page = function(page) {
375+
if (!this.shouldHandleEvent()) {
376+
return;
377+
}
411378
var settings = this.options;
412379
if (!settings.trackAllPages && !settings.trackNamedPages) return;
413380
if (settings.trackNamedPages && !page.name()) return;
@@ -435,6 +402,9 @@ Appboy.prototype.page = function(page) {
435402
*/
436403

437404
Appboy.prototype.orderCompleted = function(track) {
405+
if (!this.shouldHandleEvent()) {
406+
return;
407+
}
438408
var userId = track.userId();
439409
var products = track.products();
440410
var currencyCode = track.currency();

0 commit comments

Comments
 (0)