@segment/analytics-browser-actions-facebook-conversions-api-web 1.9.1-staging-99a2d468f.1 → 1.11.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.
Files changed (55) hide show
  1. package/dist/cjs/functions.d.ts +0 -1
  2. package/dist/cjs/functions.js +2 -11
  3. package/dist/cjs/functions.js.map +1 -1
  4. package/dist/cjs/generated-types.d.ts +1 -0
  5. package/dist/cjs/index.d.ts +6 -2
  6. package/dist/cjs/index.js +17 -5
  7. package/dist/cjs/index.js.map +1 -1
  8. package/dist/cjs/send/depends-on.js +11 -40
  9. package/dist/cjs/send/depends-on.js.map +1 -1
  10. package/dist/cjs/send/fields.js +18 -5
  11. package/dist/cjs/send/fields.js.map +1 -1
  12. package/dist/cjs/send/functions.d.ts +2 -2
  13. package/dist/cjs/send/functions.js +40 -29
  14. package/dist/cjs/send/functions.js.map +1 -1
  15. package/dist/cjs/send/generated-types.d.ts +2 -0
  16. package/dist/cjs/send/index.d.ts +5 -2
  17. package/dist/cjs/send/index.js +1 -1
  18. package/dist/cjs/send/index.js.map +1 -1
  19. package/dist/cjs/types.d.ts +10 -0
  20. package/dist/cjs/types.js.map +1 -1
  21. package/dist/esm/functions.d.ts +0 -1
  22. package/dist/esm/functions.js +2 -10
  23. package/dist/esm/functions.js.map +1 -1
  24. package/dist/esm/generated-types.d.ts +1 -0
  25. package/dist/esm/index.d.ts +6 -2
  26. package/dist/esm/index.js +17 -5
  27. package/dist/esm/index.js.map +1 -1
  28. package/dist/esm/send/depends-on.js +11 -40
  29. package/dist/esm/send/depends-on.js.map +1 -1
  30. package/dist/esm/send/fields.js +18 -5
  31. package/dist/esm/send/fields.js.map +1 -1
  32. package/dist/esm/send/functions.d.ts +2 -2
  33. package/dist/esm/send/functions.js +40 -29
  34. package/dist/esm/send/functions.js.map +1 -1
  35. package/dist/esm/send/generated-types.d.ts +2 -0
  36. package/dist/esm/send/index.d.ts +5 -2
  37. package/dist/esm/send/index.js +1 -1
  38. package/dist/esm/send/index.js.map +1 -1
  39. package/dist/esm/types.d.ts +10 -0
  40. package/dist/esm/types.js.map +1 -1
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +3 -3
  43. package/src/__tests__/functions.test.ts +159 -0
  44. package/src/constants.ts +1 -1
  45. package/src/functions.ts +66 -65
  46. package/src/generated-types.ts +4 -0
  47. package/src/index.ts +43 -26
  48. package/src/send/__tests__/depends-on.test.ts +28 -0
  49. package/src/send/__tests__/functions.test.ts +1178 -0
  50. package/src/send/depends-on.ts +41 -69
  51. package/src/send/fields.ts +304 -299
  52. package/src/send/functions.ts +213 -153
  53. package/src/send/generated-types.ts +10 -2
  54. package/src/send/index.ts +4 -4
  55. package/src/types.ts +33 -21
@@ -1,185 +1,245 @@
1
- import { FBEvent, UserData, EventOptions, FBClient, FBStandardEventType, FBNonStandardEventType } from '../types'
1
+ import { FBEvent, UserData, EventOptions, FBClient, FBStandardEventType, FBNonStandardEventType, FBClientParamBuilder, PIIType, PIIParamName } from '../types'
2
2
  import { Payload } from './generated-types'
3
3
  import { Settings } from '../generated-types'
4
4
  import { UniversalStorage, Analytics } from '@segment/analytics-next'
5
- import { US_STATE_CODES, COUNTRY_CODES, MAX_INIT_COUNT, INIT_COUNT_KEY, USER_DATA_KEY } from '../constants'
5
+ import {US_STATE_CODES, COUNTRY_CODES, MAX_INIT_COUNT, INIT_COUNT_KEY, USER_DATA_KEY } from '../constants'
6
6
  import { storageFallback, setStorageInitCount } from '../functions'
7
7
  import { getNotVisibleForEvent } from './depends-on'
