@callforge/tracking-client 0.0.1 → 0.1.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 +84 -0
- package/dist/index.d.mts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +83 -13
- package/dist/index.mjs +86 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,6 +51,29 @@ client.onReady((session) => {
|
|
|
51
51
|
});
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
### 3. Track conversion parameters (optional)
|
|
55
|
+
|
|
56
|
+
The client automatically captures ad platform click IDs from the URL:
|
|
57
|
+
|
|
58
|
+
- `gclid` - Google Ads
|
|
59
|
+
- `gbraid` - Google app-to-web (iOS 14+)
|
|
60
|
+
- `wbraid` - Google web-to-app
|
|
61
|
+
- `msclkid` - Microsoft/Bing Ads
|
|
62
|
+
- `fbclid` - Facebook/Meta Ads
|
|
63
|
+
|
|
64
|
+
You can also add custom parameters:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// Add custom tracking parameters
|
|
68
|
+
client.setParams({
|
|
69
|
+
customerId: '456',
|
|
70
|
+
landingPage: 'pricing',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Parameters are automatically sent with every API request
|
|
74
|
+
const session = await client.getSession();
|
|
75
|
+
```
|
|
76
|
+
|
|
54
77
|
## API Reference
|
|
55
78
|
|
|
56
79
|
### `CallForge.init(config)`
|
|
@@ -96,6 +119,24 @@ client.onReady((session) => {
|
|
|
96
119
|
});
|
|
97
120
|
```
|
|
98
121
|
|
|
122
|
+
### `client.setParams(params)`
|
|
123
|
+
|
|
124
|
+
Set custom tracking parameters for conversion attribution.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
client.setParams({
|
|
128
|
+
customerId: '456',
|
|
129
|
+
landingPage: 'pricing',
|
|
130
|
+
campaign: 'summer-sale',
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Behavior:**
|
|
135
|
+
- Merges with existing params (later calls override earlier values)
|
|
136
|
+
- Parameters are sent with every `getSession()` API request
|
|
137
|
+
- Persisted in localStorage alongside session data
|
|
138
|
+
- Auto-captured params (gclid, etc.) are included automatically
|
|
139
|
+
|
|
99
140
|
### `getPreloadSnippet(config)`
|
|
100
141
|
|
|
101
142
|
Generate HTML snippet for preloading tracking data.
|
|
@@ -109,6 +150,35 @@ const html = getPreloadSnippet({
|
|
|
109
150
|
});
|
|
110
151
|
```
|
|
111
152
|
|
|
153
|
+
## Tracking Parameters
|
|
154
|
+
|
|
155
|
+
### Auto-Capture
|
|
156
|
+
|
|
157
|
+
The client automatically extracts these parameters from the URL on first visit:
|
|
158
|
+
|
|
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 |
|
|
166
|
+
|
|
167
|
+
### Persistence
|
|
168
|
+
|
|
169
|
+
- Parameters are stored in localStorage alongside the session
|
|
170
|
+
- On subsequent visits, cached params are used (URL may no longer have them)
|
|
171
|
+
- Custom params via `setParams()` merge with auto-captured params
|
|
172
|
+
- Later values override earlier ones (custom > cached > auto-captured)
|
|
173
|
+
|
|
174
|
+
### API Request Format
|
|
175
|
+
|
|
176
|
+
Parameters are sent as sorted query string for cache consistency:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
/v1/tracking/session?categoryId=cat-123&fbclid=456&gclid=abc&loc_physical_ms=1014221
|
|
180
|
+
```
|
|
181
|
+
|
|
112
182
|
## Caching Behavior
|
|
113
183
|
|
|
114
184
|
- **Cache key:** `loc_physical_ms` parameter from URL
|
|
@@ -141,10 +211,24 @@ import type {
|
|
|
141
211
|
CallForgeConfig,
|
|
142
212
|
TrackingSession,
|
|
143
213
|
TrackingLocation,
|
|
214
|
+
TrackingParams,
|
|
144
215
|
ReadyCallback,
|
|
145
216
|
} from '@callforge/tracking-client';
|
|
146
217
|
```
|
|
147
218
|
|
|
219
|
+
### TrackingParams
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
interface TrackingParams {
|
|
223
|
+
gclid?: string; // Google Ads Click ID
|
|
224
|
+
gbraid?: string; // Google app-to-web (iOS 14+)
|
|
225
|
+
wbraid?: string; // Google web-to-app
|
|
226
|
+
msclkid?: string; // Microsoft/Bing Ads
|
|
227
|
+
fbclid?: string; // Facebook/Meta Ads
|
|
228
|
+
[key: string]: string | undefined; // Custom params
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
148
232
|
## Environment URLs
|
|
149
233
|
|
|
150
234
|
| Environment | Endpoint |
|
package/dist/index.d.mts
CHANGED
|
@@ -18,6 +18,23 @@ interface TrackingLocation {
|
|
|
18
18
|
/** State abbreviation (e.g., "GA") */
|
|
19
19
|
stateCode: string;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Tracking parameters for attribution (auto-captured + custom).
|
|
23
|
+
*/
|
|
24
|
+
interface TrackingParams {
|
|
25
|
+
/** Google Ads Click ID */
|
|
26
|
+
gclid?: string;
|
|
27
|
+
/** Google app-to-web (iOS 14+) */
|
|
28
|
+
gbraid?: string;
|
|
29
|
+
/** Google web-to-app */
|
|
30
|
+
wbraid?: string;
|
|
31
|
+
/** Microsoft/Bing Ads Click ID */
|
|
32
|
+
msclkid?: string;
|
|
33
|
+
/** Facebook/Meta Ads Click ID */
|
|
34
|
+
fbclid?: string;
|
|
35
|
+
/** Custom parameters */
|
|
36
|
+
[key: string]: string | undefined;
|
|
37
|
+
}
|
|
21
38
|
/**
|
|
22
39
|
* Session data returned by getSession().
|
|
23
40
|
*/
|
|
@@ -59,6 +76,7 @@ declare class CallForge {
|
|
|
59
76
|
private readonly config;
|
|
60
77
|
private readonly cache;
|
|
61
78
|
private sessionPromise;
|
|
79
|
+
private customParams;
|
|
62
80
|
private constructor();
|
|
63
81
|
/**
|
|
64
82
|
* Initialize the CallForge tracking client.
|
|
@@ -74,12 +92,19 @@ declare class CallForge {
|
|
|
74
92
|
* Callback is called once session data is available.
|
|
75
93
|
*/
|
|
76
94
|
onReady(callback: ReadyCallback): void;
|
|
95
|
+
/**
|
|
96
|
+
* Set custom tracking parameters.
|
|
97
|
+
* Merges with existing params (new values override).
|
|
98
|
+
*/
|
|
99
|
+
setParams(params: Record<string, string>): void;
|
|
77
100
|
private fetchSession;
|
|
78
101
|
private getLocationId;
|
|
102
|
+
private getAutoParams;
|
|
79
103
|
private fetchFromApi;
|
|
80
104
|
private saveToCache;
|
|
81
105
|
private formatSession;
|
|
82
106
|
private formatApiResponse;
|
|
107
|
+
private buildUrl;
|
|
83
108
|
}
|
|
84
109
|
|
|
85
110
|
/**
|
|
@@ -99,4 +124,4 @@ declare class CallForge {
|
|
|
99
124
|
*/
|
|
100
125
|
declare function getPreloadSnippet(config: CallForgeConfig): string;
|
|
101
126
|
|
|
102
|
-
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingSession, getPreloadSnippet };
|
|
127
|
+
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getPreloadSnippet };
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,23 @@ interface TrackingLocation {
|
|
|
18
18
|
/** State abbreviation (e.g., "GA") */
|
|
19
19
|
stateCode: string;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Tracking parameters for attribution (auto-captured + custom).
|
|
23
|
+
*/
|
|
24
|
+
interface TrackingParams {
|
|
25
|
+
/** Google Ads Click ID */
|
|
26
|
+
gclid?: string;
|
|
27
|
+
/** Google app-to-web (iOS 14+) */
|
|
28
|
+
gbraid?: string;
|
|
29
|
+
/** Google web-to-app */
|
|
30
|
+
wbraid?: string;
|
|
31
|
+
/** Microsoft/Bing Ads Click ID */
|
|
32
|
+
msclkid?: string;
|
|
33
|
+
/** Facebook/Meta Ads Click ID */
|
|
34
|
+
fbclid?: string;
|
|
35
|
+
/** Custom parameters */
|
|
36
|
+
[key: string]: string | undefined;
|
|
37
|
+
}
|
|
21
38
|
/**
|
|
22
39
|
* Session data returned by getSession().
|
|
23
40
|
*/
|
|
@@ -59,6 +76,7 @@ declare class CallForge {
|
|
|
59
76
|
private readonly config;
|
|
60
77
|
private readonly cache;
|
|
61
78
|
private sessionPromise;
|
|
79
|
+
private customParams;
|
|
62
80
|
private constructor();
|
|
63
81
|
/**
|
|
64
82
|
* Initialize the CallForge tracking client.
|
|
@@ -74,12 +92,19 @@ declare class CallForge {
|
|
|
74
92
|
* Callback is called once session data is available.
|
|
75
93
|
*/
|
|
76
94
|
onReady(callback: ReadyCallback): void;
|
|
95
|
+
/**
|
|
96
|
+
* Set custom tracking parameters.
|
|
97
|
+
* Merges with existing params (new values override).
|
|
98
|
+
*/
|
|
99
|
+
setParams(params: Record<string, string>): void;
|
|
77
100
|
private fetchSession;
|
|
78
101
|
private getLocationId;
|
|
102
|
+
private getAutoParams;
|
|
79
103
|
private fetchFromApi;
|
|
80
104
|
private saveToCache;
|
|
81
105
|
private formatSession;
|
|
82
106
|
private formatApiResponse;
|
|
107
|
+
private buildUrl;
|
|
83
108
|
}
|
|
84
109
|
|
|
85
110
|
/**
|
|
@@ -99,4 +124,4 @@ declare class CallForge {
|
|
|
99
124
|
*/
|
|
100
125
|
declare function getPreloadSnippet(config: CallForgeConfig): string;
|
|
101
126
|
|
|
102
|
-
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingSession, getPreloadSnippet };
|
|
127
|
+
export { CallForge, type CallForgeConfig, type ReadyCallback, type TrackingLocation, type TrackingParams, type TrackingSession, getPreloadSnippet };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,21 @@
|
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
6
20
|
var __export = (target, all) => {
|
|
7
21
|
for (var name in all)
|
|
8
22
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -64,6 +78,15 @@ var TrackingCache = class {
|
|
|
64
78
|
if (cached.locId !== locationId) return null;
|
|
65
79
|
return cached.sessionId;
|
|
66
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Get cached params (for merging with new params).
|
|
83
|
+
* Returns empty object if no cache or no params.
|
|
84
|
+
*/
|
|
85
|
+
getParams() {
|
|
86
|
+
var _a;
|
|
87
|
+
const cached = this.read();
|
|
88
|
+
return (_a = cached == null ? void 0 : cached.params) != null ? _a : {};
|
|
89
|
+
}
|
|
67
90
|
/**
|
|
68
91
|
* Store session data in cache.
|
|
69
92
|
*/
|
|
@@ -107,9 +130,11 @@ var TrackingCache = class {
|
|
|
107
130
|
// src/client.ts
|
|
108
131
|
var DEFAULT_ENDPOINT = "https://tracking.callforge.io";
|
|
109
132
|
var FETCH_TIMEOUT_MS = 1e4;
|
|
133
|
+
var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid"];
|
|
110
134
|
var CallForge = class _CallForge {
|
|
111
135
|
constructor(config) {
|
|
112
136
|
this.sessionPromise = null;
|
|
137
|
+
this.customParams = {};
|
|
113
138
|
this.config = {
|
|
114
139
|
categoryId: config.categoryId,
|
|
115
140
|
endpoint: config.endpoint || DEFAULT_ENDPOINT
|
|
@@ -141,6 +166,13 @@ var CallForge = class _CallForge {
|
|
|
141
166
|
this.getSession().then(callback).catch(() => {
|
|
142
167
|
});
|
|
143
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Set custom tracking parameters.
|
|
171
|
+
* Merges with existing params (new values override).
|
|
172
|
+
*/
|
|
173
|
+
setParams(params) {
|
|
174
|
+
this.customParams = __spreadValues(__spreadValues({}, this.customParams), params);
|
|
175
|
+
}
|
|
144
176
|
async fetchSession() {
|
|
145
177
|
const locationId = this.getLocationId();
|
|
146
178
|
if (!locationId) {
|
|
@@ -150,17 +182,20 @@ var CallForge = class _CallForge {
|
|
|
150
182
|
if (cached) {
|
|
151
183
|
return this.formatSession(cached);
|
|
152
184
|
}
|
|
185
|
+
const autoParams = this.getAutoParams();
|
|
186
|
+
const cachedParams = this.cache.getParams();
|
|
187
|
+
const params = __spreadValues(__spreadValues(__spreadValues({}, autoParams), cachedParams), this.customParams);
|
|
153
188
|
if (typeof window !== "undefined" && window.__cfTracking) {
|
|
154
189
|
try {
|
|
155
190
|
const data2 = await window.__cfTracking;
|
|
156
|
-
this.saveToCache(locationId, data2);
|
|
191
|
+
this.saveToCache(locationId, data2, params);
|
|
157
192
|
return this.formatApiResponse(data2);
|
|
158
193
|
} catch (e) {
|
|
159
194
|
}
|
|
160
195
|
}
|
|
161
196
|
const sessionId = this.cache.getSessionId(locationId);
|
|
162
|
-
const data = await this.fetchFromApi(locationId, sessionId);
|
|
163
|
-
this.saveToCache(locationId, data);
|
|
197
|
+
const data = await this.fetchFromApi(locationId, sessionId, params);
|
|
198
|
+
this.saveToCache(locationId, data, params);
|
|
164
199
|
return this.formatApiResponse(data);
|
|
165
200
|
}
|
|
166
201
|
getLocationId() {
|
|
@@ -168,12 +203,20 @@ var CallForge = class _CallForge {
|
|
|
168
203
|
const params = new URLSearchParams(window.location.search);
|
|
169
204
|
return params.get("loc_physical_ms");
|
|
170
205
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
206
|
+
getAutoParams() {
|
|
207
|
+
if (typeof window === "undefined") return {};
|
|
208
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
209
|
+
const params = {};
|
|
210
|
+
for (const key of AUTO_PARAMS) {
|
|
211
|
+
const value = urlParams.get(key);
|
|
212
|
+
if (value) {
|
|
213
|
+
params[key] = value;
|
|
214
|
+
}
|
|
176
215
|
}
|
|
216
|
+
return params;
|
|
217
|
+
}
|
|
218
|
+
async fetchFromApi(locationId, sessionId, params) {
|
|
219
|
+
const url = this.buildUrl(locationId, sessionId, params);
|
|
177
220
|
const controller = new AbortController();
|
|
178
221
|
const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
179
222
|
try {
|
|
@@ -189,13 +232,14 @@ var CallForge = class _CallForge {
|
|
|
189
232
|
clearTimeout(timeoutId);
|
|
190
233
|
}
|
|
191
234
|
}
|
|
192
|
-
saveToCache(locationId, data) {
|
|
235
|
+
saveToCache(locationId, data, params) {
|
|
193
236
|
const cached = {
|
|
194
237
|
locId: locationId,
|
|
195
238
|
sessionId: data.sessionId,
|
|
196
239
|
phoneNumber: data.phoneNumber,
|
|
197
240
|
location: data.location,
|
|
198
|
-
expiresAt: data.expiresAt
|
|
241
|
+
expiresAt: data.expiresAt,
|
|
242
|
+
params
|
|
199
243
|
};
|
|
200
244
|
this.cache.set(cached);
|
|
201
245
|
}
|
|
@@ -213,6 +257,24 @@ var CallForge = class _CallForge {
|
|
|
213
257
|
location: data.location
|
|
214
258
|
};
|
|
215
259
|
}
|
|
260
|
+
buildUrl(locationId, sessionId, params) {
|
|
261
|
+
const { categoryId, endpoint } = this.config;
|
|
262
|
+
const queryParams = {
|
|
263
|
+
categoryId,
|
|
264
|
+
loc_physical_ms: locationId
|
|
265
|
+
};
|
|
266
|
+
if (sessionId) {
|
|
267
|
+
queryParams.sessionId = sessionId;
|
|
268
|
+
}
|
|
269
|
+
for (const [key, value] of Object.entries(params)) {
|
|
270
|
+
if (value !== void 0) {
|
|
271
|
+
queryParams[key] = value;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const sorted = Object.keys(queryParams).sort();
|
|
275
|
+
const qs = sorted.map((k) => `${k}=${encodeURIComponent(queryParams[k])}`).join("&");
|
|
276
|
+
return `${endpoint}/v1/tracking/session?${qs}`;
|
|
277
|
+
}
|
|
216
278
|
};
|
|
217
279
|
|
|
218
280
|
// src/preload.ts
|
|
@@ -234,17 +296,25 @@ function getPreloadSnippet(config) {
|
|
|
234
296
|
}
|
|
235
297
|
const cacheKey = `cf_tracking_${categoryId}`;
|
|
236
298
|
const script = `(function(){
|
|
237
|
-
var
|
|
299
|
+
var u=new URLSearchParams(location.search);
|
|
300
|
+
var loc=u.get('loc_physical_ms');
|
|
238
301
|
if(!loc)return;
|
|
302
|
+
var ap=['gclid','gbraid','wbraid','msclkid','fbclid'];
|
|
303
|
+
var p={};
|
|
304
|
+
for(var i=0;i<ap.length;i++){var v=u.get(ap[i]);if(v)p[ap[i]]=v}
|
|
239
305
|
var key='${cacheKey}';
|
|
240
306
|
try{
|
|
241
307
|
var c=JSON.parse(localStorage.getItem(key));
|
|
242
|
-
if(c&&c.locId===loc&&c.expiresAt>Date.now()+30000){window.__cfTracking=Promise.resolve(c);return}
|
|
308
|
+
if(c&&c.locId===loc&&c.expiresAt>Date.now()+30000){c.params=Object.assign({},c.params,p);window.__cfTracking=Promise.resolve(c);return}
|
|
243
309
|
var sid=(c&&c.locId===loc)?c.sessionId:null;
|
|
310
|
+
var cp=c&&c.params||{};
|
|
311
|
+
p=Object.assign({},p,cp);
|
|
244
312
|
}catch(e){}
|
|
245
313
|
var url='${endpoint}/v1/tracking/session?categoryId=${categoryId}&loc_physical_ms='+loc;
|
|
246
314
|
if(sid)url+='&sessionId='+sid;
|
|
247
|
-
|
|
315
|
+
var ks=Object.keys(p).sort();
|
|
316
|
+
for(var j=0;j<ks.length;j++)url+='&'+ks[j]+'='+encodeURIComponent(p[ks[j]]);
|
|
317
|
+
window.__cfTracking=fetch(url,{credentials:'omit'}).then(function(r){return r.json()}).then(function(d){d.params=p;try{localStorage.setItem(key,JSON.stringify({locId:loc,sessionId:d.sessionId,phoneNumber:d.phoneNumber,location:d.location,expiresAt:d.expiresAt,params:p}))}catch(e){}return d});
|
|
248
318
|
})();`.replace(/\n/g, "");
|
|
249
319
|
return `<link rel="preconnect" href="${endpoint}">
|
|
250
320
|
<script>${script}</script>`;
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
|
|
1
18
|
// src/cache.ts
|
|
2
19
|
var EXPIRY_BUFFER_MS = 3e4;
|
|
3
20
|
var TrackingCache = class {
|
|
@@ -37,6 +54,15 @@ var TrackingCache = class {
|
|
|
37
54
|
if (cached.locId !== locationId) return null;
|
|
38
55
|
return cached.sessionId;
|
|
39
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Get cached params (for merging with new params).
|
|
59
|
+
* Returns empty object if no cache or no params.
|
|
60
|
+
*/
|
|
61
|
+
getParams() {
|
|
62
|
+
var _a;
|
|
63
|
+
const cached = this.read();
|
|
64
|
+
return (_a = cached == null ? void 0 : cached.params) != null ? _a : {};
|
|
65
|
+
}
|
|
40
66
|
/**
|
|
41
67
|
* Store session data in cache.
|
|
42
68
|
*/
|
|
@@ -80,9 +106,11 @@ var TrackingCache = class {
|
|
|
80
106
|
// src/client.ts
|
|
81
107
|
var DEFAULT_ENDPOINT = "https://tracking.callforge.io";
|
|
82
108
|
var FETCH_TIMEOUT_MS = 1e4;
|
|
109
|
+
var AUTO_PARAMS = ["gclid", "gbraid", "wbraid", "msclkid", "fbclid"];
|
|
83
110
|
var CallForge = class _CallForge {
|
|
84
111
|
constructor(config) {
|
|
85
112
|
this.sessionPromise = null;
|
|
113
|
+
this.customParams = {};
|
|
86
114
|
this.config = {
|
|
87
115
|
categoryId: config.categoryId,
|
|
88
116
|
endpoint: config.endpoint || DEFAULT_ENDPOINT
|
|
@@ -114,6 +142,13 @@ var CallForge = class _CallForge {
|
|
|
114
142
|
this.getSession().then(callback).catch(() => {
|
|
115
143
|
});
|
|
116
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Set custom tracking parameters.
|
|
147
|
+
* Merges with existing params (new values override).
|
|
148
|
+
*/
|
|
149
|
+
setParams(params) {
|
|
150
|
+
this.customParams = __spreadValues(__spreadValues({}, this.customParams), params);
|
|
151
|
+
}
|
|
117
152
|
async fetchSession() {
|
|
118
153
|
const locationId = this.getLocationId();
|
|
119
154
|
if (!locationId) {
|
|
@@ -123,17 +158,20 @@ var CallForge = class _CallForge {
|
|
|
123
158
|
if (cached) {
|
|
124
159
|
return this.formatSession(cached);
|
|
125
160
|
}
|
|
161
|
+
const autoParams = this.getAutoParams();
|
|
162
|
+
const cachedParams = this.cache.getParams();
|
|
163
|
+
const params = __spreadValues(__spreadValues(__spreadValues({}, autoParams), cachedParams), this.customParams);
|
|
126
164
|
if (typeof window !== "undefined" && window.__cfTracking) {
|
|
127
165
|
try {
|
|
128
166
|
const data2 = await window.__cfTracking;
|
|
129
|
-
this.saveToCache(locationId, data2);
|
|
167
|
+
this.saveToCache(locationId, data2, params);
|
|
130
168
|
return this.formatApiResponse(data2);
|
|
131
169
|
} catch (e) {
|
|
132
170
|
}
|
|
133
171
|
}
|
|
134
172
|
const sessionId = this.cache.getSessionId(locationId);
|
|
135
|
-
const data = await this.fetchFromApi(locationId, sessionId);
|
|
136
|
-
this.saveToCache(locationId, data);
|
|
173
|
+
const data = await this.fetchFromApi(locationId, sessionId, params);
|
|
174
|
+
this.saveToCache(locationId, data, params);
|
|
137
175
|
return this.formatApiResponse(data);
|
|
138
176
|
}
|
|
139
177
|
getLocationId() {
|
|
@@ -141,12 +179,20 @@ var CallForge = class _CallForge {
|
|
|
141
179
|
const params = new URLSearchParams(window.location.search);
|
|
142
180
|
return params.get("loc_physical_ms");
|
|
143
181
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
182
|
+
getAutoParams() {
|
|
183
|
+
if (typeof window === "undefined") return {};
|
|
184
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
185
|
+
const params = {};
|
|
186
|
+
for (const key of AUTO_PARAMS) {
|
|
187
|
+
const value = urlParams.get(key);
|
|
188
|
+
if (value) {
|
|
189
|
+
params[key] = value;
|
|
190
|
+
}
|
|
149
191
|
}
|
|
192
|
+
return params;
|
|
193
|
+
}
|
|
194
|
+
async fetchFromApi(locationId, sessionId, params) {
|
|
195
|
+
const url = this.buildUrl(locationId, sessionId, params);
|
|
150
196
|
const controller = new AbortController();
|
|
151
197
|
const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
152
198
|
try {
|
|
@@ -162,13 +208,14 @@ var CallForge = class _CallForge {
|
|
|
162
208
|
clearTimeout(timeoutId);
|
|
163
209
|
}
|
|
164
210
|
}
|
|
165
|
-
saveToCache(locationId, data) {
|
|
211
|
+
saveToCache(locationId, data, params) {
|
|
166
212
|
const cached = {
|
|
167
213
|
locId: locationId,
|
|
168
214
|
sessionId: data.sessionId,
|
|
169
215
|
phoneNumber: data.phoneNumber,
|
|
170
216
|
location: data.location,
|
|
171
|
-
expiresAt: data.expiresAt
|
|
217
|
+
expiresAt: data.expiresAt,
|
|
218
|
+
params
|
|
172
219
|
};
|
|
173
220
|
this.cache.set(cached);
|
|
174
221
|
}
|
|
@@ -186,6 +233,24 @@ var CallForge = class _CallForge {
|
|
|
186
233
|
location: data.location
|
|
187
234
|
};
|
|
188
235
|
}
|
|
236
|
+
buildUrl(locationId, sessionId, params) {
|
|
237
|
+
const { categoryId, endpoint } = this.config;
|
|
238
|
+
const queryParams = {
|
|
239
|
+
categoryId,
|
|
240
|
+
loc_physical_ms: locationId
|
|
241
|
+
};
|
|
242
|
+
if (sessionId) {
|
|
243
|
+
queryParams.sessionId = sessionId;
|
|
244
|
+
}
|
|
245
|
+
for (const [key, value] of Object.entries(params)) {
|
|
246
|
+
if (value !== void 0) {
|
|
247
|
+
queryParams[key] = value;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const sorted = Object.keys(queryParams).sort();
|
|
251
|
+
const qs = sorted.map((k) => `${k}=${encodeURIComponent(queryParams[k])}`).join("&");
|
|
252
|
+
return `${endpoint}/v1/tracking/session?${qs}`;
|
|
253
|
+
}
|
|
189
254
|
};
|
|
190
255
|
|
|
191
256
|
// src/preload.ts
|
|
@@ -207,17 +272,25 @@ function getPreloadSnippet(config) {
|
|
|
207
272
|
}
|
|
208
273
|
const cacheKey = `cf_tracking_${categoryId}`;
|
|
209
274
|
const script = `(function(){
|
|
210
|
-
var
|
|
275
|
+
var u=new URLSearchParams(location.search);
|
|
276
|
+
var loc=u.get('loc_physical_ms');
|
|
211
277
|
if(!loc)return;
|
|
278
|
+
var ap=['gclid','gbraid','wbraid','msclkid','fbclid'];
|
|
279
|
+
var p={};
|
|
280
|
+
for(var i=0;i<ap.length;i++){var v=u.get(ap[i]);if(v)p[ap[i]]=v}
|
|
212
281
|
var key='${cacheKey}';
|
|
213
282
|
try{
|
|
214
283
|
var c=JSON.parse(localStorage.getItem(key));
|
|
215
|
-
if(c&&c.locId===loc&&c.expiresAt>Date.now()+30000){window.__cfTracking=Promise.resolve(c);return}
|
|
284
|
+
if(c&&c.locId===loc&&c.expiresAt>Date.now()+30000){c.params=Object.assign({},c.params,p);window.__cfTracking=Promise.resolve(c);return}
|
|
216
285
|
var sid=(c&&c.locId===loc)?c.sessionId:null;
|
|
286
|
+
var cp=c&&c.params||{};
|
|
287
|
+
p=Object.assign({},p,cp);
|
|
217
288
|
}catch(e){}
|
|
218
289
|
var url='${endpoint}/v1/tracking/session?categoryId=${categoryId}&loc_physical_ms='+loc;
|
|
219
290
|
if(sid)url+='&sessionId='+sid;
|
|
220
|
-
|
|
291
|
+
var ks=Object.keys(p).sort();
|
|
292
|
+
for(var j=0;j<ks.length;j++)url+='&'+ks[j]+'='+encodeURIComponent(p[ks[j]]);
|
|
293
|
+
window.__cfTracking=fetch(url,{credentials:'omit'}).then(function(r){return r.json()}).then(function(d){d.params=p;try{localStorage.setItem(key,JSON.stringify({locId:loc,sessionId:d.sessionId,phoneNumber:d.phoneNumber,location:d.location,expiresAt:d.expiresAt,params:p}))}catch(e){}return d});
|
|
221
294
|
})();`.replace(/\n/g, "");
|
|
222
295
|
return `<link rel="preconnect" href="${endpoint}">
|
|
223
296
|
<script>${script}</script>`;
|