@splendidlabz/tracking 0.1.22 → 0.2.1
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/consts.js +425 -0
- package/lib/fb/node.js +141 -0
- package/lib/fb/readme.md +54 -0
- package/lib/fb/utils.js +15 -337
- package/lib/fb/web.js +148 -0
- package/lib/fb/web.test.js +47 -0
- package/lib/posthog/node.js +140 -0
- package/lib/posthog/readme.md +17 -0
- package/lib/posthog/web.js +79 -0
- package/package.json +6 -6
- package/dist/fb.js +0 -949
- package/lib/fb/browser.js +0 -184
- package/lib/fb/browser.test.js +0 -127
- package/lib/fb/server.js +0 -73
- /package/lib/posthog/{CrossDomainTracking.svelte → old/CrossDomainTracking.svelte} +0 -0
- /package/lib/posthog/{cross-domain.js → old/cross-domain.js} +0 -0
- /package/lib/posthog/{index.js → old/index.js} +0 -0
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
|
-
]
|
package/lib/fb/browser.test.js
DELETED
|
@@ -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
|
|
File without changes
|
|
File without changes
|