@thred-apps/thred-track 1.2.0 → 1.2.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
@@ -1,106 +1,43 @@
1
1
  # Thred SDK
2
2
 
3
- A modern TypeScript SDK for browser tracking and lead enrichment from ChatGPT referrals.
4
-
5
- ## Features
6
-
7
- - **ChatGPT Detection** - Automatic detection of visitors from ChatGPT
8
- - **Browser Fingerprinting** - Privacy-friendly visitor identification
9
- - **Page View Tracking** - Automatic page view analytics
10
- - **Form Tracking** - Automatic form submission tracking
11
- - **Lead Enrichment** - Capture and enrich lead data
12
- - **Zero Dependencies** - Lightweight with no external dependencies
13
- - **Multiple Formats** - UMD, CommonJS, and ES modules
14
- - **TypeScript Support** - Full TypeScript definitions included
3
+ Automatic browser tracking and lead enrichment for ChatGPT referrals.
15
4
 
16
5
  ## Installation
17
6
 
18
- ### NPM
19
-
20
- ```bash
21
- npm install thred-track
22
- ```
23
-
24
- ### Yarn
25
-
26
- ```bash
27
- yarn add thred-track
28
- ```
29
-
30
- ### CDN (Script Tag)
31
-
32
- ```html
33
- <script src="https://cdn.thred.dev/thred-track/thred-track.js?browserKey=YOUR_KEY"></script>
34
- ```
35
-
36
- ## Quick Start
37
-
38
7
  ### Script Tag
39
8
 
40
- Drop the script onto your page with your browser key. That's it — everything is automatic:
41
-
42
9
  ```html
43
10
  <script src="https://cdn.thred.dev/thred-track.js?browserKey=YOUR_KEY"></script>
44
11
  ```
45
12
 
46
- ### Module Import
47
-
48
- ```typescript
49
- import { ThredSDK } from 'thred-track';
13
+ ### NPM
50
14
 
51
- new ThredSDK({ browserKey: 'YOUR_KEY' });
15
+ ```bash
16
+ npm install @thred-apps/thred-track
52
17
  ```
53
18
 
54
- No additional setup required. The SDK automatically:
55
-
56
- 1. Detects ChatGPT referrals via UTM parameters
57
- 2. Generates a browser fingerprint
58
- 3. Tracks page views for ChatGPT visitors
59
- 4. Monitors and captures form submissions based on your API config
60
-
61
- ## What Happens on Initialization
62
-
63
- When the SDK initializes, it follows the same flow as the original script:
64
-
65
- 1. **Fetches config** from the Thred API using your `browserKey`
66
- 2. **Checks eligibility** — tracking only runs if the config says `enabled: true` and the visitor has a ChatGPT session or arrived via ChatGPT UTM
67
- 3. **Tracks the page view** automatically for ChatGPT visitors
68
- 4. **Sets up form tracking** — either injecting fingerprints into hosted form links, or attaching submit listeners to your form (based on config `type`)
69
-
70
- All of this happens without any manual method calls.
71
-
72
- ## Constructor Options
73
-
74
19
  ```typescript
75
- interface ThredOptions {
76
- browserKey: string; // Required: Your Thred browser key
77
- debug?: boolean; // Optional: Enable debug logging (default: false)
78
- autoInit?: boolean; // Optional: Auto-initialize on construction (default: true)
79
- }
80
- ```
20
+ import { ThredSDK } from '@thred-apps/thred-track';
81
21
 
82
- ## Usage Examples
22
+ new ThredSDK({ browserKey: 'YOUR_KEY' });
23
+ ```
83
24
 
84
- ### Basic HTML Page
25
+ That's it. The SDK automatically:
85
26
 
86
- ```html
87
- <form id="form">
88
- <input type="text" name="name" required>
89
- <input type="email" name="email" required>
90
- <input type="text" name="company">
91
- <button type="submit">Submit</button>
92
- </form>
27
+ - Detects ChatGPT referrals
28
+ - Fingerprints the visitor
29
+ - Tracks page views
30
+ - Captures form submissions
93
31
 
94
- <script src="https://unpkg.com/thred-track/dist/thred-track.umd.js?browserKey=YOUR_KEY"></script>
95
- ```
32
+ No manual method calls needed.
96
33
 
