@callforge/tracking-client 0.4.0 → 0.4.2

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Lightweight client library for the CallForge tracking API. Handles location-aware phone number assignment with aggressive caching and preload optimization.
4
4
 
5
- **v0.4.0** - Added `ga4MeasurementId` config option for cleaner gtag callback instead of cookie polling.
5
+ **v0.4.1** - Simplified GA4 capture: uses gtag callback when `ga4MeasurementId` configured, no polling fallback.
6
6
 
7
7
  ## Installation
8
8
 
@@ -53,33 +53,26 @@ client.onReady((session) => {
53
53
  });
54
54
  ```
55
55
 
56
- ### 3. GA4 Integration (automatic)
56
+ ### 3. GA4 Integration
57
57
 
58
- The client automatically captures the GA4 client ID and associates it with the tracking session. This enables CallForge to send call events (phone call, conversion, billable conversion) to your Google Analytics 4 property.
59
-
60
- **Requirements:**
61
- 1. Google Analytics 4 must be installed on your site
62
- 2. Configure GA4 credentials in CallForge dashboard (Categories → Edit → GA4 tab)
63
-
64
- **Recommended: Provide Measurement ID for callback-based capture:**
58
+ To enable GA4 call event tracking, provide your GA4 Measurement ID:
65
59
 
66
60
  ```typescript
67
61
  const client = CallForge.init({
68
62
  categoryId: 'your-category-id',
69
- ga4MeasurementId: 'G-XXXXXXXXXX', // Enables gtag('get') callback
63
+ ga4MeasurementId: 'G-XXXXXXXXXX', // Required for GA4 integration
70
64
  });
71
65
  ```
72
66
 
73
- When `ga4MeasurementId` is provided, the client uses the official `gtag('get')` API callback to retrieve the client ID. This is cleaner and more reliable than cookie polling.
67
+ **Requirements:**
68
+ 1. Google Analytics 4 must be installed on your site (`gtag.js`)
69
+ 2. Provide `ga4MeasurementId` in client config
70
+ 3. Configure GA4 credentials in CallForge dashboard (Categories → Edit → GA4 tab)
74
71
 
75
72
  **How it works:**
76
- 1. **If `ga4MeasurementId` is provided AND `window.gtag` exists:**
77
- - Uses `gtag('get', measurementId, 'client_id', callback)` to get the client ID
78
- - No polling needed - callback fires when GA4 is ready
79
- 2. **Otherwise (fallback):**
80
- - Checks for the `_ga` cookie immediately
81
- - If not found, polls every 500ms for up to 10 seconds
82
- - Handles async GA4 script loading
73
+ - Uses `gtag('get', measurementId, 'client_id', callback)` to capture the GA4 client ID
74
+ - Callback fires when GA4 is ready - no polling needed
75
+ - Client ID is automatically sent to CallForge for call event attribution
83
76
 
84
77
  **Manual override:** If you need to pass a custom GA4 client ID:
85
78
 
@@ -89,14 +82,6 @@ client.setParams({
89
82
  });
90
83
  ```
91
84
 
92
- **Extract GA4 client ID yourself:**
93
-
94
- ```typescript
95
- import { getGA4ClientId } from '@callforge/tracking-client';
96
-
97
- const clientId = getGA4ClientId(); // "1234567890.1234567890" or null
98
- ```
99
-
100
85
  ### 4. Track conversion parameters (optional)
101
86
 
102
87
  The client automatically captures ad platform click IDs from the URL:
@@ -198,35 +183,21 @@ const html = getPreloadSnippet({
198
183
  });
