@splendidlabz/tracking 0.2.11 → 0.2.13

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/node.js CHANGED
@@ -8,15 +8,36 @@ import {
8
8
  } from './consts.js'
9
9
  import { formatUserData } from './utils.js'
10
10
 
11
- // https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/
11
+ /**
12
+ * Creates a Facebook Conversions API tracker for server-side tracking
13
+ * @param {Object} config - Configuration options
14
+ * @param {string} config.pixelID - Facebook Pixel ID
15
+ * @param {string} [config.testEventCode] - Test event code for debugging
16
+ * @param {string} config.accessToken - Facebook Access Token (required)
17
+ * @param {string} config.framework - Framework being used (astro, express, fastify, koa)
18
+ * @return {Object} FB tracking instance
19
+ * @property {Function} sendEvent - Send a pre-formatted event to CAPI
20
+ * @property {Function} createEvent - Create an event payload
21
+ * @property {Function} track - Track an event and send to CAPI
22
+ * @property {Function} sendCAPIRequest - Send raw request to CAPI
23
+ * @see https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/
24
+ */
12
25
  export default function FB({ pixelID, testEventCode, accessToken, framework }) {
13
26
  framework = framework.toLowerCase()
14
27
 
15
28
  if (!accessToken) throw new Error('Facebook Access Token required')
16
29
 
17
30
  return {
18
- // When used as API call — frontend would have done all the work
19
- // So we can just send the body to the CAPI request
31
+ /**
32
+ * Sends a pre-formatted event to Facebook CAPI
33
+ * Used when frontend has already prepared the event data
34
+ * @param {Object} [props={}] - Event properties including pixel_id, test_event_code, user_data
35
+ * @param {Object} [options={}] - Additional options
36
+ * @param {Object} [options.context] - Framework-specific request context
37
+ * @param {boolean} [options.debug] - Enable debug logging
38
+ * @param {boolean} [options.dryRun] - Skip actual API call
39
+ * @return {Promise<Object>} CAPI response
40
+ */
20
41
  async sendEvent(props = {}, options = {}) {
21
42
  const { pixel_id, test_event_code, user_data, ...rest } = props
22
43
  const { context } = options
@@ -44,6 +65,14 @@ export default function FB({ pixelID, testEventCode, accessToken, framework }) {
44
65
  return this.sendCAPIRequest(body, { ...options, pixel_id })
45
66
  },
46
67
 
68
+ /**
69
+ * Creates a Facebook CAPI event payload
70
+ * @param {string} eventName - Name of the event to track
71
+ * @param {Object} [props={}] - Event properties and user data
72
+ * @param {Object} [props.context] - Framework-specific request context (required for auto-filled properties)
73
+ * @param {Object} [options={}] - Additional options
74
+ * @return {Promise<Object>} Event payload ready to send to CAPI
75
+ */
47
76
  async createEvent(eventName, props = {}, options = {}) {
48
77
  const { context, ...p } = props
49
78
  const { p: eventParams, o: r1 } = splitObject(p, SERVER_EVENT_PARAMS)
@@ -93,12 +122,32 @@ export default function FB({ pixelID, testEventCode, accessToken, framework }) {
93
122
  return body
94
123
  },
95
124
 
96
- // When used directly via backend
125
+ /**
126
+ * Tracks an event and sends it to Facebook CAPI
127
+ * Combines createEvent and sendCAPIRequest
128
+ * @param {string} eventName - Name of the event to track
129
+ * @param {Object} [props={}] - Event properties and user data
130
+ * @param {Object} [props.context] - Framework-specific request context
131
+ * @param {Object} [options={}] - Additional options
132
+ * @param {boolean} [options.debug] - Enable debug logging
133
+ * @param {boolean} [options.dryRun] - Skip actual API call
134
+ * @param {string} [options.pixel_id] - Override default pixel ID
135
+ * @return {Promise<Object>} CAPI response
136
+ */
97
137
  async track(eventName, props = {}, options = {}) {
98
138
  const body = await this.createEvent(eventName, props, options)
99
139
  return this.sendCAPIRequest(body, options)
100
140
  },
101
141
 
142
+ /**
143
+ * Sends a raw request to Facebook Conversions API
144
+ * @param {Object} body - Request body containing event data
145
+ * @param {Object} [options={}] - Request options
146
+ * @param {boolean} [options.debug] - Log request body
147
+ * @param {boolean} [options.dryRun] - Skip actual API call
148
+ * @param {string} [options.pixel_id] - Override default pixel ID
149
+ * @return {Promise<Object>} CAPI response
150
+ */
102
151
  async sendCAPIRequest(body, options) {
103
152
  const { debug = false, dryRun = false, pixel_id } = options
104
153
  const pixel = pixel_id || pixelID
@@ -121,6 +170,17 @@ export default function FB({ pixelID, testEventCode, accessToken, framework }) {
121
170
  // ========================
122
171
  // Helper Functions
123
172
  // ========================
173
+
174
+ /**
175
+ * Gets default event parameters based on the framework and context
176
+ * @param {string} framework - Framework name (astro, express, fastify, koa)
177
+ * @param {Object} context - Framework-specific request context
178
+ * @return {Object} Default event parameters
179
+ * @property {string} event_id - Randomly generated event ID
180
+ * @property {string} action_source - Always set to 'website'
181
+ * @property {number} event_time - Unix timestamp in seconds
182
+ * @property {string} event_source_url - Full URL of the request
183
+ */
124
184
  function getEventParamDefaults(framework, context) {
125
185
  return {
126
186
  event_id: randomString(10),
@@ -130,6 +190,12 @@ function getEventParamDefaults(framework, context) {
130
190
  }
131
191
  }
132
192
 
193
+ /**
194
+ * Extracts the full URL from framework-specific context
195
+ * @param {string} framework - Framework name (astro, express, fastify, koa)
196
+ * @param {Object} context - Framework-specific request context
197
+ * @return {string} Full URL including protocol, host, and path
198
+ */
133
199
  function getUrl(framework, context) {
134
200
  if (framework === 'astro') return context.url.href
135
201
  if (framework === 'express') {
@@ -143,6 +209,12 @@ function getUrl(framework, context) {
143
209
  }
144
210
  }
145
211
 
212
+ /**
213
+ * Extracts client IP address from framework-specific context
214
+ * @param {string} framework - Framework name (astro, express, fastify, koa)
215
+ * @param {Object} context - Framework-specific request context
216
+ * @return {string} Client IP address
217
+ */
146
218
  function getIP(framework, context) {
147
219
  if (framework === 'astro') return context.clientAddress
148
220
  if (framework === 'express')
@@ -151,6 +223,12 @@ function getIP(framework, context) {
151
223
  if (framework === 'koa') return context.ip
152
224
  }
153
225
 
226
+ /**
227
+ * Extracts user agent string from framework-specific context
228
+ * @param {string} framework - Framework name (astro, express, fastify, koa)
229
+ * @param {Object} context - Framework-specific request context
230
+ * @return {string} User agent string
231
+ */
154
232
  function getUserAgent(framework, context) {
155
233
  if (framework === 'astro') return context.request.headers.get('user-agent')
156
234
  if (framework === 'express') return context.get('user-agent')
@@ -158,6 +236,13 @@ function getUserAgent(framework, context) {
158
236
  if (framework === 'koa') return context.get('user-agent')
159
237
  }
160
238
 
239
+ /**
240
+ * Extracts cookie value from framework-specific context
241
+ * @param {string} framework - Framework name (astro, express, fastify, koa)
242
+ * @param {Object} context - Framework-specific request context
243
+ * @param {string} name - Cookie name
244
+ * @return {string} Cookie value
245
+ */
161
246
  function getCookie(framework, context, name) {
162
247
  if (framework === 'astro') return context.cookies.get(name)?.value
163
248
  if (framework === 'express') return context.cookies?.[name]
@@ -165,6 +250,17 @@ function getCookie(framework, context, name) {
165
250
  if (framework === 'koa') return context.cookies?.get(name)
166
251
  }
167
252
 
253
+ /**
254
+ * Normalizes and enriches user data for Facebook CAPI
255
+ * Hashes required properties and adds client information from request context
256
+ * @param {Object} params - Parameters object
257
+ * @param {Object} params.context - Framework-specific request context
258
+ * @param {string} params.framework - Framework name (astro, express, fastify, koa)
259
+ * @param {Object} params.userProps - User properties to normalize
260
+ * @param {string} [params.fbc] - Facebook click ID cookie
261
+ * @param {string} [params.fbp] - Facebook browser ID cookie
262
+ * @return {Promise<Object>} Normalized user data with hashed properties and client info
263
+ */
168
264
  async function normalizeUserData({ context, framework, userProps, fbc, fbp }) {
169
265
  const { p: userPropsToHash, o: otherUserProps } = splitObject(
170
266
  userProps,
package/lib/fb/web.js CHANGED
@@ -8,10 +8,39 @@ import {
8
8
  } from './consts.js'
9
9
  import { formatUserData } from './utils.js'
10
10
 
11
+ /**
12
+ * Creates a Facebook Pixel and CAPI tracker for client-side tracking
13
+ * @param {Object} config - Configuration options
14
+ * @param {string} config.pixelID - Facebook Pixel ID
15
+ * @param {string} [config.testEventCode] - Test event code for debugging
16
+ * @param {string} config.capiEndpoint - API endpoint for sending CAPI requests
17
+ * @return {Object} FB tracking instance
18
+ * @property {Function} init - Initialize Facebook Pixel
19
+ * @property {Function} createEvent - Create event data for both Pixel and CAPI
20
+ * @property {Function} track - Track event via both Pixel and CAPI
21
+ * @property {Function} sendPixelEvent - Send event to Facebook Pixel
22
+ * @property {Function} sendCAPIRequest - Send event to CAPI endpoint
23
+ */
11
24
  export default function FB({ pixelID, testEventCode, capiEndpoint }) {
12
25
  return {
26
+ /**
27
+ * Initializes the Facebook Pixel on the page
28
+ * @return {void}
29
+ */
13
30
  init: _ => initPixel(pixelID),
14
31
 
32
+ /**
33
+ * Creates event data for both Facebook Pixel and CAPI
34
+ * @param {string} event_name - Name of the event to track
35
+ * @param {Object} [props={}] - Event properties and user data
36
+ * @param {string} [props.eventURL] - Custom URL for the event (defaults to current page)
37
+ * @param {string} [props.actionSource] - Action source (defaults to 'website')
38
+ * @param {Object} [options={}] - Additional options
39
+ * @param {boolean} [options.debug] - Enable debug logging
40
+ * @return {Promise<Object>} Object containing pixelData and capiData
41
+ * @property {Object} pixelData - Data formatted for Facebook Pixel
42
+ * @property {Object} capiData - Data formatted for CAPI
43
+ */
15
44
  async createEvent(event_name, props = {}, options = {}) {
16
45
  const { debug = false } = options
17
46
  const { eventURL, actionSource, ...r } = props
@@ -60,6 +89,15 @@ export default function FB({ pixelID, testEventCode, capiEndpoint }) {
60
89
  return { pixelData, capiData }
61
90
  },
62
91
 
92
+ /**
93
+ * Tracks an event by sending to both Facebook Pixel and CAPI
94
+ * @param {string} event_name - Name of the event to track
95
+ * @param {Object} [props={}] - Event properties and user data
96
+ * @param {Object} [options={}] - Additional options
97
+ * @param {boolean} [options.debug] - Enable debug logging
98
+ * @param {boolean} [options.dryRun] - Skip actual tracking (for testing)
99
+ * @return {Promise<Object>} CAPI response body
100
+ */
63
101
  async track(event_name, props = {}, options = {}) {
64
102
  const { debug = false, dryRun = false } = options
65
103
  const { pixelData, capiData } = await this.createEvent(
@@ -77,11 +115,20 @@ export default function FB({ pixelID, testEventCode, capiEndpoint }) {
77
115
  return response.body
78
116
  },
79
117
 
80
- // Facebook Pixel Code
81
- // Pixel Standard Reference
82
- // https://developers.facebook.com/docs/meta-pixel/reference#standard-events
83
- // For Advanced Matching when user data is available
84
- // https://developers.facebook.com/docs/meta-pixel/advanced/advanced-matching/
118
+ /**
119
+ * Sends an event to Facebook Pixel
120
+ * Supports standard events, custom events, and advanced matching
121
+ * @param {Object} data - Event data
122
+ * @param {string} data.pixelID - Pixel ID
123
+ * @param {string} data.eventID - Event ID for deduplication
124
+ * @param {string} data.event_name - Event name (use 'init' to initialize pixel)
125
+ * @param {Object} [data.user_data] - User data for advanced matching
126
+ * @param {Object} [options] - Options
127
+ * @param {boolean} [options.debug] - Enable debug logging
128
+ * @return {void}
129
+ * @see https://developers.facebook.com/docs/meta-pixel/reference#standard-events
130
+ * @see https://developers.facebook.com/docs/meta-pixel/advanced/advanced-matching/
131
+ */
85
132
  sendPixelEvent(data, { debug = false }) {
86
133
  const { pixelID, eventID, event_name, user_data = {}, ...rest } = data
87
134
  const hasUserData = notEmpty(user_data)
@@ -108,13 +155,24 @@ export default function FB({ pixelID, testEventCode, capiEndpoint }) {
108
155
  }
109
156
  },
110
157
 
111
- // CAPI Parameters: https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters
158
+ /**
159
+ * Sends a request to the CAPI endpoint
160
+ * @param {Object} data - CAPI event data
161
+ * @return {Promise<Object>} Response from CAPI endpoint
162
+ * @see https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters
163
+ */
112
164
  sendCAPIRequest(data) {
113
165
  return zlFetch.post(capiEndpoint, { body: data })
114
166
  },
115
167
  }
116
168
  }
117
169
 
170
+ /**
171
+ * Initializes the Facebook Pixel by loading the fbevents.js script
172
+ * @param {string} pixelID - Facebook Pixel ID
173
+ * @return {void}
174
+ * @throws {Error} If called outside of browser environment
175
+ */
118
176
  function initPixel(pixelID) {
119
177
  // eslint-disable-next-line
120
178
  !(function (f, b, e, v, n, t, s) {
@@ -72,7 +72,7 @@ export default function (config = {}) {
72
72
  * @param {string} [properties.userId] - User ID (used for distinct ID)
73
73
  * @param {Object} [properties.context] - Request context (for cookie access)
74
74
  * @param {...*} properties.rest - Additional event properties
75
- * @return {Promise|undefined} PostHog capture promise, or undefined if trackDevEvents is true
75
+ * @return {Promise|undefined} PostHog capture promise, or undefined if trackEvents is false
76
76
  */
77
77
  capture(event, properties = {}) {
78
78
  if (!trackEvents) return
@@ -88,7 +88,7 @@ export default function (config = {}) {
88
88
  * Sets person properties on the current user
89
89
  * @param {Object} [set={}] - Properties to set (will overwrite existing values)
90
90
  * @param {Object} [once={}] - Properties to set only once (won't overwrite existing values)
91
- * @return {Promise|undefined} PostHog capture promise, or undefined if trackDevEvents is true
91
+ * @return {Promise|undefined} PostHog capture promise, or undefined if trackEvents is false
92
92
  */
93
93
  setPersonProperties(set = {}, once = {}) {
94
94
  if (!trackEvents) return
@@ -104,7 +104,7 @@ export default function (config = {}) {
104
104
  /**
105
105
  * Removes person properties from the current user
106
106
  * @param {string[]} properties - List of property names to remove
107
- * @return {Promise|undefined} PostHog capture promise, or undefined if trackDevEvents is true
107
+ * @return {Promise|undefined} PostHog capture promise, or undefined if trackEvents is false
108
108
  */
109
109
  removePersonProperties(properties) {
110
110
  if (!trackEvents) return
@@ -15,3 +15,11 @@ This package assumes you're using Posthog for both web and node.js.
15
15
 
16
16
  - Get distinct_id from cookies on the backend automatically when using Astro — just provide context.
17
17
  - Use `trackEvents:false` to disable tracking completely when developing.
18
+
19
+ ## Filtering out local development environments
20
+
21
+ You can create filters which include more than one value by separating values with a comma. We use such a filter to exclude events from local development environments, for example:
22
+
23
+ Host ≠ (doesn’t equal) localhost:8000,localhost:5000,127.0.0.1:8000
24
+
25
+ You can also create filters based on pre-prepared cohorts of users, which is especially useful if you’re using cohorts with Feature Flags or to run Experiments. To do this, simply select the cohort you wish to add to your internal and test user list.
@@ -41,7 +41,8 @@ export default function (config = {}) {
41
41
 
42
42
  /**
43
43
  * Set properties for the current person
44
- * @param {...any} props - Properties to set for the person
44
+ * @param {object} [set={}] - Properties to set (will overwrite existing values)
45
+ * @param {object} [once={}] - Properties to set only once (won't overwrite existing values)
45
46
  * @returns {void}
46
47
  */
47
48
  setPersonProperties(set = {}, once = {}) {
@@ -50,8 +51,9 @@ export default function (config = {}) {
50
51
  },
51
52
 
52
53
  /**
54
+ * Identify a user with PostHog. If the distinctId differs from the existing cookie ID, creates a new identity; otherwise updates properties.
53
55
  * @param {string} distinctId - New unique identifier for the user (email, userId, etc.)
54
- * @param {object} properties - The properties to set for the user
56
+ * @param {object} [properties={}] - The properties to set for the user
55
57
  * @returns {void}
56
58
  */
57
59
  identify(distinctId, properties = {}) {
@@ -67,6 +69,7 @@ export default function (config = {}) {
67
69
  },
68
70
 
69
71
  /**
72
+ * Create an alias for a user, linking two distinct IDs together
70
73
  * @param {string} distinctId - New unique identifier for the user
71
74
  * @param {string} aliasId - Alias for the user
72
75
  * @returns {void}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splendidlabz/tracking",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "Simple Tracking Helper",
5
5
  "type": "module",
6
6
  "files": [
@@ -10,7 +10,7 @@
10
10
  "lib/convertkit"
11
11
  ],
12
12
  "exports": {
13
- "./*": "./lib/*"
13
+ "./*": "./lib/*.js"
14
14
  },
15
15
  "scripts": {
16
16
  "test": "vitest",