97
- The SDK automatically picks up the form and tracks submissions — no extra JavaScript needed.
34
+ ## Framework Examples
98
35
 
99
36
  ### React
100
37
 
101
38
  ```typescript
102
39
  import { useEffect, useRef } from 'react';
103
- import { ThredSDK } from 'thred-track';
40
+ import { ThredSDK } from '@thred-apps/thred-track';
104
41
 
105
42
  function App() {
106
43
  const thredRef = useRef<ThredSDK | null>(null);
@@ -108,9 +45,7 @@ function App() {
108
45
  useEffect(() => {
109
46
  thredRef.current = new ThredSDK({
110
47
  browserKey: process.env.REACT_APP_THRED_KEY!,
111
- debug: process.env.NODE_ENV === 'development',
112
48
  });
113
-
114
49
  return () => thredRef.current?.destroy();
115
50
  }, []);
116
51
 
@@ -124,7 +59,7 @@ function App() {
124
59
  'use client';
125
60
 
126
61
  import { useEffect, useRef } from 'react';
127
- import { ThredSDK } from 'thred-track';
62
+ import { ThredSDK } from '@thred-apps/thred-track';
128
63
 
129
64
  export function ThredProvider({ children }: { children: React.ReactNode }) {
130
65
  const thredRef = useRef<ThredSDK | null>(null);
@@ -133,7 +68,6 @@ export function ThredProvider({ children }: { children: React.ReactNode }) {
133
68
  thredRef.current = new ThredSDK({
134
69
  browserKey: process.env.NEXT_PUBLIC_THRED_KEY!,
135
70
  });
136
-
137
71
  return () => thredRef.current?.destroy();
138
72
  }, []);
139
73
 
@@ -141,162 +75,17 @@ export function ThredProvider({ children }: { children: React.ReactNode }) {
141
75
  }
142
76
  ```
143
77
 
144
- ### Delayed Initialization
145
-
146
- If you need to control when tracking starts (e.g., after user consent):
147
-
148
- ```typescript
149
- import { ThredSDK } from 'thred-track';
150
-
151
- const thred = new ThredSDK({
152
- browserKey: 'YOUR_KEY',
153
- autoInit: false,
154
- });
155
-
156
- // Later, when ready:
157
- await thred.init();
158
- ```
159
-
160
- ## Advanced API
161
-
162
- These methods are available for advanced use cases but are **not required** for typical usage — the SDK handles everything automatically.
163
-
164
- #### `identify(leadData: LeadData): Promise<void>`
165
-
166
- Manually identify a user outside of automatic form tracking (e.g., after OAuth or a custom flow):
167
-
168
- ```typescript
169
- await thred.identify({
170
- name: 'John Doe',
171
- email: 'john@example.com',
172
- company: 'Acme Inc',
173
- });
174
- ```
175
-
176
- #### `destroy(): void`
177
-
178
- Clean up the SDK instance and remove event listeners. Use this when unmounting in SPAs:
179
-
180
- ```typescript
181
- thred.destroy();
182
- ```
183
-
184
- ## Development
185
-
186
- ### Setup
187
-
188
- ```bash
189
- npm install
190
- npm run build
191
- npm run dev # Watch mode
192
- npm test
193
- npm run lint
194
- npm run format
195
- ```
196
-
197
- ### Project Structure
198
-
199
- ```
200
- thred-track/
201
- ├── src/
202
- │ ├── core/ # Core SDK functionality
203
- │ │ ├── api.ts # API client
204
- │ │ ├── fingerprint.ts # Fingerprint management
205
- │ │ └── tracker.ts # Event tracking
206
- │ ├── utils/ # Utility functions
207
- │ │ ├── detector.ts # ChatGPT detection
208
- │ │ └── logger.ts # Logging utility
209
- │ ├── types/ # TypeScript definitions
210
- │ │ └── index.ts
211
- │ ├── __tests__/ # Test files
212
- │ └── index.ts # Main entry point
213
- ├── dist/ # Build output
214
- └── package.json
215
- ```
216
-
217
- ### Building
218
-
219
- The SDK builds to multiple formats:
220
-
221
- - **UMD** (`dist/thred-track.umd.js`) — For script tags
222
- - **CommonJS** (`dist/index.js`) — For Node.js / bundlers
223
- - **ES Module** (`dist/index.esm.js`) — For modern bundlers
224
- - **TypeScript** (`dist/index.d.ts`) — Type definitions
225
-
226
- ### Testing
227
-
228
- ```bash
229
- npm test
230
- npm run test:watch
231
- ```
232
-
233
- ### Local Testing
234
-
235
- ```bash
236
- npm run serve
237
- ```
238
-
239
- Then open http://localhost:8080/basic.html?utm_source=chatgpt
240
-
241
- ## Configuration
242
-
243
- The SDK fetches configuration from your Thred API automatically on init:
244
-
245
- ```json
246
- {
247
- "enabled": true,
248
- "type": "custom",
249
- "formId": "form",
250
- "emailId": "email",
251
- "nameId": "name",
252
- "companyId": "company",
253
- "hasChatSession": true
254
- }
255
- ```
256
-
257
- This config controls which form to track, which fields to extract, and whether the visitor has an existing ChatGPT session.
258
-
259
78
  ## Privacy & Security
