getu-attribution-v2-sdk 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 ADDED
@@ -0,0 +1,775 @@
1
+ # GetuAI Attribution SDK
2
+
3
+ A JavaScript SDK for tracking user attribution and conversion events in web applications.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Features](#features)
8
+ - [Installation](#installation)
9
+ - [Quick Start](#quick-start)
10
+ - [Configuration](#configuration)
11
+ - [Event Tracking](#event-tracking)
12
+ - [Auto-Tracking](#auto-tracking)
13
+ - [SPA Support](#spa-support)
14
+ - [Cross-Domain UTM](#cross-domain-utm)
15
+ - [Attribution Data](#attribution-data)
16
+ - [Storage](#storage)
17
+ - [Offline Support](#offline-support)
18
+ - [API Reference](#api-reference)
19
+ - [TypeScript Support](#typescript-support)
20
+ - [Browser Support](#browser-support)
21
+
22
+ ---
23
+
24
+ ## Features
25
+
26
+ | Feature | Description |
27
+ | ------------------------- | ---------------------------------------------------------------- |
28
+ | ๐ŸŽฏ **UTM Tracking** | Automatic capture and storage of UTM parameters from URLs |
29
+ | ๐Ÿ”— **Cross-Domain UTM** | Automatic UTM parameter passing to external links |
30
+ | ๐Ÿ“ฆ **Event Batching** | Efficient batch processing of events with configurable intervals |
31
+ | ๐Ÿ“ด **Offline Support** | Queue events locally when offline, sync when connection restores |
32
+ | ๐Ÿ”„ **SPA Support** | Automatic page view tracking for Single Page Applications |
33
+ | โšก **Immediate Events** | Critical events (purchase, login, signup) sent immediately |
34
+ | ๐Ÿ• **Session Management** | Tracks user sessions with configurable timeout |
35
+ | ๐Ÿงน **Auto Clean UTM** | Removes UTM parameters from URL after capture |
36
+ | ๐Ÿ“„ **Page View Debounce** | Prevents duplicate page view events within configurable interval |
37
+ | ๐Ÿ“ **TypeScript** | Full TypeScript support with type definitions |
38
+
39
+ ---
40
+
41
+ ## Installation
42
+
43
+ ### Via CDN (Recommended)
44
+
45
+ ```html
46
+ <script
47
+ src="https://unpkg.com/getu-attribution-v2-sdk/dist/getuai-attribution.min.js"
48
+ data-api-key="your_api_key_here"
49
+ ></script>
50
+ ```
51
+
52
+ ### Via NPM
53
+
54
+ ```bash
55
+ npm install getu-attribution-v2-sdk
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Quick Start
61
+
62
+ ### Automatic Initialization (CDN)
63
+
64
+ The SDK auto-initializes when loaded with a `data-api-key` attribute:
65
+
66
+ ```html
67
+ <script
68
+ src="https://unpkg.com/getu-attribution-v2-sdk/dist/getuai-attribution.min.js"
69
+ data-api-key="your_api_key_here"
70
+ data-auto-track-page-view="true"
71
+ data-debug="true"
72
+ ></script>
73
+ ```
74
+
75
+ ### Manual Initialization (NPM)
76
+
77
+ ```javascript
78
+ import { init, trackPageView, EventType } from "getu-attribution-v2-sdk";
79
+
80
+ // Initialize SDK
81
+ await init({
82
+ apiKey: "your_api_key_here",
83
+ autoTrackPageView: true,
84
+ enableDebug: true,
85
+ });
86
+
87
+ // Track custom event
88
+ await trackPageView({ category: "homepage" });
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Configuration
94
+
95
+ ### Script Tag Attributes
96
+
97
+ | Attribute | Type | Default | Description |
98
+ | --------------------------- | ------- | --------------------------------------------- | --------------------------------------------- |
99
+ | `data-api-key` | string | **required** | Your GetuAI API key |
100
+ | `data-api-endpoint` | string | `https://attribution.getu.ai/attribution/api` | API endpoint URL |
101
+ | `data-debug` | boolean | `false` | Enable debug logging |
102
+ | `data-auto-track` | boolean | `false` | Enable auto-tracking (forms, links) |
103
+ | `data-auto-track-page-view` | boolean | `false` | Enable auto page view tracking (includes SPA) |
104
+ | `data-batch-size` | number | `100` | Number of events per batch |
105
+ | `data-batch-interval` | number | `5000` | Batch interval in milliseconds |
106
+ | `data-auto-clean-utm` | boolean | `true` | Remove UTM params from URL after capture |
107
+
108
+ ### Configuration Object
109
+
110
+ ```typescript
111
+ interface SDKConfig {
112
+ // Required
113
+ apiKey: string;
114
+
115
+ // API Settings
116
+ apiEndpoint?: string; // Default: "https://attribution.getu.ai/attribution/api"
117
+
118
+ // Batch Settings
119
+ batchSize?: number; // Default: 100
120
+ batchInterval?: number; // Default: 5000 (ms)
121
+ maxRetries?: number; // Default: 3
122
+ retryDelay?: number; // Default: 1000 (ms)
123
+
124
+ // Auto-Tracking
125
+ autoTrack?: boolean; // Default: false - Enable form/link tracking
126
+ autoTrackPageView?: boolean; // Default: false - Enable page view + SPA tracking
127
+
128
+ // Session
129
+ sessionTimeout?: number; // Default: 1800000 (30 minutes in ms)
130
+
131
+ // Cross-Domain UTM
132
+ enableCrossDomainUTM?: boolean; // Default: true
133
+ crossDomainUTMParams?: string[]; // Default: ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"]
134
+ excludeDomains?: string[]; // Default: [] - Domains to exclude from UTM passing
135
+
136
+ // URL Management
137
+ autoCleanUTM?: boolean; // Default: true - Remove UTM from URL after capture
138
+
139
+ // Page View
140
+ pageViewDebounceInterval?: number; // Default: 5000 (ms) - Debounce interval for same page
141
+
142
+ // Debug
143
+ enableDebug?: boolean; // Default: false
144
+ }
145
+ ```
146
+
147
+ ### Full Configuration Example
148
+
149
+ ```javascript
150
+ await init({
151
+ apiKey: "your_api_key_here",
152
+ apiEndpoint: "https://your-api.com/attribution/api",
153
+ batchSize: 50,
154
+ batchInterval: 3000,
155
+ maxRetries: 5,
156
+ retryDelay: 2000,
157
+ autoTrack: true,
158
+ autoTrackPageView: true,
159
+ sessionTimeout: 60 * 60 * 1000, // 1 hour
160
+ enableCrossDomainUTM: true,
161
+ crossDomainUTMParams: ["utm_source", "utm_medium", "utm_campaign"],
162
+ excludeDomains: ["google.com", "facebook.com"],
163
+ autoCleanUTM: true,
164
+ pageViewDebounceInterval: 3000,
165
+ enableDebug: true,
166
+ });
167
+ ```
168
+
169
+ ---
170
+
171
+ ## Event Tracking
172
+
173
+ ### Event Types
174
+
175
+ ```typescript
176
+ enum EventType {
177
+ // Pre-conversion signals
178
+ PAGE_VIEW = "page_view",
179
+ VIDEO_PLAY = "video_play",
180
+
181
+ // Registration funnel
182
+ FORM_SUBMIT = "form_submit",
183
+ EMAIL_VERIFICATION = "email_verification",
184
+
185
+ // Login flow
186
+ LOGIN = "login",
187
+
188
+ // Signup flow
189
+ SIGNUP = "signup",
190
+
191
+ // Purchase funnel
192
+ PRODUCT_VIEW = "product_view",
193
+ ADD_TO_CART = "add_to_cart",
194
+ PURCHASE = "purchase",
195
+ }
196
+ ```
197
+
198
+ ### Immediate Events
199
+
200
+ These events are sent immediately (not batched):
201
+
202
+ - `PURCHASE`
203
+ - `LOGIN`
204
+ - `SIGNUP`
205
+ - `FORM_SUBMIT`
206
+ - `EMAIL_VERIFICATION`
207
+
208
+ ### Track Page View
209
+
210
+ ```javascript
211
+ // Basic
212
+ await trackPageView();
213
+
214
+ // With custom data
215
+ await trackPageView({
216
+ category: "product",
217
+ section: "electronics",
218
+ });
219
+
220
+ // With user ID
221
+ await trackPageView({ category: "dashboard" }, "user_123");
222
+ ```
223
+
224
+ ### Track Purchase
225
+
226
+ ```javascript
227
+ await trackPurchase(
228
+ "user_123", // tracking_user_id
229
+ 99.99, // revenue
230
+ Currency.USD, // currency (optional, default: USD)
231
+ {
232
+ // purchaseData (optional)
233
+ product_id: "prod_123",
234
+ product_name: "Premium Plan",
235
+ quantity: 1,
236
+ }
237
+ );
238
+ ```
239
+
240
+ ### Track Login
241
+
242
+ ```javascript
243
+ await trackLogin("user_123", {
244
+ method: "email",
245
+ provider: "google",
246
+ });
247
+ ```
248
+
249
+ ### Track Signup
250
+
251
+ ```javascript
252
+ await trackSignup("user_123", {
253
+ method: "email",
254
+ referral_code: "REF123",
255
+ });
256
+ ```
257
+
258
+ ### Track Form Submit
259
+
260
+ ```javascript
261
+ await trackFormSubmit("user_123", {
262
+ form_id: "contact_form",
263
+ form_type: "contact",
264
+ });
265
+ ```
266
+
267
+ ### Track Custom Event
268
+
269
+ ```javascript
270
+ await trackEvent(
271
+ EventType.ADD_TO_CART,
272
+ {
273
+ product_id: "prod_123",
274
+ product_name: "Widget",
275
+ price: 29.99,
276
+ quantity: 2,
277
+ },
278
+ "user_123", // tracking_user_id (optional)
279
+ 29.99, // revenue (optional)
280
+ Currency.USD // currency (optional)
281
+ );
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Auto-Tracking
287
+
288
+ ### General Auto-Tracking (`autoTrack`)
289
+
290
+ When `autoTrack: true`, the SDK automatically tracks:
291
+
292
+ #### Form Submissions
293
+
294
+ - Captures all form field values (with password masking)
295
+ - Includes form metadata (id, action, method)
296
+ - Handles checkboxes, radio buttons, multi-select, file inputs
297
+
298
+ #### External Link Clicks
299
+
300
+ - Adds UTM parameters to external links
301
+ - Respects `excludeDomains` configuration
302
+
303
+ ### Page View Auto-Tracking (`autoTrackPageView`)
304
+
305
+ When `autoTrackPageView: true`, the SDK:
306
+
307
+ 1. **Initial Page View**: Tracks page view on SDK initialization
308
+ 2. **SPA Route Changes**: Automatically tracks navigation via:
309
+ - `history.pushState()`
310
+ - `history.replaceState()`
311
+ - Browser back/forward (popstate)
312
+ 3. **Debouncing**: Prevents duplicate tracking within `pageViewDebounceInterval`
313
+
314
+ ---
315
+
316
+ ## SPA Support
317
+
318
+ Single Page Application support is automatically enabled when `autoTrackPageView: true`.
319
+
320
+ ### How It Works
321
+
322
+ ```
323
+ User visits /home
324
+ โ””โ”€โ”€ SDK tracks PAGE_VIEW for /home
325
+
326
+ User clicks link to /products
327
+ โ””โ”€โ”€ React Router calls history.pushState()
328
+ โ””โ”€โ”€ SDK detects route change
329
+ โ””โ”€โ”€ SDK tracks PAGE_VIEW for /products (after 100ms delay for title update)
330
+
331
+ User clicks browser back button
332
+ โ””โ”€โ”€ Browser fires popstate event
333
+ โ””โ”€โ”€ SDK detects route change
334
+ โ””โ”€โ”€ SDK tracks PAGE_VIEW for /home
335
+ ```
336
+
337
+ ### Route Change Detection
338
+
339
+ The SDK intercepts:
340
+
341
+ - `history.pushState()` - Standard navigation
342
+ - `history.replaceState()` - URL replacement
343
+ - `popstate` event - Browser back/forward
344
+
345
+ ### Path Comparison
346
+
347
+ Only tracks when `pathname + search` actually changes:
348
+
349
+ ```javascript
350
+ // These are considered different paths:
351
+ "/products"
352
+ "/products?category=electronics"
353
+ "/products/123"
354
+
355
+ // These are considered the same (no duplicate tracking):
356
+ "/products" -> "/products"
357
+ ```
358
+
359
+ ---
360
+
361
+ ## Cross-Domain UTM
362
+
363
+ ### Automatic UTM Passing
364
+
365
+ When users click external links, UTM parameters are automatically appended:
366
+
367
+ ```
368
+ User visits your site with ?utm_source=google&utm_medium=cpc
369
+ โ””โ”€โ”€ UTM params stored in localStorage
370
+
371
+ User clicks link to https://partner-site.com/page
372
+ โ””โ”€โ”€ SDK modifies link to:
373
+ https://partner-site.com/page?utm_source=google&utm_medium=cpc
374
+ ```
375
+
376
+ ### Configuration
377
+
378
+ ```javascript
379
+ await init({
380
+ apiKey: "your_api_key",
381
+ enableCrossDomainUTM: true, // Default: true
382
+ crossDomainUTMParams: [
383
+ // Which params to pass
384
+ "utm_source",
385
+ "utm_medium",
386
+ "utm_campaign",
387
+ ],
388
+ excludeDomains: [
389
+ // Don't pass UTM to these domains
390
+ "google.com",
391
+ "facebook.com",
392
+ "twitter.com",
393
+ ],
394
+ });
395
+ ```
396
+
397
+ ### Manual UTM Enhancement
398
+
399
+ ```javascript
400
+ // Add UTM to any URL
401
+ const enhancedURL = addUTMToURL("https://example.com/page");
402
+ // Result: "https://example.com/page?utm_source=google&utm_medium=cpc"
403
+
404
+ // Get current UTM parameters
405
+ const utmParams = getCurrentUTMParams();
406
+ // Result: { utm_source: "google", utm_medium: "cpc", utm_campaign: "summer" }
407
+ ```
408
+
409
+ ---
410
+
411
+ ## Attribution Data
412
+
413
+ ### Data Structure
414
+
415
+ ```typescript
416
+ interface AttributionData {
417
+ firstTouch: UTMData; // First attribution touchpoint
418
+ lastTouch: UTMData; // Most recent touchpoint
419
+ touchpoints: UTMData[]; // All touchpoints history
420
+ expiresAt: number; // Expiration timestamp
421
+ }
422
+
423
+ interface UTMData {
424
+ utm_source?: string;
425
+ utm_medium?: string;
426
+ utm_campaign?: string;
427
+ utm_term?: string;
428
+ utm_content?: string;
429
+ timestamp: number;
430
+ }
431
+ ```
432
+
433
+ ### Accessing Attribution Data
434
+
435
+ ```javascript
436
+ const attribution = getAttributionData();
437
+
438
+ if (attribution) {
439
+ console.log("First Touch:", attribution.firstTouch);
440
+ console.log("Last Touch:", attribution.lastTouch);
441
+ console.log("All Touchpoints:", attribution.touchpoints);
442
+ }
443
+ ```
444
+
445
+ ### Touchpoint Recording
446
+
447
+ A new touchpoint is recorded when:
448
+
449
+ - `utm_source` changes, OR
450
+ - `utm_campaign` changes
451
+
452
+ ---
453
+
454
+ ## Storage
455
+
456
+ ### LocalStorage
457
+
458
+ | Key | Content | Retention |
459
+ | ---------------------- | -------------------- | ------------- |
460
+ | `attribution_utm_data` | UTM attribution data | 30 days |
461
+ | `attribution_session` | Session information | Session-based |
462
+
463
+ ### IndexedDB
464
+
465
+ | Store | Content | Retention |
466
+ | -------- | ----------- | --------------------- |
467
+ | `events` | Event queue | 7 days (auto cleanup) |
468
+
469
+ ### Automatic Cleanup
470
+
471
+ - **UTM Data**: Expired data removed on next access
472
+ - **Events**: Old events (>7 days) cleaned up periodically
473
+ - **Quota Exceeded**: Oldest 20% of data removed automatically
474
+
475
+ ---
476
+
477
+ ## Offline Support
478
+
479
+ ### How It Works
480
+
481
+ ```
482
+ User goes offline
483
+ โ””โ”€โ”€ Events queued in IndexedDB
484
+
485
+ User tracks events
486
+ โ””โ”€โ”€ Events stored locally
487
+
488
+ User goes online
489
+ โ””โ”€โ”€ SDK detects connection restore
490
+ โ””โ”€โ”€ Queued events sent to server
491
+
492
+ Page unload
493
+ โ””โ”€โ”€ SDK attempts to flush pending events
494
+ ```
495
+
496
+ ### Retry Strategy
497
+
498
+ - Failed requests retry with exponential backoff
499
+ - Default: 3 retries with 1s base delay
500
+ - Delay: `baseDelay * 2^attemptNumber`
501
+
502
+ ---
503
+
504
+ ## API Reference
505
+
506
+ ### Core Functions
507
+
508
+ #### `init(config: SDKConfig): Promise<AttributionSDK>`
509
+
510
+ Initialize the SDK with configuration.
511
+
512
+ ```javascript
513
+ const sdk = await init({ apiKey: "your_key" });
514
+ ```
515
+
516
+ #### `getSDK(): AttributionSDK | null`
517
+
518
+ Get the current SDK instance.
519
+
520
+ ```javascript
521
+ const sdk = getSDK();
522
+ if (sdk) {
523
+ // SDK is initialized
524
+ }
525
+ ```
526
+
527
+ #### `waitForSDK(): Promise<AttributionSDK>`
528
+
529
+ Wait for SDK initialization (useful with auto-init).
530
+
531
+ ```javascript
532
+ const sdk = await waitForSDK();
533
+ ```
534
+
535
+ ### Event Functions
536
+
537
+ #### `trackEvent(eventType, eventData?, tracking_user_id?, revenue?, currency?): Promise<void>`
538
+
539
+ Track a custom event.
540
+
541
+ #### `trackPageView(pageData?, tracking_user_id?): Promise<void>`
542
+
543
+ Track a page view event.
544
+
545
+ #### `trackPurchase(tracking_user_id, revenue, currency?, purchaseData?): Promise<void>`
546
+
547
+ Track a purchase event (sent immediately).
548
+
549
+ #### `trackLogin(tracking_user_id, loginData?): Promise<void>`
550
+
551
+ Track a login event (sent immediately).
552
+
553
+ #### `trackSignup(tracking_user_id, signupData?): Promise<void>`
554
+
555
+ Track a signup event (sent immediately).
556
+
557
+ #### `trackFormSubmit(tracking_user_id?, formData?): Promise<void>`
558
+
559
+ Track a form submission event (sent immediately).
560
+
561
+ ### Attribution Functions
562
+
563
+ #### `getAttributionData(): AttributionData | null`
564
+
565
+ Get current attribution data.
566
+
567
+ #### `addUTMToURL(url: string): string`
568
+
569
+ Add current UTM parameters to a URL.
570
+
571
+ #### `getCurrentUTMParams(): Record<string, string>`
572
+
573
+ Get current UTM parameters as object.
574
+
575
+ ### Utility Functions
576
+
577
+ #### `flush(): Promise<void>`
578
+
579
+ Flush all pending events to the server.
580
+
581
+ #### `getStatus(): SDKStatus | null`
582
+
583
+ Get SDK status including initialization state, session info, queue size, and SPA tracking status.
584
+
585
+ ```javascript
586
+ const status = getStatus();
587
+ // {
588
+ // initialized: true,
589
+ // session: { sessionId: "...", startTime: ..., lastActivity: ..., pageViews: 0 },
590
+ // queueSize: 5,
591
+ // online: true,
592
+ // crossDomainUTM: {
593
+ // enabled: true,
594
+ // currentParams: { utm_source: "google" }
595
+ // },
596
+ // spaTracking: {
597
+ // enabled: true,
598
+ // currentPath: "/products"
599
+ // }
600
+ // }
601
+ ```
602
+
603
+ #### `destroy(): void`
604
+
605
+ Destroy SDK instance and clean up resources.
606
+
607
+ ---
608
+
609
+ ## Usage Patterns
610
+
611
+ ### Global Window Object (CDN)
612
+
613
+ ```javascript
614
+ // Access via window.getuaiSDK namespace
615
+ await window.getuaiSDK.init({ apiKey: "your_key" });
616
+ await window.getuaiSDK.trackPageView();
617
+ await window.getuaiSDK.trackPurchase("user_123", 99.99);
618
+
619
+ // Access enums
620
+ const eventType = window.getuaiSDK.EventType.PURCHASE;
621
+ const currency = window.getuaiSDK.Currency.USD;
622
+ ```
623
+
624
+ ### Static Methods (Advanced)
625
+
626
+ ```javascript
627
+ import { AttributionSDK, EventType } from "getu-attribution-v2-sdk";
628
+
629
+ // Use static methods
630
+ await AttributionSDK.init({ apiKey: "your_key" });
631
+ await AttributionSDK.trackEvent(EventType.PAGE_VIEW);
632
+ await AttributionSDK.trackPurchase("user_123", 99.99);
633
+
634
+ const attribution = AttributionSDK.getAttributionData();
635
+ const status = AttributionSDK.getStatus();
636
+ ```
637
+
638
+ ### Custom Instance
639
+
640
+ ```javascript
641
+ import { AttributionSDK } from "getu-attribution-v2-sdk";
642
+
643
+ const sdk = new AttributionSDK({
644
+ apiKey: "your_key",
645
+ enableDebug: true,
646
+ });
647
+
648
+ await sdk.init();
649
+ await sdk.trackPageView();
650
+ ```
651
+
652
+ ### Event Listeners
653
+
654
+ ```javascript
655
+ // Listen for SDK ready
656
+ window.addEventListener("getuaiSDKReady", (event) => {
657
+ console.log("SDK initialized:", event.detail.sdk);
658
+ });
659
+
660
+ // Listen for SDK errors
661
+ window.addEventListener("getuaiSDKError", (event) => {
662
+ console.error("SDK error:", event.detail.error);
663
+ });
664
+ ```
665
+
666
+ ---
667
+
668
+ ## TypeScript Support
669
+
670
+ ```typescript
671
+ import {
672
+ init,
673
+ trackEvent,
674
+ EventType,
675
+ Currency,
676
+ type SDKConfig,
677
+ type EventData,
678
+ type AttributionData,
679
+ } from "getu-attribution-v2-sdk";
680
+
681
+ const config: SDKConfig = {
682
+ apiKey: "your_api_key_here",
683
+ enableDebug: true,
684
+ autoTrackPageView: true,
685
+ };
686
+
687
+ await init(config);
688
+
689
+ // Type-safe event tracking
690
+ await trackEvent(
691
+ EventType.PURCHASE,
692
+ { product_id: "123" },
693
+ "user_123",
694
+ 99.99,
695
+ Currency.USD
696
+ );
697
+
698
+ // Type-safe attribution data
699
+ const attribution: AttributionData | null = getAttributionData();
700
+ ```
701
+
702
+ ---
703
+
704
+ ## Browser Support
705
+
706
+ | Browser | Minimum Version |
707
+ | ------- | --------------- |
708
+ | Chrome | 50+ |
709
+ | Firefox | 50+ |
710
+ | Safari | 10+ |
711
+ | Edge | 79+ |
712
+
713
+ ### Required APIs
714
+
715
+ - `localStorage`
716
+ - `IndexedDB`
717
+ - `history.pushState/replaceState`
718
+ - `fetch`
719
+ - `Promise`
720
+
721
+ ---
722
+
723
+ ## Debug Mode
724
+
725
+ Enable debug logging to see detailed SDK activity:
726
+
727
+ ```html
728
+ <!-- Via script tag -->
729
+ <script src="..." data-api-key="your_key" data-debug="true"></script>
730
+ ```
731
+
732
+ ```javascript
733
+ // Via config
734
+ await init({
735
+ apiKey: "your_key",
736
+ enableDebug: true,
737
+ });
738
+ ```
739
+
740
+ ### Console Output Examples
741
+
742
+ ```
743
+ [GetuAI Info] ๐Ÿš€ GetuAI Attribution SDK initialized successfully
744
+ [GetuAI Info] ๐Ÿ“„ Auto track page view enabled (including SPA route tracking)
745
+ [GetuAI Debug] ๐Ÿ”„ [SPA] Route change detected (pushState): /home -> /products
746
+ [GetuAI Debug] โœ… [SPA] Page view tracked for: /products
747
+ [GetuAI Info] UTM data extracted and stored successfully
748
+ ```
749
+
750
+ ---
751
+
752
+ ## Error Handling
753
+
754
+ ```javascript
755
+ try {
756
+ await trackPurchase("user_123", 99.99, Currency.USD, {
757
+ product_id: "prod_123",
758
+ });
759
+ } catch (error) {
760
+ console.error("Failed to track purchase:", error);
761
+ // Event will be queued for retry automatically
762
+ }
763
+ ```
764
+
765
+ Events that fail to send are:
766
+
767
+ 1. Stored in IndexedDB
768
+ 2. Retried with exponential backoff
769
+ 3. Sent when connection restores
770
+
771
+ ---
772
+
773
+ ## License
774
+
775
+ MIT