199
184
  ```
200
185
 
201
- ### `getGA4ClientId()`
202
-
203
- Extract the GA4 client ID from the `_ga` cookie.
204
-
205
- ```typescript
206
- import { getGA4ClientId } from '@callforge/tracking-client';
207
-
208
- const clientId = getGA4ClientId();
209
- // Returns: "1234567890.1234567890" or null if cookie not found
210
- ```
211
-
212
- **Cookie format:** `GA1.1.1234567890.1234567890`
213
-
214
- The client ID is the last two dot-separated segments (timestamp.random).
215
-
216
186
  ## Tracking Parameters
217
187
 
218
188
  ### Auto-Capture
219
189
 
220
- The client automatically extracts these parameters:
190
+ The client automatically extracts these parameters from the URL:
221
191
 
222
- | Parameter | Source | Capture Method |
223
- |-----------|--------|----------------|
224
- | `gclid` | Google Ads Click ID | URL query param |
225
- | `gbraid` | Google app-to-web (iOS 14+) | URL query param |
226
- | `wbraid` | Google web-to-app | URL query param |
227
- | `msclkid` | Microsoft/Bing Ads | URL query param |
228
- | `fbclid` | Facebook/Meta Ads | URL query param |
229
- | `ga4ClientId` | Google Analytics 4 | `_ga` cookie (polled) |
192
+ | Parameter | Source |
193
+ |-----------|--------|
194
+ | `gclid` | Google Ads Click ID |
195
+ | `gbraid` | Google app-to-web (iOS 14+) |
196
+ | `wbraid` | Google web-to-app |
197
+ | `msclkid` | Microsoft/Bing Ads |
198
+ | `fbclid` | Facebook/Meta Ads |
199
+
200
+ **Note:** `ga4ClientId` is captured via `gtag('get')` callback when `ga4MeasurementId` is configured.
230
201
 
231
202
  ### Persistence
232
203
 
@@ -278,8 +249,6 @@ import type {
278
249
  TrackingParams,
279
250
  ReadyCallback,
280
251
  } from '@callforge/tracking-client';
281
-
282
- import { getGA4ClientId } from '@callforge/tracking-client';
283
252
  ```
284
253
 
285
254
  ### TrackingParams
@@ -291,7 +260,7 @@ interface TrackingParams {
291
260
  wbraid?: string; // Google web-to-app
292
261
  msclkid?: string; // Microsoft/Bing Ads
293
262
  fbclid?: string; // Facebook/Meta Ads
294
- ga4ClientId?: string; // Google Analytics 4 Client ID (auto-captured from _ga cookie)
263
+ ga4ClientId?: string; // Google Analytics 4 Client ID (auto-captured via gtag callback)
295
264
  [key: string]: string | undefined; // Custom params
296
265
  }