260
79
 
261
- - Only tracks visitors from ChatGPT (opt-in by source)
262
- - Uses browser fingerprinting (no cookies required)
263
- - All tracking controlled by API configuration
80
+ - Only tracks visitors arriving from ChatGPT
81
+ - Browser fingerprinting no cookies required
264
82
  - No PII collected without explicit user submission
265
- - Compliant with privacy regulations (GDPR, CCPA)
83
+ - GDPR and CCPA compliant
266
84
 
267
85
  ## Browser Support
268
86
 
269
- - Chrome/Edge (latest)
270
- - Firefox (latest)
271
- - Safari (latest)
272
- - Opera (latest)
273
-
274
- Requires ES2015+ support.
275
-
276
- ## API Endpoints
277
-
278
- - **Config**: `GET /v1/config?browserKey={key}`
279
- - **Page View**: `POST /v1/events/page-view?browserKey={key}`
280
- - **Enrich**: `POST /v1/customers/enrich?browserKey={key}`
281
-
282
- ## TypeScript
283
-
284
- Full TypeScript support with exported types:
285
-
286
- ```typescript
287
- import type {
288
- ThredOptions,
289
- ThredConfig,
290
- LeadData,
291
- PageViewPayload,
292
- EnrichPayload,
293
- } from 'thred-track';
294
- ```
87
+ Chrome, Firefox, Safari, Edge (latest versions). Requires ES2015+.
295
88
 
296
89
  ## License
297
90
 
298
91
  MIT
