@callforge/tracking-client 0.3.1 → 0.4.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/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.3.0** - Added automatic GA4 integration for sending call events to Google Analytics 4.
5
+ **v0.4.0** - Added `ga4MeasurementId` config option for cleaner gtag callback instead of cookie polling.
6
6
 
7
7
  ## Installation
8
8
 
@@ -55,17 +55,31 @@ client.onReady((session) => {
55
55
 
56
56
  ### 3. GA4 Integration (automatic)
57
57
 
58
- The client automatically captures the GA4 client ID from the `_ga` cookie 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.
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
59
 
60
60
  **Requirements:**
61
61
  1. Google Analytics 4 must be installed on your site
62
62
  2. Configure GA4 credentials in CallForge dashboard (Categories → Edit → GA4 tab)
63
63
 
64
+ **Recommended: Provide Measurement ID for callback-based capture:**
65
+
66
+ ```typescript
67
+ const client = CallForge.init({
68
+ categoryId: 'your-category-id',
69
+ ga4MeasurementId: 'G-XXXXXXXXXX', // Enables gtag('get') callback
70
+ });
71
+ ```
72
+
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.
74
+
64
75
  **How it works:**
65
- - On initialization, the client checks for the `_ga` cookie
66
- - If not found immediately (GA4 script may load async), polls every 500ms for up to 10 seconds
67
- - Once found, extracts the client ID and sends it to CallForge via `setParams()`
68
- - If session already exists, uses PATCH to update with the GA4 client ID
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
69
83
 
70
84
  **Manual override:** If you need to pass a custom GA4 client ID:
71
85
 
@@ -114,8 +128,10 @@ Initialize the tracking client.
114
128
 
115
129
  ```typescript
116
130
  interface CallForgeConfig {
117
- categoryId: string; // Required - which number pool to use
118
- endpoint?: string; // Optional - defaults to 'https://tracking.callforge.io'
131
+ categoryId: string; // Required - which number pool to use
132
+ endpoint?: string; // Optional - defaults to 'https://tracking.callforge.io'
133
+ ga4MeasurementId?: string; // Optional - GA4 Measurement ID (e.g., "G-XXXXXXXXXX")
134
+ // Enables gtag callback instead of cookie polling
119
135
  }
120
136
  ```
121
137
 
package/dist/index.d.mts CHANGED
@@ -6,6 +6,8 @@ interface CallForgeConfig {
6
6
  categoryId: string;
7
7
  /** Optional - API endpoint. Defaults to 'https://tracking.callforge.io' */
8
8
  endpoint?: string;
9
+ /** Optional - GA4 Measurement ID (e.g., "G-XXXXXXXXXX"). Enables gtag callback instead of cookie polling. */
10
+ ga4MeasurementId?: string;
9
11
  }
10
12
  /**
11
13
  * Location data returned by the tracking API.
@@ -64,11 +66,12 @@ interface ApiResponse {
64
66
  */
65
67
  type ReadyCallback = (session: TrackingSession) => void;
66
68
  /**
67
- * Global window extension for preload promise.
69
+ * Global window extension for preload promise and gtag.
68
70
  */
69
71
  declare global {
70
72
  interface Window {
71
73
  __cfTracking?: Promise<ApiResponse>;
74
+ gtag?: (command: 'get', targetId: string, fieldName: string, callback: (value: string) => void) => void;
72
75
  }
73
76
  }
74
77
 
@@ -113,12 +116,18 @@ declare class CallForge {
113
116
  */
114
117
  getQueuedParams(): TrackingParams;
115
118
  private patchSession;
119
+ /**
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;
116
125
  /**
117
126
  * Start polling for the GA4 _ga cookie.
118
127
  * If found immediately, calls setParams right away.
119
128
  * Otherwise polls every 500ms for up to 10 seconds.
120
129
  */
121
- startGA4CookiePolling(): void;
130
+ private startGA4CookiePolling;
122
131
  private stopGA4CookiePolling;
123
132
  private fetchSession;
124
133
  private getLocationId;
package/dist/index.d.ts CHANGED
@@ -6,6 +6,8 @@ interface CallForgeConfig {
6
6
  categoryId: string;
7
7
  /** Optional - API endpoint. Defaults to 'https://tracking.callforge.io' */
8
8
  endpoint?: string;
9
+ /** Optional - GA4 Measurement ID (e.g., "G-XXXXXXXXXX"). Enables gtag callback instead of cookie polling. */
10
+ ga4MeasurementId?: string;
9
11
  }
10
12
  /**
11
13
  * Location data returned by the tracking API.
@@ -64,11 +66,12 @@ interface ApiResponse {
64
66
  */
65
67
  type ReadyCallback = (session: TrackingSession) => void;
66
68
  /**
67
- * Global window extension for preload promise.
69
+ * Global window extension for preload promise and gtag.
68
70
  */
69
71
  declare global {
70
72
  interface Window {
71
73
  __cfTracking?: Promise<ApiResponse>;
74
+ gtag?: (command: 'get', targetId: string, fieldName: string, callback: (value: string) => void) => void;
72
75
  }
73
76
  }
74
77
 
@@ -113,12 +116,18 @@ declare class CallForge {
113
116
  */
114
117
  getQueuedParams(): TrackingParams;
115
118
  private patchSession;
119
+ /**
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;
116
125
  /**
117
126
  * Start polling for the GA4 _ga cookie.
118
127
  * If found immediately, calls setParams right away.
119
128
  * Otherwise polls every 500ms for up to 10 seconds.
120
129
  */
121
- startGA4CookiePolling(): void;
130
+ private startGA4CookiePolling;
122
131
  private stopGA4CookiePolling;
123
132
  private fetchSession;
124
133
  private getLocationId;
package/dist/index.js CHANGED
@@ -147,10 +147,11 @@ var CallForge = class _CallForge {
147
147
  this.sessionCreated = false;
148
148
  this.config = {
149
149
  categoryId: config.categoryId,
150
- endpoint: config.endpoint || DEFAULT_ENDPOINT
150
+ endpoint: config.endpoint || DEFAULT_ENDPOINT,
151
+ ga4MeasurementId: config.ga4MeasurementId
151
152
  };
152
153
  this.cache = new TrackingCache(config.categoryId);
153
- this.startGA4CookiePolling();
154
+ this.startGA4ClientIdCapture();
154
155
  }
155
156
  /**
156
157
  * Initialize the CallForge tracking client.
@@ -211,15 +212,31 @@ var CallForge = class _CallForge {
211
212
  console.warn("[CallForge] Failed to patch session:", error);
212
213
  }
213
214
  }
215
+ /**
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.
219
+ */
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
+ });
230
+ return;
231
+ }
232
+ this.startGA4CookiePolling();
233
+ }
214
234
  /**
215
235
  * Start polling for the GA4 _ga cookie.
216
236
  * If found immediately, calls setParams right away.
217
237
  * Otherwise polls every 500ms for up to 10 seconds.
218
238
  */
