@splendidlabz/tracking 0.1.21 → 0.2.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.
package/lib/fb/browser.js DELETED
@@ -1,184 +0,0 @@
1
- import { getCookie, randomString, sha256Hash } from '@splendidlabz/utils/dom'
2
- import { isEmpty, notEmpty, splitObject } from '@splendidlabz/utils'
3
-
4
- import { formatUserData } from './utils.js'
5
- import zlFetch from 'zl-fetch'
6
-
7
- // TODO: Figure a way to put the Pixel Code into the DOM... if possible!
8
- export default function FB({ pixelID, testEventCode, capiEndpoint }) {
9
- const _fb = {
10
- options: { pixelID, testEventCode, capiEndpoint },
11
-
12
- // Initializes Facebook
13
- init() {
14
- !(function (f, b, e, v, n, t, s) {
15
- if (f.fbq) return
16
- n = f.fbq = function () {
17
- n.callMethod
18
- ? n.callMethod.apply(n, arguments)
19
- : n.queue.push(arguments)
20
- }
21
- if (!f._fbq) f._fbq = n
22
- n.push = n
23
- n.loaded = !0
24
- n.version = '2.0'
25
- n.queue = []
26
- t = b.createElement(e)
27
- t.async = !0
28
- t.src = v
29
- s = b.getElementsByTagName(e)[0]
30
- s.parentNode.insertBefore(t, s)
31
- })(
32
- window,
33
- document,
34
- 'script',
35
- 'https://connect.facebook.net/en_US/fbevents.js',
36
- )
37
- fbq('init', pixelID)
38
- },
39
-
40
- async sendEvent(eventName, props = {}) {
41
- const eventData = await _fb.createFBEvent(eventName, props)
42
-
43
- // Question whether we want to verbose log this thing in the future so users can know whether these events are sent.
44
- _fb.sendPixelEvent(eventData)
45
- return _fb.sendCAPIEvent(eventData)
46
- },
47
-
48
- async createFBEvent(eventName, props = {}) {
49
- const { eventURL, actionSource, ...rest } = props
50
-
51
- const { picked: userProperties, omitted: customData } = splitObject(
52
- rest,
53
- [...USER_PROPERTIES_TO_HASH, ...USER_PROPERTIES_NOT_TO_HASH],
54
- )
55
-
56
- const { picked: userPropsToHash, omitted: otherUserProps } = splitObject(
57
- userProperties,
58
- USER_PROPERTIES_TO_HASH,
59
- )
60
-
61
- const userData = {
62
- ...(await formatUserData(userPropsToHash)),
63
- ...otherUserProps,
64
- }
65
-
66
- const ret = {
67
- // Data for both Pixel and CAPI
68
- pixelID,
69
- eventID: await randomString(),
70
- eventName: eventName,
71
- userData,
72
- customData,
73
-
74
- // Data for CAPI only
75
- fbp: getCookie('_fbp'),
76
- fbc: getCookie('_fbc'),
77
- eventTime: Math.floor(new Date() / 1000),
78
- eventURL: eventURL || window.location.href,
79
- actionSource: actionSource || 'website',
80
- }
81
- if (testEventCode) ret.testEventCode = testEventCode
82
-
83
- return ret
84
- },
85
-
86
- // Facebook Pixel Code
87
- // Pixel Standard Reference
88
- // https://developers.facebook.com/docs/meta-pixel/reference#standard-events
89
- sendPixelEvent(data) {
90
- const {
91
- eventID,
92
- eventName,
93
- userData = {},
94
- customData = {},
95
- pixelID,
96
- } = data
97
- const props = { ...userData, ...customData }
98
-
99
- let action = 'track'
100
- let evtName = eventName
101
- if (evtName === 'init') action = 'init'
102
-
103
- // When we use fbq init, we have to add the pixelID instead of the event name as the 2nd parameter.
104
- if (action === 'init') evtName = pixelID
105
-
106
- // If the event is a custom event, we need to use `trackCustom` instead of `track`.
107
- if (action !== 'init' && !standardEvents.includes(evtName))
108
- action = 'trackCustom'
109
-
110
- fbq(action, evtName, props, { eventID })
111
- },
112
-
113
- // CAPI Parameters: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters
114
- sendCAPIEvent(data) {
115
- return zlFetch.post(capiEndpoint, { body: data })
116
- },
117
- }
118
-
119
- return _fb
120
- }
121
-
122
- const standardEvents = [
123
- 'AddPaymentInfo',
124
- 'AddToCart',
125
- 'AddToWishlist',
126
- 'CompleteRegistration',
127
- 'Contact',
128
- 'CustomizeProduct',
129
- 'Donate',
130
- 'FindLocation',
131
- 'InitiateCheckout',
132
- 'Lead',
133
- 'Purchase',
134
- 'Schedule',
135
- 'Search',
136
- 'StartTrial',
137
- 'SubmitApplication',
138
- 'Subscribe',
139
- 'ViewContent',
140
- ]
141
-
142
- // https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters
143
- const USER_PROPERTIES_TO_HASH = [
144
- 'email',
145
- 'phone',
146
- 'firstName',
147
- 'lastName',
148
- 'birthdate',
149
- 'gender',
150
- 'city',
151
- 'state',
152
- 'zip',
153
- 'country',
154
- 'externalID',
155
- ]
156
-
157
- // Other optional FB Stuff — doesn't seem very useful
158
- const USER_PROPERTIES_NOT_TO_HASH = [
159
- 'subscription_id',
160
- 'fb_login_id',
161
- 'lead_id',
162
- 'anon_id',
163
- 'madid',
164
- 'page_id',
165
- 'page_scoped_user_id',
166
- 'ctwa_clid',
167
- 'ig_account_id',
168
- 'ig_sid',
169
- ]
170
-
171
- const CUSTOM_PROPERTIES = [
172
- 'content_category',
173
- 'content_ids',
174
- 'content_name',
175
- 'content_type',
176
- 'contents',
177
- 'currency',
178
- 'delivery_category',
179
- 'num_items',
180
- 'predicted_ltv',
181
- 'search_string',
182
- 'status',
183
- 'value',
184
- ]
@@ -1,127 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { describe, expect, it } from 'vitest'
3
-
4
- import FB from './browser.js'
5
- import { sha256Hash } from '@splendidlabz/utils/dom'
6
-
7
- describe('Facebook Event Props', _ => {
8
- it('Basic Event Props', async _ => {
9
- const fb = new FB({
10
- pixelID: '123456789',
11
- testEventCode: 'TEST123',
12
- capiEndpoint: 'https://somewhere.com',
13
- })
14
-
15
- const eventData = await fb.createFBEvent('PageView', {})
16
-
17
- expect(eventData).toHaveProperty('pixelID')
18
- expect(eventData).toHaveProperty('eventID')
19
- expect(eventData).toHaveProperty('eventName')
20
- expect(eventData).toHaveProperty('eventURL')
21
- expect(eventData).toHaveProperty('eventTime')
22
- expect(eventData).toHaveProperty('actionSource')
23
- expect(eventData).toHaveProperty('fbp')
24
- expect(eventData).toHaveProperty('fbc')
25
- expect(eventData).toHaveProperty('userData')
26
- expect(eventData).toHaveProperty('customData')
27
- })
28
-
29
- it('Correctly splits userData and customData', async _ => {
30
- const fb = new FB({
31
- pixelID: '123456789',
32
- testEventCode: 'TEST123',
33
- capiEndpoint: 'https://somewhere.com',
34
- })
35
-
36
- const eventData = await fb.createFBEvent('Lead', {
37
- email: 'abc@test.com',
38
- firstName: 'ABC',
39
- contents: [
40
- { id: '22', quantity: 1 },
41
- { id: '23', quantity: 1 },
42
- ],
43
- })
44
-
45
- const { userData, customData } = eventData
46
-
47
- expect(userData).toHaveProperty('em')
48
- expect(userData).toHaveProperty('fn')
49
- expect(customData).toEqual({
50
- contents: [
51
- { id: '22', quantity: 1 },
52
- { id: '23', quantity: 1 },
53
- ],
54
- })
55
- })
56
-
57
- it('Hashing User Properties', async _ => {
58
- const fb = new FB({
59
- pixelID: '123456789',
60
- testEventCode: 'TEST123',
61
- capiEndpoint: 'https://somewhere.com',
62
- })
63
-
64
- const eventData = await fb.createFBEvent('Lead', {
65
- email: 'zellwk@gmail.com',
66
- firstName: 'Zell',
67
- lastName: 'Liew',
68
- birthdate: '19900101',
69
- gender: 'm',
70
- city: 'Singapore',
71
- country: 'Singapore',
72
- state: 'Singapore',
73
- zip: '12345',
74
- })
75
-
76
- const { userData } = eventData
77
-
78
- expect(userData).toEqual({
79
- em: '5fc6517c0a210f60c685fa4e21c1c4a8a9862c55ed37f2db25cb4ae893f8e9a9',
80
- fn: '07bea691e1173e5366d4ddf2c13103802b3f16441c81d6a19037a6d88118b46c',
81
- ln: '555ba31c9795b7e549c88014751487db1310a2daaabd891555c3c34156e9e531',
82
- db: 'd6165fc8037886424321260c0f9c2a76f7d8d545a02f95c70da9952a13299f33',
83
- ge: '62c66a7a5dd70c3146618063c344e531e6d4b59e379808443ce962b3abd63c5a',
84
- ct: '51e2a46721d104d9148d85b617833e7745fdbd6795cb0b502a5b6ea31d33378e',
85
- country:
86
- '88195283220112932b02b8aa03dc289106f478e998cadaeeea2e181f8aa1a01d',
87
- st: '51e2a46721d104d9148d85b617833e7745fdbd6795cb0b502a5b6ea31d33378e',
88
- zp: '5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5',
89
- })
90
- })
91
-
92
- it('Not Hashing certain user properties', async _ => {
93
- const fb = new FB({
94
- pixelID: '123456789',
95
- testEventCode: 'TEST123',
96
- capiEndpoint: 'https://somewhere.com',
97
- })
98
-
99
- const eventData = await fb.createFBEvent('Lead', {
100
- subscription_id: '123456789',
101
- fb_login_id: '123456789',
102
- lead_id: '123456789',
103
- anon_id: '123456789',
104
- madid: '123456789',
105
- page_id: '123456789',
106
- page_scoped_user_id: '123456789',
107
- ctwa_clid: '123456789',
108
- ig_account_id: '123456789',
109
- ig_sid: '123456789',
110
- })
111
-
112
- const { userData } = eventData
113
-
114
- expect(userData).toEqual({
115
- subscription_id: '123456789',
116
- fb_login_id: '123456789',
117
- lead_id: '123456789',
118
- anon_id: '123456789',
119
- madid: '123456789',
120
- page_id: '123456789',
121
- page_scoped_user_id: '123456789',
122
- ctwa_clid: '123456789',
123
- ig_account_id: '123456789',
124
- ig_sid: '123456789',
125
- })
126
- })
127
- })
package/lib/fb/server.js DELETED
@@ -1,73 +0,0 @@
1
- import createError from 'http-errors'
2
- import { formatUserData } from './utils.js'
3
- import zlFetch from 'zl-fetch'
4
-
5
- const accessToken = process.env.FB_ACCESS_TOKEN
6
-
7
- export async function sendConversionAPIRequest(req) {
8
- const {
9
- pixelID,
10
- eventID,
11
- eventName,
12
- actionSource,
13
- eventURL,
14
- eventTime,
15
- userData,
16
- customData,
17
- fbp,
18
- fbc,
19
- testEventCode,
20
- ...rest
21
- } = req.body
22
-
23
- if (!accessToken) {
24
- throw createError(
25
- 500,
26
- 'Facebook Access Token is not provided in the environment variables.'
27
- )
28
- return
29
- }
30
-
31
- // Don't send init event for CAPI
32
- if (eventName === 'init') return
33
-
34
- const outgoingData = [
35
- {
36
- event_id: eventID, // For deduplication
37
- event_name: eventName,
38
- action_source: actionSource,
39
- event_source_url: eventURL,
40
- event_time: eventTime,
41
- user_data: {
42
- ...userData,
43
- client_ip_address: req.clientIp, // Checks if this works... if not, use ipify from the browser.
44
- client_user_agent: req.headers['user-agent'],
45
- fbc: fbc,
46
- fbp: fbp,
47
- },
48
- custom_data: customData,
49
-
50
- // Optional data processing stuff
51
- opt_out: data.opt_out || false, //
52
- data_processing_options: [],
53
- data_processing_options_country: [],
54
- data_processing_options_state: [],
55
- },
56
- ]
57
-
58
- // Format CAPI Body
59
- const body = {
60
- data: outgoingData,
61
- access_token: accessToken,
62
- }
63
-
64
- if (testEventCode) body.test_event_code = testEventCode
65
-
66
- // Send the CAPI request
67
- // Maybe need to update the version here somehow
68
- return zlFetch('https://graph.facebook.com/v19.0/' + pixelID + '/events', {
69
- method: 'post',
70
- auth: accessToken,
71
- body,
72
- })
73
- }
File without changes