299
-
300
- ## Support
301
-
302
- For questions or issues, please open a GitHub issue or contact support@thred.dev.
@@ -8,6 +8,10 @@ export declare class Tracker {
8
8
  private logger;
9
9
  private config;
10
10
  private formObserver;
11
+ private lastTrackedUrl;
12
+ private popstateHandler;
13
+ private originalPushState;
14
+ private originalReplaceState;
11
15
  constructor(api: ThredAPI, fingerprint: FingerprintManager, logger: Logger);
12
16
  /**
13
17
  * Initialize tracker with config
@@ -25,6 +29,11 @@ export declare class Tracker {
25
29
  * Identify user and enrich lead data
26
30
  */
27
31
  identify(leadData: LeadData): Promise<void>;
32
+ /**
33
+ * Track page views on SPA route changes by patching pushState/replaceState
34
+ * and listening for popstate.
35
+ */
36
+ private setupRouteTracking;
28
37
  /**
29
38
  * Setup automatic form tracking
30
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/core/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAW;IACtB,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,YAAY,CAAiC;gBAGnD,GAAG,EAAE,QAAQ,EACb,WAAW,EAAE,kBAAkB,EAC/B,MAAM,EAAE,MAAM;IAOhB;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA8B3B;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBpC;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BxD;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAcjD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsGzB;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAOlC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAuBjC;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB"}
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/core/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAW;IACtB,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,iBAAiB,CAAyC;IAClE,OAAO,CAAC,oBAAoB,CAA4C;gBAGtE,GAAG,EAAE,QAAQ,EACb,WAAW,EAAE,kBAAkB,EAC/B,MAAM,EAAE,MAAM;IAOhB;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBpC;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BxD;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAcjD;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA8B1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsGzB;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAOlC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAuBjC;;OAEG;IACH,OAAO,IAAI,IAAI;CAqBhB"}
package/dist/index.esm.js CHANGED
@@ -258,6 +258,10 @@ class Tracker {
258
258
  constructor(api, fingerprint, logger) {
259
259
  this.config = null;
260
260
  this.formObserver = null;
261
+ this.lastTrackedUrl = null;
262
+ this.popstateHandler = null;
263
+ this.originalPushState = null;
264
+ this.originalReplaceState = null;
261
265
  this.api = api;
262
266
  this.fingerprint = fingerprint;
263
267
  this.logger = logger;
@@ -283,13 +287,15 @@ class Tracker {
283
287
  this.logger.log('No chat session for this fingerprint - exiting');
284
288
  return;
285
289
  }
286
- // Only track page view if UTM is from ChatGPT
290
+ // Track initial page view
287
291
  if (isFromChatGPT()) {
288
292
  yield this.trackPageView();
289
293
  }
290
294
  else {
291
295
  this.logger.log('UTM not from ChatGPT - skipping page view');
292
296
  }
297
+ // Track SPA route changes
298
+ this.setupRouteTracking();
293
299
  // Setup form tracking
294
300
  this.setupFormTracking();
295
301
  });
@@ -358,6 +364,35 @@ class Tracker {
358
364
  });
359
365
  });
360
366
  }
367
+ /**
368
+ * Track page views on SPA route changes by patching pushState/replaceState
369
+ * and listening for popstate.
370
+ */
371
+ setupRouteTracking() {
372
+ if (typeof window === 'undefined')
373
+ return;
374
+ this.lastTrackedUrl = window.location.href;
375
+ const onRouteChange = () => {
376
+ const currentUrl = window.location.href;
377
+ if (currentUrl === this.lastTrackedUrl)
378
+ return;
379
+ this.lastTrackedUrl = currentUrl;
380
+ this.logger.log('Route change detected:', currentUrl);
381
+ this.trackPageView();
382
+ };
383
+ this.popstateHandler = onRouteChange;
384
+ window.addEventListener('popstate', this.popstateHandler);
385
+ this.originalPushState = history.pushState.bind(history);
386
+ this.originalReplaceState = history.replaceState.bind(history);
387
+ history.pushState = (...args) => {
388
+ this.originalPushState(...args);
389
+ onRouteChange();
390
+ };
391
+ history.replaceState = (...args) => {
392
+ this.originalReplaceState(...args);
393
+ onRouteChange();
394
+ };
395
+ }
361
396
  /**
362
397
  * Setup automatic form tracking
363
398
  */
@@ -485,6 +520,18 @@ class Tracker {
485
520
  this.formObserver.disconnect();
486
521
  this.formObserver = null;
487
522
  }
523
+ if (this.popstateHandler) {
524
+ window.removeEventListener('popstate', this.popstateHandler);
525
+ this.popstateHandler = null;
526
+ }
527
+ if (this.originalPushState) {
528
+ history.pushState = this.originalPushState;
529
+ this.originalPushState = null;
530
+ }
531
+ if (this.originalReplaceState) {
532
+ history.replaceState = this.originalReplaceState;
533
+ this.originalReplaceState = null;
534
+ }
488
535
  }
489
536
  }
490
537