@callforge/tracking-client 0.2.0 → 0.3.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 +94 -14
- package/dist/index.d.mts +26 -3
- package/dist/index.d.ts +26 -3
- package/dist/index.js +84 -4
- package/dist/index.mjs +83 -4
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
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.
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```bash
|
|
@@ -51,7 +53,37 @@ client.onReady((session) => {
|
|
|
51
53
|
});
|
|
52
54
|
```
|
|
53
55
|
|
|
54
|
-
### 3.
|
|
56
|
+
### 3. GA4 Integration (automatic)
|
|
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.
|
|
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
|
+
**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
|
|
69
|
+
|
|
70
|
+
**Manual override:** If you need to pass a custom GA4 client ID:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
client.setParams({
|
|
74
|
+
ga4ClientId: '1234567890.1234567890',
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
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
|
+
### 4. Track conversion parameters (optional)
|
|
55
87
|
|
|
56
88
|
The client automatically captures ad platform click IDs from the URL:
|
|
57
89
|
|
|
@@ -150,19 +182,35 @@ const html = getPreloadSnippet({
|
|
|
150
182
|
});
|
|
151
183
|
```
|
|
152
184
|
|
|
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
|
+
|
|
153
200
|
## Tracking Parameters
|
|
154
201
|
|
|
155
202
|
### Auto-Capture
|
|
156
203
|
|
|
157
|
-
The client automatically extracts these parameters
|
|
204
|
+
The client automatically extracts these parameters:
|
|
158
205
|
|
|
159
|
-
| Parameter | Source |
|
|
160
|
-
|
|
161
|
-
| `gclid` | Google Ads Click ID |
|
|
162
|
-
| `gbraid` | Google app-to-web (iOS 14+) |
|
|
163
|
-
| `wbraid` | Google web-to-app |
|
|
164
|
-
| `msclkid` | Microsoft/Bing Ads |
|
|
165
|
-
| `fbclid` | Facebook/Meta Ads |
|
|
206
|
+
| Parameter | Source | Capture Method |
|
|
207
|
+
|-----------|--------|----------------|
|
|
208
|
+
| `gclid` | Google Ads Click ID | URL query param |
|
|
209
|
+
| `gbraid` | Google app-to-web (iOS 14+) | URL query param |
|
|
210
|
+
| `wbraid` | Google web-to-app | URL query param |
|
|
211
|
+
| `msclkid` | Microsoft/Bing Ads | URL query param |
|
|
212
|
+
| `fbclid` | Facebook/Meta Ads | URL query param |
|
|
213
|
+
| `ga4ClientId` | Google Analytics 4 | `_ga` cookie (polled) |
|
|
166
214
|
|
|
167
215
|
### Persistence
|
|
168
216
|
|
|
@@ -214,21 +262,53 @@ import type {
|
|
|
214
262
|
TrackingParams,
|
|
215
263
|
ReadyCallback,
|
|
216
264
|
} from '@callforge/tracking-client';
|
|
265
|
+
|
|
266
|
+
import { getGA4ClientId } from '@callforge/tracking-client';
|
|
217
267
|
```
|
|
218
268
|
|
|
219
269
|
### TrackingParams
|
|
220
270
|
|
|
221
271
|
```typescript
|
|
222
272
|
interface TrackingParams {
|
|
223
|
-
gclid?: string;
|
|
224
|
-
gbraid?: string;
|
|
225
|
-
wbraid?: string;
|
|
226
|
-
msclkid?: string;
|
|
227
|
-
fbclid?: string;
|
|
273
|
+
gclid?: string; // Google Ads Click ID
|
|
274
|
+
gbraid?: string; // Google app-to-web (iOS 14+)
|
|
275
|
+
wbraid?: string; // Google web-to-app
|
|
276
|
+
msclkid?: string; // Microsoft/Bing Ads
|
|
277
|
+
fbclid?: string; // Facebook/Meta Ads
|
|
278
|
+
ga4ClientId?: string; // Google Analytics 4 Client ID (auto-captured from _ga cookie)
|
|
228
279
|
[key: string]: string | undefined; // Custom params
|
|
229
280
|
}
|
|
230
281
|
```
|
|
231
282
|
|
|
283
|
+
## GA4 Events
|
|
284
|
+
|
|
285
|
+
When GA4 is configured for a category, CallForge sends these events to Google Analytics 4 via the Measurement Protocol:
|
|
286
|
+
|
|
287
|
+
| Event Name | When Sent | Description |
|
|
288
|
+
|------------|-----------|-------------|
|
|
289
|
+
| `phone_call` | Call initiated | A phone call was placed to the tracking number |
|
|
290
|
+
| `call_conversion` | Call qualified | The call met conversion criteria (e.g., duration threshold) |
|
|
291
|
+
| `call_conversion_billable` | Call billable | The call was both qualified AND billable |
|
|
292
|
+
|
|
293
|
+
**Event Parameters:**
|
|
294
|
+
|
|
295
|
+
All events include:
|
|
296
|
+
- `session_id` - CallForge session ID
|
|
297
|
+
- `phone_number` - Tracking number dialed
|
|
298
|
+
- `category` - Category slug
|
|
299
|
+
|
|
300
|
+
`call_conversion` and `call_conversion_billable` also include:
|
|
301
|
+
- `call_duration` - Call duration in seconds
|
|
302
|
+
- `buyer` - Buyer the call was routed to (if applicable)
|
|
303
|
+
|
|
304
|
+
**Setup:**
|
|
305
|
+
1. In Google Analytics 4, go to Admin → Data Streams → your web stream
|
|
306
|
+
2. Copy the **Measurement ID** (e.g., `G-XXXXXXXXXX`)
|
|
307
|
+
3. Go to Admin → Data Streams → Measurement Protocol API secrets → Create
|
|
308
|
+
4. Copy the **API Secret**
|
|
309
|
+
5. In CallForge dashboard: Categories → Edit category → GA4 tab
|
|
310
|
+
6. Enable GA4, paste Measurement ID and API Secret, save
|
|
311
|
+
|
|
232
312
|
## Environment URLs
|
|
233
313
|
|
|
234
314
|
| Environment | Endpoint |
|
package/dist/index.d.mts
CHANGED
|
@@ -72,11 +72,21 @@ declare global {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
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;
|
|
75
81
|
declare class CallForge {
|
|
76
82
|
private readonly config;
|
|
77
83
|
private readonly cache;
|
|
78
84
|
private sessionPromise;
|
|
79
85
|
private customParams;
|
|
86
|
+
private ga4PollInterval;
|
|
87
|
+
private ga4PollTimeout;
|
|
88
|
+
private sessionId;
|
|
89
|
+
private sessionCreated;
|
|
80
90
|
private constructor();
|
|
81
91
|
/**
|
|
82
92
|
* Initialize the CallForge tracking client.
|
|
@@ -94,9 +104,22 @@ declare class CallForge {
|
|
|
94
104
|
onReady(callback: ReadyCallback): void;
|
|
95
105
|
/**
|
|
96
106
|
* Set custom tracking parameters.
|
|
97
|
-
*
|
|
107
|
+
* If session already exists, sends PATCH to update.
|
|
108
|
+
* Otherwise queues params for next session request.
|
|
109
|
+
*/
|
|
110
|
+
setParams(params: Record<string, string>): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Get the currently queued custom params.
|
|
113
|
+
*/
|
|
114
|
+
getQueuedParams(): TrackingParams;
|
|
115
|
+
private patchSession;
|
|
116
|
+
/**
|
|
117
|
+
* Start polling for the GA4 _ga cookie.
|
|
118
|
+
* If found immediately, calls setParams right away.
|
|
119
|
+
* Otherwise polls every 500ms for up to 10 seconds.
|
|
98
120
|
*/
|
|
99
|
-
|
|
121
|
+
startGA4CookiePolling(): void;
|
|
122
|
+
private stopGA4CookiePolling;
|
|
100
123
|
private fetchSession;
|
|
101
124
|
private getLocationId;
|
|
102
125
|
private getAutoParams;
|
|
@@ -124,4 +147,4 @@ declare class CallForge {
|
|
|
124
147
|
*/
|
|
125
148
|
declare function getPreloadSnippet(config: CallForgeConfig): string;
|
|
126
149
|
|
|
127
|
-
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getPreloadSnippet };
|
|
150
|
+
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getGA4ClientId, getPreloadSnippet };
|
package/dist/index.d.ts
CHANGED
|
@@ -72,11 +72,21 @@ declare global {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
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;
|
|
75
81
|
declare class CallForge {
|
|
76
82
|
private readonly config;
|
|
77
83
|
private readonly cache;
|
|
78
84
|
private sessionPromise;
|
|
79
85
|
private customParams;
|
|
86
|
+
private ga4PollInterval;
|
|
87
|
+
private ga4PollTimeout;
|
|
88
|
+
private sessionId;
|
|
89
|
+
private sessionCreated;
|
|
80
90
|
private constructor();
|
|
81
91
|
/**
|
|
82
92
|
* Initialize the CallForge tracking client.
|
|
@@ -94,9 +104,22 @@ declare class CallForge {
|
|
|
94
104
|
onReady(callback: ReadyCallback): void;
|
|
95
105
|
/**
|
|
96
106
|
* Set custom tracking parameters.
|
|
97
|
-
*
|
|
107
|
+
* If session already exists, sends PATCH to update.
|
|
108
|
+
* Otherwise queues params for next session request.
|
|
109
|
+
*/
|
|
110
|
+
setParams(params: Record<string, string>): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Get the currently queued custom params.
|
|
113
|
+
*/
|
|
114
|
+
getQueuedParams(): TrackingParams;
|
|
115
|
+
private patchSession;
|
|
116
|
+
/**
|
|
117
|
+
* Start polling for the GA4 _ga cookie.
|
|
118
|
+
* If found immediately, calls setParams right away.
|
|
119
|
+
* Otherwise polls every 500ms for up to 10 seconds.
|
|
98
120
|
*/
|
|
99
|
-
|
|
121
|
+
startGA4CookiePolling(): void;
|
|
122
|
+
private stopGA4CookiePolling;
|
|
100
123
|
private fetchSession;
|
|
101
124
|
private getLocationId;
|
|
102
125
|
private getAutoParams;
|
|
@@ -124,4 +147,4 @@ declare class CallForge {
|
|
|
124
147
|
*/
|
|
125
148
|
declare function getPreloadSnippet(config: CallForgeConfig): string;
|
|
126
149
|
|
|
127
|
-
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getPreloadSnippet };
|
|
150
|
+
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getGA4ClientId, getPreloadSnippet };
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ 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,
|
|
38
39
|
getPreloadSnippet: () => getPreloadSnippet
|
|
39
40
|
});
|
|
40
41
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -129,17 +130,27 @@ var TrackingCache = class {
|
|
|
129
130
|
|
|
130
131
|
// src/client.ts
|
|
131
132
|
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
|
+
}
|
|
132
138
|
var FETCH_TIMEOUT_MS = 1e4;
|
|
133
139
|
var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid"];
|
|
134
140
|
var CallForge = class _CallForge {
|
|
135
141
|
constructor(config) {
|
|
136
142
|
this.sessionPromise = null;
|
|
137
143
|
this.customParams = {};
|
|
144
|
+
this.ga4PollInterval = null;
|
|
145
|
+
this.ga4PollTimeout = null;
|
|
146
|
+
this.sessionId = null;
|
|
147
|
+
this.sessionCreated = false;
|
|
138
148
|
this.config = {
|
|
139
149
|
categoryId: config.categoryId,
|
|
140
150
|
endpoint: config.endpoint || DEFAULT_ENDPOINT
|
|
141
151
|
};
|
|
142
152
|
this.cache = new TrackingCache(config.categoryId);
|
|
153
|
+
this.startGA4CookiePolling();
|
|
143
154
|
}
|
|
144
155
|
/**
|
|
145
156
|
* Initialize the CallForge tracking client.
|
|
@@ -168,16 +179,80 @@ var CallForge = class _CallForge {
|
|
|
168
179
|
}
|
|
169
180
|
/**
|
|
170
181
|
* Set custom tracking parameters.
|
|
171
|
-
*
|
|
182
|
+
* If session already exists, sends PATCH to update.
|
|
183
|
+
* Otherwise queues params for next session request.
|
|
172
184
|
*/
|
|
173
|
-
setParams(params) {
|
|
185
|
+
async setParams(params) {
|
|
174
186
|
this.customParams = __spreadValues(__spreadValues({}, this.customParams), params);
|
|
187
|
+
if (this.sessionCreated && this.sessionId) {
|
|
188
|
+
await this.patchSession(params);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get the currently queued custom params.
|
|
193
|
+
*/
|
|
194
|
+
getQueuedParams() {
|
|
195
|
+
return __spreadValues({}, this.customParams);
|
|
196
|
+
}
|
|
197
|
+
async patchSession(params) {
|
|
198
|
+
try {
|
|
199
|
+
const response = await fetch(
|
|
200
|
+
`${this.config.endpoint}/v1/tracking/session/${this.sessionId}`,
|
|
201
|
+
{
|
|
202
|
+
method: "PATCH",
|
|
203
|
+
headers: { "Content-Type": "application/json" },
|
|
204
|
+
body: JSON.stringify(params)
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
console.warn("[CallForge] Failed to patch session:", response.status);
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.warn("[CallForge] Failed to patch session:", error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Start polling for the GA4 _ga cookie.
|
|
216
|
+
* If found immediately, calls setParams right away.
|
|
217
|
+
* Otherwise polls every 500ms for up to 10 seconds.
|
|
218
|
+
*/
|
|
219
|
+
startGA4CookiePolling() {
|
|
220
|
+
if (this.ga4PollInterval !== null || this.ga4PollTimeout !== null) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const clientId = getGA4ClientId();
|
|
224
|
+
if (clientId) {
|
|
225
|
+
this.setParams({ ga4ClientId: clientId });
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
this.ga4PollInterval = setInterval(() => {
|
|
229
|
+
const clientId2 = getGA4ClientId();
|
|
230
|
+
if (clientId2) {
|
|
231
|
+
this.setParams({ ga4ClientId: clientId2 });
|
|
232
|
+
this.stopGA4CookiePolling();
|
|
233
|
+
}
|
|
234
|
+
}, 500);
|
|
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
|
+
}
|
|
175
248
|
}
|
|
176
249
|
async fetchSession() {
|
|
177
250
|
const locationId = this.getLocationId();
|
|
178
251
|
if (locationId) {
|
|
179
252
|
const cached = this.cache.get(locationId);
|
|
180
253
|
if (cached) {
|
|
254
|
+
this.sessionId = cached.sessionId;
|
|
255
|
+
this.sessionCreated = true;
|
|
181
256
|
return this.formatSession(cached);
|
|
182
257
|
}
|
|
183
258
|
}
|
|
@@ -188,15 +263,19 @@ var CallForge = class _CallForge {
|
|
|
188
263
|
try {
|
|
189
264
|
const data2 = await window.__cfTracking;
|
|
190
265
|
this.saveToCache(locationId, data2, params);
|
|
266
|
+
this.sessionId = data2.sessionId;
|
|
267
|
+
this.sessionCreated = true;
|
|
191
268
|
return this.formatApiResponse(data2);
|
|
192
269
|
} catch (e) {
|
|
193
270
|
}
|
|
194
271
|
}
|
|
195
|
-
const
|
|
196
|
-
const data = await this.fetchFromApi(locationId,
|
|
272
|
+
const cachedSessionId = locationId ? this.cache.getSessionId(locationId) : null;
|
|
273
|
+
const data = await this.fetchFromApi(locationId, cachedSessionId, params);
|
|
197
274
|
if (locationId) {
|
|
198
275
|
this.saveToCache(locationId, data, params);
|
|
199
276
|
}
|
|
277
|
+
this.sessionId = data.sessionId;
|
|
278
|
+
this.sessionCreated = true;
|
|
200
279
|
return this.formatApiResponse(data);
|
|
201
280
|
}
|
|
202
281
|
getLocationId() {
|
|
@@ -326,5 +405,6 @@ window.__cfTracking=fetch(url,{credentials:'omit'}).then(function(r){return r.js
|
|
|
326
405
|
// Annotate the CommonJS export names for ESM import in node:
|
|
327
406
|
0 && (module.exports = {
|
|
328
407
|
CallForge,
|
|
408
|
+
getGA4ClientId,
|
|
329
409
|
getPreloadSnippet
|
|
330
410
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -105,17 +105,27 @@ 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
|
+
}
|
|
108
113
|
var FETCH_TIMEOUT_MS = 1e4;
|
|
109
114
|
var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid"];
|
|
110
115
|
var CallForge = class _CallForge {
|
|
111
116
|
constructor(config) {
|
|
112
117
|
this.sessionPromise = null;
|
|
113
118
|
this.customParams = {};
|
|
119
|
+
this.ga4PollInterval = null;
|
|
120
|
+
this.ga4PollTimeout = null;
|
|
121
|
+
this.sessionId = null;
|
|
122
|
+
this.sessionCreated = false;
|
|
114
123
|
this.config = {
|
|
115
124
|
categoryId: config.categoryId,
|
|
116
125
|
endpoint: config.endpoint || DEFAULT_ENDPOINT
|
|
117
126
|
};
|
|
118
127
|
this.cache = new TrackingCache(config.categoryId);
|
|
128
|
+
this.startGA4CookiePolling();
|
|
119
129
|
}
|
|
120
130
|
/**
|
|
121
131
|
* Initialize the CallForge tracking client.
|
|
@@ -144,16 +154,80 @@ var CallForge = class _CallForge {
|
|
|
144
154
|
}
|
|
145
155
|
/**
|
|
146
156
|
* Set custom tracking parameters.
|
|
147
|
-
*
|
|
157
|
+
* If session already exists, sends PATCH to update.
|
|
158
|
+
* Otherwise queues params for next session request.
|
|
148
159
|
*/
|
|
149
|
-
setParams(params) {
|
|
160
|
+
async setParams(params) {
|
|
150
161
|
this.customParams = __spreadValues(__spreadValues({}, this.customParams), params);
|
|
162
|
+
if (this.sessionCreated && this.sessionId) {
|
|
163
|
+
await this.patchSession(params);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get the currently queued custom params.
|
|
168
|
+
*/
|
|
169
|
+
getQueuedParams() {
|
|
170
|
+
return __spreadValues({}, this.customParams);
|
|
171
|
+
}
|
|
172
|
+
async patchSession(params) {
|
|
173
|
+
try {
|
|
174
|
+
const response = await fetch(
|
|
175
|
+
`${this.config.endpoint}/v1/tracking/session/${this.sessionId}`,
|
|
176
|
+
{
|
|
177
|
+
method: "PATCH",
|
|
178
|
+
headers: { "Content-Type": "application/json" },
|
|
179
|
+
body: JSON.stringify(params)
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
if (!response.ok) {
|
|
183
|
+
console.warn("[CallForge] Failed to patch session:", response.status);
|
|
184
|
+
}
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.warn("[CallForge] Failed to patch session:", error);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Start polling for the GA4 _ga cookie.
|
|
191
|
+
* If found immediately, calls setParams right away.
|
|
192
|
+
* Otherwise polls every 500ms for up to 10 seconds.
|
|
193
|
+
*/
|
|
194
|
+
startGA4CookiePolling() {
|
|
195
|
+
if (this.ga4PollInterval !== null || this.ga4PollTimeout !== null) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const clientId = getGA4ClientId();
|
|
199
|
+
if (clientId) {
|
|
200
|
+
this.setParams({ ga4ClientId: clientId });
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
this.ga4PollInterval = setInterval(() => {
|
|
204
|
+
const clientId2 = getGA4ClientId();
|
|
205
|
+
if (clientId2) {
|
|
206
|
+
this.setParams({ ga4ClientId: clientId2 });
|
|
207
|
+
this.stopGA4CookiePolling();
|
|
208
|
+
}
|
|
209
|
+
}, 500);
|
|
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
|
+
}
|
|
151
223
|
}
|
|
152
224
|
async fetchSession() {
|
|
153
225
|
const locationId = this.getLocationId();
|
|
154
226
|
if (locationId) {
|
|
155
227
|
const cached = this.cache.get(locationId);
|
|
156
228
|
if (cached) {
|
|
229
|
+
this.sessionId = cached.sessionId;
|
|
230
|
+
this.sessionCreated = true;
|
|
157
231
|
return this.formatSession(cached);
|
|
158
232
|
}
|
|
159
233
|
}
|
|
@@ -164,15 +238,19 @@ var CallForge = class _CallForge {
|
|
|
164
238
|
try {
|
|
165
239
|
const data2 = await window.__cfTracking;
|
|
166
240
|
this.saveToCache(locationId, data2, params);
|
|
241
|
+
this.sessionId = data2.sessionId;
|
|
242
|
+
this.sessionCreated = true;
|
|
167
243
|
return this.formatApiResponse(data2);
|
|
168
244
|
} catch (e) {
|
|
169
245
|
}
|
|
170
246
|
}
|
|
171
|
-
const
|
|
172
|
-
const data = await this.fetchFromApi(locationId,
|
|
247
|
+
const cachedSessionId = locationId ? this.cache.getSessionId(locationId) : null;
|
|
248
|
+
const data = await this.fetchFromApi(locationId, cachedSessionId, params);
|
|
173
249
|
if (locationId) {
|
|
174
250
|
this.saveToCache(locationId, data, params);
|
|
175
251
|
}
|
|
252
|
+
this.sessionId = data.sessionId;
|
|
253
|
+
this.sessionCreated = true;
|
|
176
254
|
return this.formatApiResponse(data);
|
|
177
255
|
}
|
|
178
256
|
getLocationId() {
|
|
@@ -301,5 +379,6 @@ window.__cfTracking=fetch(url,{credentials:'omit'}).then(function(r){return r.js
|
|
|
301
379
|
}
|
|
302
380
|
export {
|
|
303
381
|
CallForge,
|
|
382
|
+
getGA4ClientId,
|
|
304
383
|
getPreloadSnippet
|
|
305
384
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@callforge/tracking-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -14,17 +14,17 @@
|
|
|
14
14
|
"files": [
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
|
-
"devDependencies": {
|
|
18
|
-
"jsdom": "^27.4.0",
|
|
19
|
-
"tsup": "^8.0.0",
|
|
20
|
-
"typescript": "^5.3.0",
|
|
21
|
-
"vitest": "^1.6.0",
|
|
22
|
-
"@callforge/tsconfig": "0.0.0"
|
|
23
|
-
},
|
|
24
17
|
"scripts": {
|
|
25
18
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
26
19
|
"clean": "rm -rf dist",
|
|
27
20
|
"test": "vitest run",
|
|
28
21
|
"test:watch": "vitest"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@callforge/tsconfig": "workspace:*",
|
|
25
|
+
"jsdom": "^27.4.0",
|
|
26
|
+
"tsup": "^8.0.0",
|
|
27
|
+
"typescript": "^5.3.0",
|
|
28
|
+
"vitest": "^1.6.0"
|
|
29
29
|
}
|
|
30
|
-
}
|
|
30
|
+
}
|