@callforge/tracking-client 0.3.1 → 0.4.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/README.md +31 -46
- package/dist/index.d.mts +8 -15
- package/dist/index.d.ts +8 -15
- package/dist/index.js +12 -38
- package/dist/index.mjs +12 -37
- package/package.json +1 -1
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.
|
|
5
|
+
**v0.4.1** - Simplified GA4 capture: uses gtag callback when `ga4MeasurementId` configured, no polling fallback.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -53,19 +53,26 @@ client.onReady((session) => {
|
|
|
53
53
|
});
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
### 3. GA4 Integration
|
|
56
|
+
### 3. GA4 Integration
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
To enable GA4 call event tracking, provide your GA4 Measurement ID:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
const client = CallForge.init({
|
|
62
|
+
categoryId: 'your-category-id',
|
|
63
|
+
ga4MeasurementId: 'G-XXXXXXXXXX', // Required for GA4 integration
|
|
64
|
+
});
|
|
65
|
+
```
|
|
59
66
|
|
|
60
67
|
**Requirements:**
|
|
61
|
-
1. Google Analytics 4 must be installed on your site
|
|
62
|
-
2.
|
|
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)
|
|
63
71
|
|
|
64
72
|
**How it works:**
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
- If session already exists, uses PATCH to update with the GA4 client ID
|
|
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
|
|
69
76
|
|
|
70
77
|
**Manual override:** If you need to pass a custom GA4 client ID:
|
|
71
78
|
|
|
@@ -75,14 +82,6 @@ client.setParams({
|
|
|
75
82
|
});
|
|
76
83
|
```
|
|
77
84
|
|
|
78
|
-
**Extract GA4 client ID yourself:**
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
import { getGA4ClientId } from '@callforge/tracking-client';
|
|
82
|
-
|
|
83
|
-
const clientId = getGA4ClientId(); // "1234567890.1234567890" or null
|
|
84
|
-
```
|
|
85
|
-
|
|
86
85
|
### 4. Track conversion parameters (optional)
|
|
87
86
|
|
|
88
87
|
The client automatically captures ad platform click IDs from the URL:
|
|
@@ -114,8 +113,10 @@ Initialize the tracking client.
|
|
|
114
113
|
|
|
115
114
|
```typescript
|
|
116
115
|
interface CallForgeConfig {
|
|
117
|
-
categoryId: string;
|
|
118
|
-
endpoint?: string;
|
|
116
|
+
categoryId: string; // Required - which number pool to use
|
|
117
|
+
endpoint?: string; // Optional - defaults to 'https://tracking.callforge.io'
|
|
118
|
+
ga4MeasurementId?: string; // Optional - GA4 Measurement ID (e.g., "G-XXXXXXXXXX")
|
|
119
|
+
// Enables gtag callback instead of cookie polling
|
|
119
120
|
}
|
|
120
121
|
```
|
|
121
122
|
|
|
@@ -182,35 +183,21 @@ const html = getPreloadSnippet({
|
|
|
182
183
|
});
|
|
183
184
|
```
|
|
184
185
|
|
|
185
|
-
### `getGA4ClientId()`
|
|
186
|
-
|
|
187
|
-
Extract the GA4 client ID from the `_ga` cookie.
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
import { getGA4ClientId } from '@callforge/tracking-client';
|
|
191
|
-
|
|
192
|
-
const clientId = getGA4ClientId();
|
|
193
|
-
// Returns: "1234567890.1234567890" or null if cookie not found
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
**Cookie format:** `GA1.1.1234567890.1234567890`
|
|
197
|
-
|
|
198
|
-
The client ID is the last two dot-separated segments (timestamp.random).
|
|
199
|
-
|
|
200
186
|
## Tracking Parameters
|
|
201
187
|
|
|
202
188
|
### Auto-Capture
|
|
203
189
|
|
|
204
|
-
The client automatically extracts these parameters:
|
|
190
|
+
The client automatically extracts these parameters from the URL:
|
|
205
191
|
|
|
206
|
-
| Parameter | Source |
|
|
207
|
-
|
|
208
|
-
| `gclid` | Google Ads Click ID |
|
|
209
|
-
| `gbraid` | Google app-to-web (iOS 14+) |
|
|
210
|
-
| `wbraid` | Google web-to-app |
|
|
211
|
-
| `msclkid` | Microsoft/Bing Ads |
|
|
212
|
-
| `fbclid` | Facebook/Meta Ads |
|
|
213
|
-
|
|
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.
|
|
214
201
|
|
|
215
202
|
### Persistence
|
|
216
203
|
|
|
@@ -262,8 +249,6 @@ import type {
|
|
|
262
249
|
TrackingParams,
|
|
263
250
|
ReadyCallback,
|
|
264
251
|
} from '@callforge/tracking-client';
|
|
265
|
-
|
|
266
|
-
import { getGA4ClientId } from '@callforge/tracking-client';
|
|
267
252
|
```
|
|
268
253
|
|
|
269
254
|
### TrackingParams
|
|
@@ -275,7 +260,7 @@ interface TrackingParams {
|
|
|
275
260
|
wbraid?: string; // Google web-to-app
|
|
276
261
|
msclkid?: string; // Microsoft/Bing Ads
|
|
277
262
|
fbclid?: string; // Facebook/Meta Ads
|
|
278
|
-
ga4ClientId?: string; // Google Analytics 4 Client ID (auto-captured
|
|
263
|
+
ga4ClientId?: string; // Google Analytics 4 Client ID (auto-captured via gtag callback)
|
|
279
264
|
[key: string]: string | undefined; // Custom params
|
|
280
265
|
}
|
|
281
266
|
```
|
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,27 +66,20 @@ 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
|
|
|
75
|
-
/**
|
|
76
|
-
* Extract GA4 client_id from the _ga cookie.
|
|
77
|
-
* Cookie format: GA1.1.1234567890.1234567890
|
|
78
|
-
* Client ID is the last two segments: 1234567890.1234567890
|
|
79
|
-
*/
|
|
80
|
-
declare function getGA4ClientId(): string | null;
|
|
81
78
|
declare class CallForge {
|
|
82
79
|
private readonly config;
|
|
83
80
|
private readonly cache;
|
|
84
81
|
private sessionPromise;
|
|
85
82
|
private customParams;
|
|
86
|
-
private ga4PollInterval;
|
|
87
|
-
private ga4PollTimeout;
|
|
88
83
|
private sessionId;
|
|
89
84
|
private sessionCreated;
|
|
90
85
|
private constructor();
|
|
@@ -114,12 +109,10 @@ declare class CallForge {
|
|
|
114
109
|
getQueuedParams(): TrackingParams;
|
|
115
110
|
private patchSession;
|
|
116
111
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* 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.
|
|
120
114
|
*/
|
|
121
|
-
|
|
122
|
-
private stopGA4CookiePolling;
|
|
115
|
+
private captureGA4ClientId;
|
|
123
116
|
private fetchSession;
|
|
124
117
|
private getLocationId;
|
|
125
118
|
private getAutoParams;
|
|
@@ -147,4 +140,4 @@ declare class CallForge {
|
|
|
147
140
|
*/
|
|
148
141
|
declare function getPreloadSnippet(config: CallForgeConfig): string;
|
|
149
142
|
|
|
150
|
-
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession,
|
|
143
|
+
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getPreloadSnippet };
|
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,27 +66,20 @@ 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
|
|
|
75
|
-
/**
|
|
76
|
-
* Extract GA4 client_id from the _ga cookie.
|
|
77
|
-
* Cookie format: GA1.1.1234567890.1234567890
|
|
78
|
-
* Client ID is the last two segments: 1234567890.1234567890
|
|
79
|
-
*/
|
|
80
|
-
declare function getGA4ClientId(): string | null;
|
|
81
78
|
declare class CallForge {
|
|
82
79
|
private readonly config;
|
|
83
80
|
private readonly cache;
|
|
84
81
|
private sessionPromise;
|
|
85
82
|
private customParams;
|
|
86
|
-
private ga4PollInterval;
|
|
87
|
-
private ga4PollTimeout;
|
|
88
83
|
private sessionId;
|
|
89
84
|
private sessionCreated;
|
|
90
85
|
private constructor();
|
|
@@ -114,12 +109,10 @@ declare class CallForge {
|
|
|
114
109
|
getQueuedParams(): TrackingParams;
|
|
115
110
|
private patchSession;
|
|
116
111
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* 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.
|
|
120
114
|
*/
|
|
121
|
-
|
|
122
|
-
private stopGA4CookiePolling;
|
|
115
|
+
private captureGA4ClientId;
|
|
123
116
|
private fetchSession;
|
|
124
117
|
private getLocationId;
|
|
125
118
|
private getAutoParams;
|
|
@@ -147,4 +140,4 @@ declare class CallForge {
|
|
|
147
140
|
*/
|
|
148
141
|
declare function getPreloadSnippet(config: CallForgeConfig): string;
|
|
149
142
|
|
|
150
|
-
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession,
|
|
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,27 +129,21 @@ 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
133
|
var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid"];
|
|
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 = {
|
|
149
141
|
categoryId: config.categoryId,
|
|
150
|
-
endpoint: config.endpoint || DEFAULT_ENDPOINT
|
|
142
|
+
endpoint: config.endpoint || DEFAULT_ENDPOINT,
|
|
143
|
+
ga4MeasurementId: config.ga4MeasurementId
|
|
151
144
|
};
|
|
152
145
|
this.cache = new TrackingCache(config.categoryId);
|
|
153
|
-
this.
|
|
146
|
+
this.captureGA4ClientId();
|
|
154
147
|
}
|
|
155
148
|
/**
|
|
156
149
|
* Initialize the CallForge tracking client.
|
|
@@ -212,39 +205,21 @@ var CallForge = class _CallForge {
|
|
|
212
205
|
}
|
|
213
206
|
}
|
|
214
207
|
/**
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
* Otherwise polls every 500ms for up to 10 seconds.
|
|
208
|
+
* Capture the GA4 client ID using gtag callback.
|
|
209
|
+
* Only runs if ga4MeasurementId is configured.
|
|
218
210
|
*/
|
|
219
|
-
|
|
220
|
-
if (this.
|
|
211
|
+
captureGA4ClientId() {
|
|
212
|
+
if (!this.config.ga4MeasurementId) {
|
|
221
213
|
return;
|
|
222
214
|
}
|
|
223
|
-
|
|
224
|
-
if (clientId) {
|
|
225
|
-
this.setParams({ ga4ClientId: clientId });
|
|
215
|
+
if (typeof window === "undefined" || !window.gtag) {
|
|
226
216
|
return;
|
|
227
217
|
}
|
|
228
|
-
this.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
this.setParams({ ga4ClientId: clientId2 });
|
|
232
|
-
this.stopGA4CookiePolling();
|
|
218
|
+
window.gtag("get", this.config.ga4MeasurementId, "client_id", (clientId) => {
|
|
219
|
+
if (clientId) {
|
|
220
|
+
this.setParams({ ga4ClientId: clientId });
|
|
233
221
|
}
|
|
234
|
-
}
|
|
235
|
-
this.ga4PollTimeout = setTimeout(() => {
|
|
236
|
-
this.stopGA4CookiePolling();
|
|
237
|
-
}, 1e4);
|
|
238
|
-
}
|
|
239
|
-
stopGA4CookiePolling() {
|
|
240
|
-
if (this.ga4PollInterval) {
|
|
241
|
-
clearInterval(this.ga4PollInterval);
|
|
242
|
-
this.ga4PollInterval = null;
|
|
243
|
-
}
|
|
244
|
-
if (this.ga4PollTimeout) {
|
|
245
|
-
clearTimeout(this.ga4PollTimeout);
|
|
246
|
-
this.ga4PollTimeout = null;
|
|
247
|
-
}
|
|
222
|
+
});
|
|
248
223
|
}
|
|
249
224
|
async fetchSession() {
|
|
250
225
|
const locationId = this.getLocationId();
|
|
@@ -405,6 +380,5 @@ window.__cfTracking=fetch(url,{credentials:'omit'}).then(function(r){return r.js
|
|
|
405
380
|
// Annotate the CommonJS export names for ESM import in node:
|
|
406
381
|
0 && (module.exports = {
|
|
407
382
|
CallForge,
|
|
408
|
-
getGA4ClientId,
|
|
409
383
|
getPreloadSnippet
|
|
410
384
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -105,27 +105,21 @@ 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
109
|
var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid"];
|
|
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 = {
|
|
124
117
|
categoryId: config.categoryId,
|
|
125
|
-
endpoint: config.endpoint || DEFAULT_ENDPOINT
|
|
118
|
+
endpoint: config.endpoint || DEFAULT_ENDPOINT,
|
|
119
|
+
ga4MeasurementId: config.ga4MeasurementId
|
|
126
120
|
};
|
|
127
121
|
this.cache = new TrackingCache(config.categoryId);
|
|
128
|
-
this.
|
|
122
|
+
this.captureGA4ClientId();
|
|
129
123
|
}
|
|
130
124
|
/**
|
|
131
125
|
* Initialize the CallForge tracking client.
|
|
@@ -187,39 +181,21 @@ var CallForge = class _CallForge {
|
|
|
187
181
|
}
|
|
188
182
|
}
|
|
189
183
|
/**
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* Otherwise polls every 500ms for up to 10 seconds.
|
|
184
|
+
* Capture the GA4 client ID using gtag callback.
|
|
185
|
+
* Only runs if ga4MeasurementId is configured.
|
|
193
186
|
*/
|
|
194
|
-
|
|
195
|
-
if (this.
|
|
187
|
+
captureGA4ClientId() {
|
|
188
|
+
if (!this.config.ga4MeasurementId) {
|
|
196
189
|
return;
|
|
197
190
|
}
|
|
198
|
-
|
|
199
|
-
if (clientId) {
|
|
200
|
-
this.setParams({ ga4ClientId: clientId });
|
|
191
|
+
if (typeof window === "undefined" || !window.gtag) {
|
|
201
192
|
return;
|
|
202
193
|
}
|
|
203
|
-
this.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
this.setParams({ ga4ClientId: clientId2 });
|
|
207
|
-
this.stopGA4CookiePolling();
|
|
194
|
+
window.gtag("get", this.config.ga4MeasurementId, "client_id", (clientId) => {
|
|
195
|
+
if (clientId) {
|
|
196
|
+
this.setParams({ ga4ClientId: clientId });
|
|
208
197
|
}
|
|
209
|
-
}
|
|
210
|
-
this.ga4PollTimeout = setTimeout(() => {
|
|
211
|
-
this.stopGA4CookiePolling();
|
|
212
|
-
}, 1e4);
|
|
213
|
-
}
|
|
214
|
-
stopGA4CookiePolling() {
|
|
215
|
-
if (this.ga4PollInterval) {
|
|
216
|
-
clearInterval(this.ga4PollInterval);
|
|
217
|
-
this.ga4PollInterval = null;
|
|
218
|
-
}
|
|
219
|
-
if (this.ga4PollTimeout) {
|
|
220
|
-
clearTimeout(this.ga4PollTimeout);
|
|
221
|
-
this.ga4PollTimeout = null;
|
|
222
|
-
}
|
|
198
|
+
});
|
|
223
199
|
}
|
|
224
200
|
async fetchSession() {
|
|
225
201
|
const locationId = this.getLocationId();
|
|
@@ -379,6 +355,5 @@ window.__cfTracking=fetch(url,{credentials:'omit'}).then(function(r){return r.js
|
|
|
379
355
|
}
|
|
380
356
|
export {
|
|
381
357
|
CallForge,
|
|
382
|
-
getGA4ClientId,
|
|
383
358
|
getPreloadSnippet
|
|
384
359
|
};
|