8
8
 
9
- export function send(client: FBClient, payload: Payload, settings: Settings, analytics: Analytics) {
10
- const { pixelId } = settings
11
- const { event_config: { custom_event_name, event_name } = {} } = payload
9
+ export function send(client: FBClient, clientParamBuilder: FBClientParamBuilder | undefined, payload: Payload, settings: Settings, analytics: Analytics) {
10
+ const { pixelId } = settings
11
+ const {
12
+ event_config: {
13
+ custom_event_name,
14
+ event_name
15
+ } = {}
16
+ } = payload
12
17
 
13
- const isCustom = event_name === 'CustomEvent' ? true : false
18
+ const isCustom = event_name === 'CustomEvent' ? true : false
14
19
 
15
- const errorMessage = validate(payload)
20
+ const errorMessage = validate(payload)
16
21
 
17
- if (errorMessage) {
18
- console.warn(`${errorMessage}`)
19
- return
20
- }
21
-
22
- const fbEvent = formatFBEvent(payload)
23
-
24
- maybeSendUserData(client, payload, settings, analytics)
25
-
26
- const options = formatOptions(payload)
27
-
28
- if (isCustom) {
29
- client('trackSingleCustom', pixelId, custom_event_name as string, { ...fbEvent }, options)
30
- } else {
31
- client('trackSingle', pixelId, event_name as FBStandardEventType, { ...fbEvent }, options)
32
- }
22
+ if(errorMessage) {
23
+ console.warn(`${errorMessage}`)
24
+ return
25
+ }
26
+
27
+ const fbEvent = formatFBEvent(payload)
28
+
29
+ maybeSendUserData(client, clientParamBuilder, payload, settings, analytics)
30
+
31
+ const options = formatOptions(payload)
32
+
33
+ if(isCustom){
34
+ client(
35
+ 'trackSingleCustom',
36
+ pixelId,
37
+ custom_event_name as string,
38
+ { ...fbEvent },
39
+ options
40
+ )
41
+ }
42
+ else {
43
+ client(
44
+ 'trackSingle',
45
+ pixelId,
46
+ event_name as FBStandardEventType,
47
+ { ...fbEvent },
48
+ options
49
+ )
50
+ }
33
51
  }
34
52
 
35
53
  function validate(payload: Payload): string | undefined {
36
- const {
37
- event_config: { event_name },
38
- content_ids,
39
- contents
40
- } = payload
41
-
42
- if (['AddToCart', 'Purchase', 'ViewContent'].includes(event_name)) {
43
- if (
44
- (!content_ids || (Array.isArray(content_ids) && content_ids.length === 0)) &&
45
- (!contents || (Array.isArray(contents) && contents.length === 0))
46
- ) {
47
- return `At least one of content_ids or contents is required for the ${event_name} event.`
48
- }
49
- }
50
-
51
- return undefined
54
+ const {
55
+ event_config: { event_name },
56
+ content_ids,
57
+ contents
58
+ } = payload
59
+
60
+ if(['AddToCart', 'Purchase', 'ViewContent'].includes(event_name)){
61
+ if ((!content_ids || (Array.isArray(content_ids) && content_ids.length === 0)) && (!contents || (Array.isArray(contents) && contents.length === 0))) {
62
+ return `At least one of content_ids or contents is required for the ${event_name} event.`
63
+ }
64
+ }
65
+
66
+ return undefined
52
67
  }
53
68
 
54
69
  function formatFBEvent(payload: Payload): FBEvent {
55
- const {
56
- content_category,
57
- content_ids,
58
- content_name,
59
- content_type,
60
- contents,
61
- currency,
62
- delivery_category,
63
- num_items,
64
- value,
65
- predicted_ltv,
66
- net_revenue,
67
- custom_data,
68
- event_config: { event_name, show_fields } = {}
69
- } = payload
70
-
71
- const fbEvent: FBEvent = {
72
- ...(content_category ? { content_category } : {}),
73
- ...(content_ids && Array.isArray(content_ids) && content_ids.length > 0 ? { content_ids } : {}),
74
- ...(content_name ? { content_name } : {}),
75
- ...(content_type ? { content_type } : {}),
76
- ...(contents && Array.isArray(contents) && contents.length > 0 ? { contents } : {}),
77
- ...(currency ? { currency } : {}),
78
- ...(delivery_category ? { delivery_category } : {}),
79
- ...(typeof num_items === 'number' ? { num_items } : {}),
80
- ...(typeof value === 'number' ? { value } : {}),
81
- ...(typeof predicted_ltv === 'number' ? { predicted_ltv } : {}),
82
- ...(typeof net_revenue === 'number' ? { net_revenue } : {}),
83
- ...(custom_data && Object.entries(custom_data).length > 0 ? { custom_data } : {})
84
- }
85
-
86
- if (show_fields === false) {
87
- // If show_fields is false we delete values for fields which are hidden in the UI.
88
- const fieldsToDelete = getNotVisibleForEvent(event_name as FBStandardEventType | FBNonStandardEventType)
89
- fieldsToDelete.forEach((field) => {
90
- if (field in fbEvent) {
91
- delete fbEvent[field as keyof typeof fbEvent]
92
- }
93
- })
94
- }
95
-
96
- return Object.keys(fbEvent).length > 0 ? fbEvent : {}
70
+ const {
71
+ content_category,
72
+ content_ids,
73
+ content_name,
74
+ content_type,
75
+ contents,
76
+ currency,
77
+ delivery_category,
78
+ num_items,
79
+ value,
80
+ predicted_ltv,
81
+ net_revenue,
82
+ custom_data,
83
+ event_config: {
84
+ event_name,
85
+ show_fields
86
+ } = {}
87
+ } = payload
88
+
89
+ const fbEvent: FBEvent = {
90
+ ...(content_category ? { content_category } : {}),
91
+ ...(content_ids && Array.isArray(content_ids) && content_ids.length > 0 ? { content_ids } : {}),
92
+ ...(content_name ? { content_name } : {}),
93
+ ...(content_type ? { content_type } : {}),
94
+ ...(contents && Array.isArray(contents) && contents.length > 0 ? { contents } : {}),
95
+ ...(currency ? { currency } : {}),
96
+ ...(delivery_category ? { delivery_category } : {}),
97
+ ...(typeof num_items === 'number' ? { num_items } : {}),
98
+ ...(typeof value === 'number' ? { value } : {}),
99
+ ...(typeof predicted_ltv === 'number' ? { predicted_ltv } : {}),
100
+ ...(typeof net_revenue === 'number' ? { net_revenue } : {}),
101
+ ...(custom_data && Object.entries(custom_data).length > 0 ? { custom_data } : {})
102
+ }
103
+
104
+ if(show_fields === false){
105
+ // If show_fields is false we delete values for fields which are hidden in the UI.
106
+ const fieldsToDelete = getNotVisibleForEvent(event_name as FBStandardEventType | FBNonStandardEventType)
107
+ fieldsToDelete.forEach(field => {
108
+ if (field in fbEvent) {
109
+ delete fbEvent[field as keyof typeof fbEvent]
110
+ }
111
+ })
112
+ }
113
+
114
+ return Object.keys(fbEvent).length > 0 ? fbEvent : {}
97
115
  }
98
116
 
99
117
  function formatOptions(payload: Payload): EventOptions | undefined {
100
- const { eventID, eventSourceUrl } = payload
101
- const options: EventOptions = {
102
- ...(eventID ? { eventID } : {}),
103
- ...(eventSourceUrl ? { eventSourceUrl } : {})
104
- }
105
- return Object.values(options).some(Boolean) ? options : undefined
118
+ const { eventID, eventSourceUrl } = payload
119
+ const options: EventOptions = {
120
+ ...(eventID ? { eventID } : {}),
121
+ ...(eventSourceUrl ? { eventSourceUrl } : {}),
122
+ }
123
+ return Object.values(options).some(Boolean) ? options : undefined
106
124
  }
107
125
 
108
- function maybeSendUserData(client: FBClient, payload: Payload, settings: Settings, analytics: Analytics) {
109
- const { pixelId } = settings
110
- const { userData } = payload
111
- const userDataFormatted = formatUserData(userData)
126
+ function maybeSendUserData(client: FBClient, clientParamBuilder: FBClientParamBuilder | undefined, payload: Payload, settings: Settings, analytics: Analytics) {
127
+ const {
128
+ pixelId
129
+ } = settings
130
+ const {
131
+ userData
132
+ } = payload
133
+ const userDataFormatted = formatUserData(userData, clientParamBuilder)
134
+
135
+ if(userDataFormatted) {
136
+ /*
137
+ Facebook indicated that init should only trigger on a single page load up to max 2 times.
138
+ When userData is created it gets added to storage and included in the next init call on page load.
139
+ Facebook also advised to always send userData when it's available, even if it was collected via previous events.
140
+ */
141
+ const storage = (analytics.storage as UniversalStorage<Record<string, string>>) ?? storageFallback
142
+ const initCountFromStorage: string | null = storage.get(INIT_COUNT_KEY)
143
+ const initCount: number | undefined = (initCountFromStorage && !isNaN(Number(initCountFromStorage)))
144
+ ? parseInt(initCountFromStorage, 10)
145
+ : undefined
146
+
147
+ if(typeof initCount === 'number' && initCount < MAX_INIT_COUNT) {
148
+ client('init', pixelId, userDataFormatted)
149
+ setStorageInitCount(analytics, initCount + 1)
150
+ }
151
+
152
+ storage.set(USER_DATA_KEY, JSON.stringify(userDataFormatted))
153
+ }
154
+ }
112
155
 
113
- if (userDataFormatted) {
114
- const storage = (analytics.storage as UniversalStorage<Record<string, string>>) ?? storageFallback
115
- const initCountFromStorage: string | null = storage.get(INIT_COUNT_KEY)
116
- const initCount: number | undefined =
117
- initCountFromStorage && !isNaN(Number(initCountFromStorage)) ? parseInt(initCountFromStorage, 10) : undefined
156
+ function formatUserData(userData: Payload['userData'], clientParamBuilder: FBClientParamBuilder | undefined): UserData | undefined {
157
+ if(!userData){
158
+ return undefined
159
+ }
118
160
 
119
- if (typeof initCount === 'number' && initCount < MAX_INIT_COUNT) {
120
- client('init', pixelId, userDataFormatted)
121
- setStorageInitCount(analytics, initCount + 1)
161
+ const {
162
+ external_id,
163
+ em,
164
+ ph,
165
+ fn,
166
+ ln,
167
+ ge,
168
+ db,
169
+ ct,
170
+ st,
171
+ zp,
172
+ country,
173
+ fbp,
174
+ fbc
175
+ } = userData
176
+
177
+ let fbcValue = fbc ? fbc.trim() : undefined
178
+ let fbpValue = fbp ? fbp.trim() : undefined
179
+
180
+ if(clientParamBuilder){
181
+ clientParamBuilder.processAndCollectAllParams()
182
+ fbcValue = clientParamBuilder.getFbc() || fbcValue
183
+ fbpValue = clientParamBuilder.getFbp() || fbpValue
184
+ }
185
+
186
+ const ud: UserData = {
187
+ ...(formatPII(em, 'email', 'em', clientParamBuilder, (s) => s.toLowerCase().trim())),
188
+ ...(formatPII(ph, 'phone', 'ph', clientParamBuilder, (s) => s.replace(/\D/g, ''))),
189
+ ...(formatPII(fn, 'first_name', 'fn', clientParamBuilder, (s) => s.toLowerCase().trim())),
190
+ ...(formatPII(ln, 'last_name', 'ln', clientParamBuilder, (s) => s.toLowerCase().trim())),
191
+ ...(formatPII(ge, 'gender', 'ge', clientParamBuilder, (s) => (['m', 'f'].includes(s) ? s as 'm' | 'f' : undefined) ) as {ge: 'm'|'f'} || {}),
192
+ ...(formatPII(db, 'date_of_birth', 'db', clientParamBuilder, (s) => formatDate(s))),
193
+ ...(formatPII(ct, 'city', 'ct', clientParamBuilder, (s) => s.toLowerCase().replace(/\s+/g, ''))),
194
+ ...(formatPII(st, 'state', 'st', clientParamBuilder, (s) => fromMap(US_STATE_CODES, s))),
195
+ ...(formatPII(zp, 'zip_code', 'zp', clientParamBuilder, (s) => s.trim())),
196
+ ...(formatPII(country, 'country', 'country', clientParamBuilder, (s) => fromMap(COUNTRY_CODES, s))),
197
+ ...(formatPII(external_id, 'external_id', 'external_id', clientParamBuilder, (s) => s.trim())),
198
+ ...(fbcValue ? { fbc: fbcValue } : {}),
199
+ ...(fbpValue ? { fbp: fbpValue } : {})
122
200
  }
123
201
 
124
- storage.set(USER_DATA_KEY, JSON.stringify(userDataFormatted))
125
- }
202
+ if(Object.keys(ud).length === 0){
203
+ return undefined
204
+ }
205
+ return ud
126
206
  }
127
207
 
128
- function formatUserData(userData: Payload['userData']): UserData | undefined {
129
- if (!userData) {
130
- return undefined
131
- }
132
-
133
- const { external_id, em, ph, fn, ln, ge, db, ct, st, zp, country } = userData
134
-
135
- const dbFormatted = formatDate(db)
136
- const stFormatted = fromMap(US_STATE_CODES, st)
137
- const countryFormatted = fromMap(COUNTRY_CODES, country)
138
-
139
- const ud: UserData = {
140
- ...(typeof em === 'string' ? { em: em.toLowerCase().trim() } : {}), // lowercase and trim whitespace
141
- ...(typeof ph === 'string' ? { ph: ph.replace(/\D/g, '') } : {}), // remove non-numeric characters
142
- ...(typeof fn === 'string' ? { fn: fn.toLowerCase().trim() } : {}), // lowercase and trim whitespace
143
- ...(typeof ln === 'string' ? { ln: ln.toLowerCase().trim() } : {}), // lowercase and trim whitespace
144
- ...(typeof ge === 'string' && ['m', 'f'].includes(ge) ? { ge: ge as 'm' | 'f' } : {}),
145
- ...(typeof dbFormatted === 'string' ? { db: dbFormatted } : {}), // format date to YYYYMMDD
146
- ...(typeof ct === 'string' ? { ct: ct.toLowerCase().replace(/\s+/g, '') } : {}), // lowercase and replace any whitespace
147
- ...(typeof stFormatted === 'string' ? { st: stFormatted } : {}), // lowercase 2 character state code
148
- ...(typeof zp === 'string' ? { zp: zp.trim() } : {}),
149
- ...(typeof countryFormatted === 'string' ? { country: countryFormatted } : {}), // lowercase 2 character country code
150
- ...(typeof external_id === 'string' ? { external_id: external_id.trim() } : {}) // trim whitespace
151
- }
152
-
153
- if (Object.keys(ud).length === 0) {
154
- return undefined
155
- }
156
- return ud
208
+ function formatPII<K extends PIIParamName, V extends string>(
209
+ value: string | undefined,
210
+ piiType: PIIType,
211
+ piiParamType: K,
212
+ clientParamBuilder: FBClientParamBuilder | undefined,
213
+ formatter: (s: string) => string | undefined
214
+ ): Partial<Record<K, V>> {
215
+ if(!value) {
216
+ return {}
217
+ }
218
+ const val = clientParamBuilder?.getNormalizedAndHashedPII(value, piiType) ?? formatter(value)
219
+ return val ? ({ [piiParamType]: val as V } as Partial<Record<K, V>>) : {}
157
220
  }
158
221
 
159
222
  function formatDate(isoDate?: string): string | undefined {
160
- if (!isoDate || typeof isoDate !== 'string') {
161
- return undefined
162
- }
163
- const date = new Date(isoDate)
164
- if (isNaN(date.getTime())) {
165
- return undefined
166
- }
167
- const year = date.getUTCFullYear()
168
- const month = (date.getUTCMonth() + 1).toString().padStart(2, '0')
169
- const day = date.getUTCDate().toString().padStart(2, '0')
170
- return `${year}${month}${day}`
223
+ if (!isoDate || typeof isoDate !== 'string') {
224
+ return undefined
225
+ }
226
+ const date = new Date(isoDate)
227
+ if (isNaN(date.getTime())) {
228
+ return undefined
229
+ }
230
+ const year = date.getUTCFullYear()
231
+ const month = (date.getUTCMonth() + 1).toString().padStart(2, '0')
232
+ const day = date.getUTCDate().toString().padStart(2, '0')
233
+ return `${year}${month}${day}`
171
234
  }
172
235
 
173
236
  function fromMap(map: Map<string, string>, value?: string): string | undefined {
174
- const cleaned = value
175
- ?.toLowerCase()
176
- .replace(/[^a-z]/g, '')
177
- .trim()
178
- if (!cleaned) {
179
- return undefined
180
- }
181
- if (cleaned.length === 2 && Array.from(map.values()).includes(cleaned)) {
182
- return cleaned
183
- }
184
- return map.get(cleaned) || undefined
185
- }
237
+ const cleaned = value?.toLowerCase().replace(/[^a-z]/g, '').trim()
238
+ if (!cleaned) {
239
+ return undefined
240
+ }
241
+ if(cleaned.length === 2 && Array.from(map.values()).includes(cleaned)) {
242
+ return cleaned
243
+ }
244
+ return map.get(cleaned) || undefined
245
+ }
@@ -111,7 +111,7 @@ export interface Payload {
111
111
  */
112
112
  em?: string
113
113
  /**
114
- * Phone number of the user
114
+ * Phone number of the user. Make sure to include the country code. For example, "15551234567" for a US number.
115
115
  */
116
116
  ph?: string
117
117
  /**
@@ -139,12 +139,20 @@ export interface Payload {
139
139
  */
140
140
  st?: string
141
141
  /**
142
- * ZIP or postal code of the user. For example, "94025" for Menlo Park, CA, or "10001" for New York City.
142
+ * ZIP or postal code of the user. For example, U.S zip code: 94035, Australia zip code: 1987, France zip code: 75018, UK zip code: m11ae.
143
143
  */
144
144
  zp?: string
145
145
  /**
146
146
  * The country of the user. Facebook expects the 2-letter ISO 3166-1 alpha-2 country code. For example, "US" for the United States, or "GB" for the United Kingdom.
147
147
  */
148
148
  country?: string
149
+ /**
150
+ * Use this field to pass the Facebook browser cookie value (_fbp) associated with the user. If the "Format User Data with Parameter Builder" setting is enabled, Segment will automatically capture this value from the _fbp cookie.
151
+ */
152
+ fbp?: string
153
+ /**
154
+ * Use this field to pass The Facebook browser cookie value (_fbc) associated with the user. If the "Format User Data with Parameter Builder" setting is enabled, Segment will automatically capture this value from the _fbc cookie.
155
+ */
156
+ fbc?: string
149
157
  }
150
158
  }
package/src/send/index.ts CHANGED
@@ -2,18 +2,18 @@ import type { BrowserActionDefinition } from '@segment/browser-destination-runti
2
2
  import type { Settings } from '../generated-types'
3
3
  import type { Payload } from './generated-types'
4
4
  import { AllFields } from './fields'
5
- import type { FBClient } from '../types'
5
+ import type { FBClient, FBClientParamBuilder } from '../types'
6
6
  import { send } from './functions'
7
7
 
8
- const action: BrowserActionDefinition<Settings, FBClient, Payload> = {
8
+ const action: BrowserActionDefinition<Settings, { fbq: FBClient, clientParamBuilder: FBClientParamBuilder | undefined }, Payload> = {
9
9
  title: 'Send Event',
10
10
  description: 'Send a Standard or Custom Event to Facebook Conversions API.',
11
11
  defaultSubscription: 'type = "track"',
12
12
  platform: 'web',
13
13
  fields: AllFields,
14
14
  perform: (client, { payload, settings, analytics }) => {
15
- return send(client, payload, settings, analytics)
15
+ return send(client.fbq, client.clientParamBuilder, payload, settings, analytics)
16
16
  }
17
17
  }
18
18
 
19
- export default action
19
+ export default action
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export interface WindowWithOptionalFbq extends Omit<Window, 'fbq' | '_fbq'> {
2
- fbq?: FBClient
3
- _fbq?: FBClient
2
+ fbq?: FBClient;
3
+ _fbq?: FBClient;
4
4
  }
5
5
 
6
6
  export type FBStandardEventType =
@@ -29,8 +29,8 @@ export type InitOptions = {
29
29
  agent?: string
30
30
  }
31
31
 
32
- export type EventOptions = {
33
- eventID?: string
32
+ export type EventOptions = {
33
+ eventID?: string
34
34
  eventSourceUrl?: string
35
35
  }
36
36
 
@@ -47,6 +47,8 @@ export type UserData = {
47
47
  st?: string // State (FB hashes with SHA-256)
48
48
  zp?: string // ZIP/Postal code (FB hashes with SHA-256)
49
49
  country?: string // Country code (FB hashes with SHA-256)
50
+ fbp?: string // Facebook browser pixel ID
51
+ fbc?: string // Facebook click ID
50
52
  }
51
53
 
52
54
  export type FBEvent = {
@@ -63,7 +65,7 @@ export type FBEvent = {
63
65
  currency?: string
64
66
  delivery_category?: string
65
67
  num_items?: number
66
- value?: number
68
+ value?: number
67
69
  custom_data?: {
68
70
  [k: string]: unknown
69
71
  }
@@ -78,26 +80,36 @@ export type FBClient = {
78
80
  callMethod?: (...args: unknown[]) => void
79
81
  (command: 'set', key: string, value: boolean, pixelId: string): void
80
82
  (command: 'dataProcessingOptions', options: string[], country?: number, state?: number): void
81
- (command: 'init', pixelId: string, userData?: UserData, options?: InitOptions): void
83
+ (command: 'init', pixelId: string, userData?: UserData, options?: InitOptions ): void
82
84
  (command: 'trackSingle', pixelId: string, event: FBStandardEventType, params?: FBEvent, options?: EventOptions): void
83
85
  (command: 'trackSingleCustom', pixelId: string, event: string, params?: FBEvent, options?: EventOptions): void
84
86
  }
85
87
 
88
+ export type FBClientParamBuilder = {
89
+ getNormalizedAndHashedPII: (value: string, piiType: PIIType) => string | undefined
90
+ processAndCollectAllParams: () => void
91
+ getFbc: () => string | undefined
92
+ getFbp: () => string | undefined
93
+ }
94
+
95
+ export type PIIType = 'email' | 'phone' | 'first_name' | 'last_name' | 'gender' | 'date_of_birth' | 'city' | 'state' | 'zip_code' | 'country' | 'external_id'
96
+ export type PIIParamName = 'em' | 'ph' | 'fn' | 'ln' | 'ge' | 'db' | 'ct' | 'st' | 'zp' | 'country' | 'external_id'
97
+
86
98
  export const LDU = {
87
- Disabled: { key: 'Disabled', state: undefined, country: undefined },
88
- GeolocationLogic: { key: 'GeolocationLogic', state: 0, country: 0 },
89
- California: { key: 'California', state: 1000, country: 1 },
90
- Colorado: { key: 'Colorado', state: 1001, country: 1 },
91
- Connecticut: { key: 'Connecticut', state: 1002, country: 1 },
92
- Florida: { key: 'Florida', state: 1003, country: 1 },
93
- Oregon: { key: 'Oregon', state: 1004, country: 1 },
94
- Texas: { key: 'Texas', state: 1005, country: 1 },
95
- Montana: { key: 'Montana', state: 1006, country: 1 },
96
- Delaware: { key: 'Delaware', state: 1007, country: 1 },
97
- Nebraska: { key: 'Nebraska', state: 1008, country: 1 },
98
- NewHampshire: { key: 'NewHampshire', state: 1009, country: 1 },
99
- NewJersey: { key: 'NewJersey', state: 1010, country: 1 },
100
- Minnesota: { key: 'Minnesota', state: 1011, country: 1 }
99
+ Disabled: {key: 'Disabled', state: undefined, country: undefined},
100
+ GeolocationLogic: {key: 'GeolocationLogic', state: 0, country: 0},
101
+ California: {key: 'California', state: 1000, country: 1},
102
+ Colorado: {key: 'Colorado', state: 1001, country: 1},
103
+ Connecticut: {key: 'Connecticut', state: 1002, country: 1},
104
+ Florida: {key: 'Florida', state: 1003, country: 1},
105
+ Oregon: {key: 'Oregon', state: 1004, country: 1},
106
+ Texas: {key: 'Texas', state: 1005, country: 1},
107
+ Montana: {key: 'Montana', state: 1006, country: 1},
108
+ Delaware: {key: 'Delaware', state: 1007, country: 1},
109
+ Nebraska: {key: 'Nebraska', state: 1008, country: 1},
110
+ NewHampshire: {key: 'NewHampshire', state: 1009, country: 1},
111
+ NewJersey: {key: 'NewJersey', state: 1010, country: 1},
112
+ Minnesota: {key: 'Minnesota', state: 1011, country: 1}
101
113
  } as const
102
114
 
103
- export type LDU = typeof LDU[keyof typeof LDU]
115
+ export type LDU = typeof LDU[keyof typeof LDU]