219
239
  startGA4CookiePolling() {
220
- if (this.ga4PollInterval !== null || this.ga4PollTimeout !== null) {
221
- return;
222
- }
223
240
  const clientId = getGA4ClientId();
224
241
  if (clientId) {
225
242
  this.setParams({ ga4ClientId: clientId });
package/dist/index.mjs CHANGED
@@ -122,10 +122,11 @@ var CallForge = class _CallForge {
122
122
  this.sessionCreated = false;
123
123
  this.config = {
124
124
  categoryId: config.categoryId,
125
- endpoint: config.endpoint || DEFAULT_ENDPOINT
125
+ endpoint: config.endpoint || DEFAULT_ENDPOINT,
126
+ ga4MeasurementId: config.ga4MeasurementId
126
127
  };
127
128
  this.cache = new TrackingCache(config.categoryId);
128
- this.startGA4CookiePolling();
129
+ this.startGA4ClientIdCapture();
129
130
  }
130
131
  /**
131
132
  * Initialize the CallForge tracking client.
@@ -186,15 +187,31 @@ var CallForge = class _CallForge {
186
187
  console.warn("[CallForge] Failed to patch session:", error);
187
188
  }
188
189
  }
190
+ /**
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.
194
+ */
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
+ });
205
+ return;
206
+ }
207
+ this.startGA4CookiePolling();
208
+ }
189
209
  /**
190
210
  * Start polling for the GA4 _ga cookie.
191
211
  * If found immediately, calls setParams right away.
192
212
  * Otherwise polls every 500ms for up to 10 seconds.
193
213
  */
194
214
  startGA4CookiePolling() {
195
- if (this.ga4PollInterval !== null || this.ga4PollTimeout !== null) {
196
- return;
197
- }
198
215
  const clientId = getGA4ClientId();
199
216
  if (clientId) {
200
217
  this.setParams({ ga4ClientId: clientId });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@callforge/tracking-client",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",