297
266
  ```
package/dist/index.d.mts CHANGED
@@ -75,19 +75,11 @@ declare global {
75
75
  }
76
76
  }
77
77
 
78
- /**
79
- * Extract GA4 client_id from the _ga cookie.
80
- * Cookie format: GA1.1.1234567890.1234567890
81
- * Client ID is the last two segments: 1234567890.1234567890
82
- */
83
- declare function getGA4ClientId(): string | null;
84
78
  declare class CallForge {
85
79
  private readonly config;
86
80
  private readonly cache;
87
81
  private sessionPromise;
88
82
  private customParams;
89
- private ga4PollInterval;
90
- private ga4PollTimeout;
91
83
  private sessionId;
92
84
  private sessionCreated;
93
85
  private constructor();
@@ -117,18 +109,10 @@ declare class CallForge {
117
109
  getQueuedParams(): TrackingParams;
118
110
  private patchSession;
119
111
  /**
120
- * Start capturing the GA4 client ID.
121
- * If ga4MeasurementId is configured, uses gtag('get') callback.
122
- * Otherwise falls back to polling the _ga cookie.
123
- */
124
- startGA4ClientIdCapture(): void;
125
- /**
126
- * Start polling for the GA4 _ga cookie.
127
- * If found immediately, calls setParams right away.
128
- * Otherwise polls every 500ms for up to 10 seconds.
112
+ * Capture the GA4 client ID using gtag callback.
113
+ * Only runs if ga4MeasurementId is configured.
129
114
  */
130
- private startGA4CookiePolling;
131
- private stopGA4CookiePolling;
115
+ private captureGA4ClientId;
132
116
  private fetchSession;
133
117
  private getLocationId;
134
118
  private getAutoParams;
@@ -156,4 +140,4 @@ declare class CallForge {
156
140
  */
157
141
  declare function getPreloadSnippet(config: CallForgeConfig): string;
158
142
 
159
- export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getGA4ClientId, getPreloadSnippet };
143
+ export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getPreloadSnippet };
package/dist/index.d.ts CHANGED
@@ -75,19 +75,11 @@ declare global {
75
75
  }
76
76
  }
77
77
 
78
- /**
79
- * Extract GA4 client_id from the _ga cookie.
80
- * Cookie format: GA1.1.1234567890.1234567890
81
- * Client ID is the last two segments: 1234567890.1234567890
82
- */
83
- declare function getGA4ClientId(): string | null;
84
78
  declare class CallForge {
85
79
  private readonly config;
86
80
  private readonly cache;
87
81
  private sessionPromise;
88
82
  private customParams;
89
- private ga4PollInterval;
90
- private ga4PollTimeout;
91
83
  private sessionId;
92
84
  private sessionCreated;
93
85
  private constructor();
@@ -117,18 +109,10 @@ declare class CallForge {
117
109
  getQueuedParams(): TrackingParams;
118
110
  private patchSession;
119
111
  /**
120
- * Start capturing the GA4 client ID.
121
- * If ga4MeasurementId is configured, uses gtag('get') callback.
122
- * Otherwise falls back to polling the _ga cookie.
123
- */
124
- startGA4ClientIdCapture(): void;
125
- /**
126
- * Start polling for the GA4 _ga cookie.
127
- * If found immediately, calls setParams right away.
128
- * Otherwise polls every 500ms for up to 10 seconds.
112
+ * Capture the GA4 client ID using gtag callback.
113
+ * Only runs if ga4MeasurementId is configured.
129
114
  */
130
- private startGA4CookiePolling;
131
- private stopGA4CookiePolling;
115
+ private captureGA4ClientId;
132
116
  private fetchSession;
133
117
  private getLocationId;
134
118
  private getAutoParams;
@@ -156,4 +140,4 @@ declare class CallForge {
156
140
  */
157
141
  declare function getPreloadSnippet(config: CallForgeConfig): string;
158
142
 
159
- export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getGA4ClientId, getPreloadSnippet };
143
+ export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getPreloadSnippet };
package/dist/index.js CHANGED
@@ -35,7 +35,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
35
35
  var index_exports = {};
36
36
  __export(index_exports, {
37
37
  CallForge: () => CallForge,
38
- getGA4ClientId: () => getGA4ClientId,
39
38
  getPreloadSnippet: () => getPreloadSnippet
40
39
  });
41
40
  module.exports = __toCommonJS(index_exports);
@@ -130,19 +129,12 @@ var TrackingCache = class {
130
129
 
131
130
  // src/client.ts
132
131
  var DEFAULT_ENDPOINT = "https://tracking.callforge.io";
133
- function getGA4ClientId() {
134
- if (typeof document === "undefined") return null;
135
- const match = document.cookie.match(/_ga=GA\d+\.\d+\.(.+?)(?:;|$)/);
136
- return match ? match[1] : null;
137
- }
138
132
  var FETCH_TIMEOUT_MS = 1e4;
139
- var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid"];
133
+ var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid", "gad_campaignid", "gad_source"];
140
134
  var CallForge = class _CallForge {
141
135
  constructor(config) {
142
136
  this.sessionPromise = null;
143
137
  this.customParams = {};
144
- this.ga4PollInterval = null;
145
- this.ga4PollTimeout = null;
146
138
  this.sessionId = null;
147
139
  this.sessionCreated = false;
148
140
  this.config = {
@@ -151,7 +143,7 @@ var CallForge = class _CallForge {
151
143
  ga4MeasurementId: config.ga4MeasurementId
152
144
  };
153
145
  this.cache = new TrackingCache(config.categoryId);
154
- this.startGA4ClientIdCapture();
146
+ this.captureGA4ClientId();
155
147
  }
156
148
  /**
157
149
  * Initialize the CallForge tracking client.
@@ -213,55 +205,21 @@ var CallForge = class _CallForge {
213
205
  }
214
206
  }
215
207
  /**
216
- * Start capturing the GA4 client ID.
217
- * If ga4MeasurementId is configured, uses gtag('get') callback.
218
- * Otherwise falls back to polling the _ga cookie.
208
+ * Capture the GA4 client ID using gtag callback.
209
+ * Only runs if ga4MeasurementId is configured.
219
210
  */
220
- startGA4ClientIdCapture() {
221
- if (this.ga4PollInterval !== null || this.ga4PollTimeout !== null) {
222
- return;
223
- }
224
- if (this.config.ga4MeasurementId && typeof window !== "undefined" && window.gtag) {
225
- window.gtag("get", this.config.ga4MeasurementId, "client_id", (clientId) => {
226
- if (clientId) {
227
- this.setParams({ ga4ClientId: clientId });
228
- }
229
- });
211
+ captureGA4ClientId() {
212
+ if (!this.config.ga4MeasurementId) {
230
213
  return;
231
214
  }
232
- this.startGA4CookiePolling();
233
- }
234
- /**
235
- * Start polling for the GA4 _ga cookie.
236
- * If found immediately, calls setParams right away.
237
- * Otherwise polls every 500ms for up to 10 seconds.
238
- */
239
- startGA4CookiePolling() {
240
- const clientId = getGA4ClientId();
241
- if (clientId) {
242
- this.setParams({ ga4ClientId: clientId });
215
+ if (typeof window === "undefined" || !window.gtag) {
243
216
  return;
244
217
  }
245
- this.ga4PollInterval = setInterval(() => {
246
- const clientId2 = getGA4ClientId();
247
- if (clientId2) {
248
- this.setParams({ ga4ClientId: clientId2 });
249
- this.stopGA4CookiePolling();
218
+ window.gtag("get", this.config.ga4MeasurementId, "client_id", (clientId) => {
219
+ if (clientId) {
220
+ this.setParams({ ga4ClientId: clientId });
250
221
  }
251
- }, 500);
252
- this.ga4PollTimeout = setTimeout(() => {
253
- this.stopGA4CookiePolling();
254
- }, 1e4);
255
- }
256
- stopGA4CookiePolling() {
257
- if (this.ga4PollInterval) {
258
- clearInterval(this.ga4PollInterval);
259
- this.ga4PollInterval = null;
260
- }
261
- if (this.ga4PollTimeout) {
262
- clearTimeout(this.ga4PollTimeout);
263
- this.ga4PollTimeout = null;
264
- }
222
+ });
265
223
  }
266
224
  async fetchSession() {
267
225
  const locationId = this.getLocationId();
@@ -397,7 +355,7 @@ function getPreloadSnippet(config) {
397
355
  const script = `(function(){
398
356
  var u=new URLSearchParams(location.search);
399
357
  var loc=u.get('loc_physical_ms');
400
- var ap=['gclid','gbraid','wbraid','msclkid','fbclid'];
358
+ var ap=['gclid','gbraid','wbraid','msclkid','fbclid','gad_campaignid','gad_source'];
401
359
  var p={};
402
360
  for(var i=0;i<ap.length;i++){var v=u.get(ap[i]);if(v)p[ap[i]]=v}
403
361
  var key='${cacheKey}';
@@ -422,6 +380,5 @@ window.__cfTracking=fetch(url,{credentials:'omit'}).then(function(r){return r.js
422
380
  // Annotate the CommonJS export names for ESM import in node:
423
381
  0 && (module.exports = {
424
382
  CallForge,
425
- getGA4ClientId,
426
383
  getPreloadSnippet
427
384
  });
package/dist/index.mjs CHANGED
@@ -105,19 +105,12 @@ var TrackingCache = class {
105
105
 
106
106
  // src/client.ts
107
107
  var DEFAULT_ENDPOINT = "https://tracking.callforge.io";
108
- function getGA4ClientId() {
109
- if (typeof document === "undefined") return null;
110
- const match = document.cookie.match(/_ga=GA\d+\.\d+\.(.+?)(?:;|$)/);
111
- return match ? match[1] : null;
112
- }
113
108
  var FETCH_TIMEOUT_MS = 1e4;
114
- var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid"];
109
+ var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid", "gad_campaignid", "gad_source"];
115
110
  var CallForge = class _CallForge {
116
111
  constructor(config) {
117
112
  this.sessionPromise = null;
118
113
  this.customParams = {};
119
- this.ga4PollInterval = null;
120
- this.ga4PollTimeout = null;
121
114
  this.sessionId = null;
122
115
  this.sessionCreated = false;
123
116
  this.config = {
@@ -126,7 +119,7 @@ var CallForge = class _CallForge {
126
119
  ga4MeasurementId: config.ga4MeasurementId
127
120
  };
128
121
  this.cache = new TrackingCache(config.categoryId);
129
- this.startGA4ClientIdCapture();
122
+ this.captureGA4ClientId();
130
123
  }
131
124
  /**
132
125
  * Initialize the CallForge tracking client.
@@ -188,55 +181,21 @@ var CallForge = class _CallForge {
188
181
  }
189
182
  }
190
183
  /**
191
- * Start capturing the GA4 client ID.
192
- * If ga4MeasurementId is configured, uses gtag('get') callback.
193
- * Otherwise falls back to polling the _ga cookie.
184
+ * Capture the GA4 client ID using gtag callback.
185
+ * Only runs if ga4MeasurementId is configured.
194
186
  */
195
- startGA4ClientIdCapture() {
196
- if (this.ga4PollInterval !== null || this.ga4PollTimeout !== null) {
197
- return;
198
- }
199
- if (this.config.ga4MeasurementId && typeof window !== "undefined" && window.gtag) {
200
- window.gtag("get", this.config.ga4MeasurementId, "client_id", (clientId) => {
201
- if (clientId) {
202
- this.setParams({ ga4ClientId: clientId });
203
- }
204
- });
187
+ captureGA4ClientId() {
188
+ if (!this.config.ga4MeasurementId) {
205
189
  return;
206
190
  }
207
- this.startGA4CookiePolling();
208
- }
209
- /**
210
- * Start polling for the GA4 _ga cookie.
211
- * If found immediately, calls setParams right away.
212
- * Otherwise polls every 500ms for up to 10 seconds.
213
- */
214
- startGA4CookiePolling() {
215
- const clientId = getGA4ClientId();
216
- if (clientId) {
217
- this.setParams({ ga4ClientId: clientId });
191
+ if (typeof window === "undefined" || !window.gtag) {
218
192
  return;
219
193
  }
220
- this.ga4PollInterval = setInterval(() => {
221
- const clientId2 = getGA4ClientId();
222
- if (clientId2) {
223
- this.setParams({ ga4ClientId: clientId2 });
224
- this.stopGA4CookiePolling();
194
+ window.gtag("get", this.config.ga4MeasurementId, "client_id", (clientId) => {
195
+ if (clientId) {
196
+ this.setParams({ ga4ClientId: clientId });
225
197
  }
226
- }, 500);
227
- this.ga4PollTimeout = setTimeout(() => {
228
- this.stopGA4CookiePolling();
229
- }, 1e4);
230
- }
231
- stopGA4CookiePolling() {
232
- if (this.ga4PollInterval) {
233
- clearInterval(this.ga4PollInterval);
234
- this.ga4PollInterval = null;
235
- }
236
- if (this.ga4PollTimeout) {
237
- clearTimeout(this.ga4PollTimeout);
238
- this.ga4PollTimeout = null;
239
- }
198
+ });
240
199
  }
241
200
  async fetchSession() {
242
201
  const locationId = this.getLocationId();
@@ -372,7 +331,7 @@ function getPreloadSnippet(config) {
372
331
  const script = `(function(){
373
332
  var u=new URLSearchParams(location.search);
374
333
  var loc=u.get('loc_physical_ms');
375
- var ap=['gclid','gbraid','wbraid','msclkid','fbclid'];
334
+ var ap=['gclid','gbraid','wbraid','msclkid','fbclid','gad_campaignid','gad_source'];
376
335
  var p={};
377
336
  for(var i=0;i<ap.length;i++){var v=u.get(ap[i]);if(v)p[ap[i]]=v}
378
337
  var key='${cacheKey}';
@@ -396,6 +355,5 @@ window.__cfTracking=fetch(url,{credentials:'omit'}).then(function(r){return r.js
396
355
  }
397
356
  export {
398
357
  CallForge,
399
- getGA4ClientId,
400
358
  getPreloadSnippet
401
359
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@callforge/tracking-client",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",