cryptique-sdk 1.0.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,3580 @@
1
+ # Cryptique Analytics SDK - Function Reference Guide
2
+
3
+ This document provides a comprehensive reference for all functions in the modular Cryptique SDK. Use this guide to understand the logic, purpose, and when to reuse functions.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Architecture Overview](#architecture-overview)
10
+ 2. [Section 1: Configuration](#section-1-configuration)
11
+ 3. [Section 2: Storage Management](#section-2-storage-management)
12
+ 4. [Section 3: Session ID Management](#section-3-session-id-management)
13
+ 5. [Utility Functions](#utility-functions)
14
+
15
+ ---
16
+
17
+ ## Architecture Overview
18
+
19
+ The SDK is organized into modular sections, each with a single source of truth. This prevents conflicts, duplicate code, and makes it easy to find and reuse functions.
20
+
21
+ ### Key Principles:
22
+ - **Single Source of Truth**: Only one function handles each responsibility
23
+ - **Modular Design**: Each section is independent and can be understood separately
24
+ - **Clear Data Flow**: Functions have defined inputs/outputs
25
+ - **Error Handling**: Centralized error handling in each section
26
+
27
+ ---
28
+
29
+ ## Section 1: Configuration
30
+
31
+ ### Purpose
32
+ Centralizes all constants, API URLs, storage keys, and configuration values in one place.
33
+
34
+ ### Why It Matters
35
+ - Easy to update URLs/keys without searching through code
36
+ - Prevents typos and inconsistencies
37
+ - Makes it clear what can be configured
38
+ - Single place to change environment (dev/prod)
39
+
40
+ ### Configuration Object: `CONFIG`
41
+
42
+ ```javascript
43
+ CONFIG.API.TRACK // Main session tracking endpoint
44
+ CONFIG.API.OVERVIEW // Overview/analytics data endpoint
45
+ CONFIG.API.CUSTOM_EVENTS // Custom event tracking endpoint
46
+ CONFIG.API.UTM_EVENTS // UTM campaign tracking endpoint
47
+
48
+ CONFIG.VERSION // SDK version string
49
+
50
+ CONFIG.STORAGE_KEYS.SESSION // Primary session storage key
51
+ CONFIG.STORAGE_KEYS.USER_ID // User ID storage key
52
+ CONFIG.STORAGE_KEYS.CONSENT // Consent flag storage key
53
+
54
+ CONFIG.SESSION.TIMEOUT_MS // Session timeout (30 minutes)
55
+ CONFIG.SESSION.BACKUP_VALIDITY_MS // Backup validity (5 minutes)
56
+ CONFIG.SESSION.BOUNCE_THRESHOLD_SECONDS // Bounce threshold (30 seconds)
57
+
58
+ CONFIG.INTERVALS.SESSION_TRACKING_MS // Session update interval (5 seconds)
59
+ CONFIG.INTERVALS.OVERVIEW_DEBOUNCE_MS // Overview debounce (10 seconds)
60
+ ```
61
+
62
+ ### When to Use
63
+ - **Accessing API URLs**: Use `CONFIG.API.*` instead of hardcoding URLs
64
+ - **Accessing Storage Keys**: Use `CONFIG.STORAGE_KEYS.*` instead of string literals
65
+ - **Session Configuration**: Use `CONFIG.SESSION.*` for timeout and validity checks
66
+ - **Changing Environment**: Update `CONFIG` object to switch between dev/prod
67
+
68
+ ### Reusability
69
+ ✅ **Highly Reusable**: Import or reference `CONFIG` anywhere you need configuration values.
70
+
71
+ ---
72
+
73
+ ## Section 2: Storage Management
74
+
75
+ ### Purpose
76
+ Single source of truth for ALL storage operations (localStorage, sessionStorage). Prevents conflicts and ensures consistency.
77
+
78
+ ### Why It Matters
79
+ - Prevents storage conflicts (multiple functions writing different formats)
80
+ - Centralized error handling
81
+ - Easy to debug storage issues
82
+ - Can add features (encryption, compression) in one place
83
+
84
+ ### StorageManager Object
85
+
86
+ #### `StorageManager.loadSession()`
87
+ **Purpose**: Load session from sessionStorage with localStorage backup fallback.
88
+
89
+ **Logic Flow**:
90
+ 1. Try sessionStorage first (primary source)
91
+ 2. If found, update localStorage backup
92
+ 3. If not found, try localStorage backup
93
+ 4. If backup is recent (< 5 min), restore it
94
+ 5. Return session or null
95
+
96
+ **When to Use**:
97
+ - Loading existing session on page load
98
+ - Checking if session exists
99
+ - Recovering session after tab close
100
+
101
+ **Returns**: Session object with `{id, userId, lastActivity}` or `null`
102
+
103
+ **Example**:
104
+ ```javascript
105
+ const session = StorageManager.loadSession();
106
+ if (session) {
107
+ console.log('Session found:', session.id);
108
+ }
109
+ ```
110
+
111
+ ---
112
+
113
+ #### `StorageManager.saveSession(session)`
114
+ **Purpose**: Save session to both sessionStorage and localStorage backup.
115
+
116
+ **Logic**:
117
+ - Saves to sessionStorage (primary, fast, tab-specific)
118
+ - Also saves to localStorage (backup, survives tab close)
119
+ - Ensures we never lose session data
120
+
121
+ **When to Use**:
122
+ - After creating new session
123
+ - After updating session data
124
+ - After session activity updates
125
+
126
+ **Parameters**: `session` - Session object with `{id, userId, lastActivity, ...}`
127
+
128
+ **Example**:
129
+ ```javascript
130
+ const session = {
131
+ id: 'session-id',
132
+ userId: 'user-id',
133
+ lastActivity: Date.now()
134
+ };
135
+ StorageManager.saveSession(session);
136
+ ```
137
+
138
+ ---
139
+
140
+ #### `StorageManager.updateBackup(session)`
141
+ **Purpose**: Update localStorage backup (called automatically by `saveSession`).
142
+
143
+ **Logic**:
144
+ - Creates lightweight backup with essential data only
145
+ - Stores: sessionId, userId, timestamp
146
+ - Used for session recovery across tabs
147
+
148
+ **When to Use**:
149
+ - Usually called automatically by `saveSession`
150
+ - Can be called manually if you only want to update backup
151
+
152
+ **Parameters**: `session` - Session object
153
+
154
+ ---
155
+
156
+ #### `StorageManager.getUserId()`
157
+ **Purpose**: Get or create persistent user ID.
158
+
159
+ **Logic**:
160
+ - Checks localStorage for existing user ID
161
+ - If not found, generates new ID: `"usr_" + random string`
162
+ - Stores in localStorage (survives browser restarts)
163
+
164
+ **When to Use**:
165
+ - Initializing user session
166
+ - Tracking user across sessions
167
+ - User-level analytics
168
+
169
+ **Returns**: User ID string (e.g., `"usr_abc123xyz"`)
170
+
171
+ **Example**:
172
+ ```javascript
173
+ const userId = StorageManager.getUserId();
174
+ // Always returns same ID for same user
175
+ ```
176
+
177
+ ---
178
+
179
+ #### `StorageManager.getConsent()` / `StorageManager.setConsent(consent)`
180
+ **Purpose**: Get/set user consent status for GDPR/privacy compliance.
181
+
182
+ **Logic**:
183
+ - Stores consent flag in localStorage
184
+ - Returns `true` if consent given, `false` otherwise
185
+ - Defaults to `false` if storage fails
186
+
187
+ **When to Use**:
188
+ - Checking if tracking is allowed
189
+ - Storing user consent preference
190
+ - Privacy compliance
191
+
192
+ **Example**:
193
+ ```javascript
194
+ if (StorageManager.getConsent()) {
195
+ // User has consented, proceed with tracking
196
+ } else {
197
+ // Show consent banner
198
+ }
199
+
200
+ // User gives consent
201
+ StorageManager.setConsent(true);
202
+ ```
203
+
204
+ ---
205
+
206
+ #### `StorageManager.getReferrer()` / `StorageManager.saveReferrer(referrer)`
207
+ **Purpose**: Get/set stored referrer (falls back to `document.referrer`).
208
+
209
+ **Logic**:
210
+ - Stores referrer in localStorage
211
+ - Falls back to `document.referrer` if not stored
212
+ - Falls back to `"direct"` if no referrer
213
+
214
+ **Why Store**:
215
+ - `document.referrer` can be lost on navigation
216
+ - We want to track original referrer for entire session
217
+
218
+ **When to Use**:
219
+ - Getting referrer for session tracking
220
+ - Storing referrer on first page visit
221
+ - Traffic source analysis
222
+
223
+ **Example**:
224
+ ```javascript
225
+ const referrer = StorageManager.getReferrer();
226
+ // Returns stored referrer or document.referrer or "direct"
227
+
228
+ StorageManager.saveReferrer("google.com");
229
+ // Stores referrer for future use
230
+ ```
231
+
232
+ ---
233
+
234
+ #### `StorageManager.acquireLock(name, ttl)`
235
+ **Purpose**: Acquire a lock to prevent race conditions.
236
+
237
+ **Logic**:
238
+ - Stores timestamp in localStorage with key `"lock_{name}"`
239
+ - If lock exists and is recent (< TTL), return `false` (locked)
240
+ - Otherwise, set lock and return `true` (acquired)
241
+ - Locks expire automatically after TTL
242
+
243
+ **When to Use**:
244
+ - Preventing multiple functions from creating sessions simultaneously
245
+ - Preventing duplicate API calls
246
+ - Preventing concurrent initialization
247
+
248
+ **Parameters**:
249
+ - `name`: Lock name (e.g., `'session_creation'`)
250
+ - `ttl`: Time to live in milliseconds (default: 500ms)
251
+
252
+ **Returns**: `true` if lock acquired, `false` if already locked
253
+
254
+ **Example**:
255
+ ```javascript
256
+ if (StorageManager.acquireLock('session_creation')) {
257
+ // Only one function can execute this block at a time
258
+ createSession();
259
+ StorageManager.releaseLock('session_creation'); // Optional
260
+ }
261
+ ```
262
+
263
+ ---
264
+
265
+ #### `StorageManager.releaseLock(name)`
266
+ **Purpose**: Release a lock (optional - locks expire automatically).
267
+
268
+ **When to Use**:
269
+ - Explicitly releasing lock before TTL expires
270
+ - Usually not needed (locks expire automatically)
271
+
272
+ ---
273
+
274
+ #### `StorageManager.saveLastSession(sessionData)` / `StorageManager.getLastSession()`
275
+ **Purpose**: Save/get last session as backup for recovery on next page load.
276
+
277
+ **Logic**:
278
+ - Saves full session data to localStorage
279
+ - Used as last-resort backup if all other methods fail
280
+ - Can be retrieved on next page load
281
+
282
+ **When to Use**:
283
+ - Before page unload (as backup)
284
+ - On page load (to recover lost session)
285
+ - Error recovery scenarios
286
+
287
+ ---
288
+
289
+ #### `StorageManager.clearAll()`
290
+ **Purpose**: Clear all SDK storage (useful for testing/reset).
291
+
292
+ **Logic**:
293
+ - Removes session, backup, and last session
294
+ - Does NOT clear USER_ID or CONSENT (persistent preferences)
295
+
296
+ **When to Use**:
297
+ - Testing/debugging
298
+ - User logout
299
+ - Privacy reset
300
+
301
+ ---
302
+
303
+ #### `StorageManager.updateSessionActivity(session)`
304
+ **Purpose**: Update session activity timestamp.
305
+
306
+ **Logic**:
307
+ - Updates `sessionData.lastActivity = Date.now()`
308
+ - If session provided, updates that session object and saves it
309
+ - If no session provided, loads current session and updates it
310
+ - Saves updated session to storage
311
+
312
+ **Parameters**: `session` (optional) - Session object to update. If not provided, loads current session.
313
+
314
+ **Returns**: Current timestamp (Date.now())
315
+
316
+ **When to Use**:
317
+ - When tracking user activity (page visits, interactions, etc.)
318
+ - To keep session alive
319
+ - Called automatically by various managers
320
+
321
+ **Example**:
322
+ ```javascript
323
+ StorageManager.updateSessionActivity();
324
+ // Updates lastActivity and saves to storage
325
+ ```
326
+
327
+ ---
328
+
329
+ ### Reusability
330
+ ✅ **Highly Reusable**: All storage operations should go through `StorageManager`. Never access `localStorage` or `sessionStorage` directly.
331
+
332
+ ---
333
+
334
+ ## Section 3: Session ID Management
335
+
336
+ ### Purpose
337
+ Single source of truth for session ID creation, retrieval, and management. Prevents duplicate sessions and ensures session continuity.
338
+
339
+ ### Why It Matters
340
+ - Prevents duplicate session IDs
341
+ - Ensures session continuity across page navigation
342
+ - Handles edge cases (fast navigation, multiple tabs, storage failures)
343
+ - Single place to fix session ID bugs
344
+
345
+ ### SessionIdManager Object
346
+
347
+ #### `SessionIdManager.generate()`
348
+ **Purpose**: Generate a new UUID v4 session ID.
349
+
350
+ **Logic**:
351
+ - Creates UUID v4 format: `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`
352
+ - '4' indicates version 4 (random)
353
+ - 'y' is one of 8, 9, A, or B
354
+ - Guaranteed unique (collision-resistant)
355
+
356
+ **When to Use**:
357
+ - Creating new session (called internally by `getOrCreate()`)
358
+ - Should NOT be called directly - use `getOrCreate()` instead
359
+
360
+ **Returns**: UUID v4 string
361
+
362
+ **Example**:
363
+ ```javascript
364
+ // Don't call directly - use getOrCreate() instead
365
+ const sessionId = SessionIdManager.getOrCreate();
366
+ ```
367
+
368
+ ---
369
+
370
+ #### `SessionIdManager.isSessionValid(session)`
371
+ **Purpose**: Check if a session is still valid (not expired).
372
+
373
+ **Logic**:
374
+ - Session is valid if:
375
+ - `lastActivity` exists AND is less than 5 minutes ago
376
+ - OR `lastActivity` doesn't exist (new session format)
377
+ - Uses `CONFIG.SESSION.TIMEOUT_MS` (30 minutes) for timeout check
378
+
379
+ **When to Use**:
380
+ - Before reusing existing session
381
+ - Checking if session should be expired
382
+ - Validating session before use
383
+
384
+ **Parameters**: `session` - Session object with `lastActivity` property
385
+
386
+ **Returns**: `true` if valid, `false` if expired
387
+
388
+ **Example**:
389
+ ```javascript
390
+ const session = StorageManager.loadSession();
391
+ if (SessionIdManager.isSessionValid(session)) {
392
+ // Session is still active
393
+ } else {
394
+ // Session expired, create new one
395
+ }
396
+ ```
397
+
398
+ ---
399
+
400
+ #### `SessionIdManager.updateActivity(session)`
401
+ **Purpose**: Update session activity timestamp to keep session alive.
402
+
403
+ **Logic**:
404
+ - Sets `session.lastActivity` to current timestamp
405
+ - Saves session to storage
406
+ - Called when session is reused
407
+
408
+ **When to Use**:
409
+ - After reusing existing session
410
+ - After user activity
411
+ - To prevent session expiration
412
+
413
+ **Parameters**: `session` - Session object
414
+
415
+ **Returns**: Current timestamp (number)
416
+
417
+ **Example**:
418
+ ```javascript
419
+ const session = StorageManager.loadSession();
420
+ SessionIdManager.updateActivity(session);
421
+ // Session activity updated, session stays alive
422
+ ```
423
+
424
+ ---
425
+
426
+ #### `SessionIdManager.getOrCreate()`
427
+ **Purpose**: Get existing session ID or create new one - THE SINGLE SOURCE OF TRUTH.
428
+
429
+ **Logic Flow**:
430
+ 1. Ensure we have user ID first
431
+ 2. Try to load existing session (with retries for fast navigation)
432
+ 3. If found, check if it's still valid (< 5 min inactivity)
433
+ 4. If valid, reuse it and update activity
434
+ 5. If expired or not found, do final checks (with delays)
435
+ 6. If still not found, create new session
436
+ 7. Verify it was saved correctly
437
+
438
+ **Key Features**:
439
+ - Retry logic handles fast page navigation (up to 3 attempts)
440
+ - Final checks with delays (up to 5 attempts, 10ms between)
441
+ - Multiple fallbacks: sessionStorage → localStorage → generate new
442
+ - Verification ensures session was saved correctly
443
+
444
+ **When to Use**:
445
+ - **ONLY function that should create session IDs**
446
+ - On page load to get/create session
447
+ - When you need to ensure session exists
448
+ - Never call `generate()` directly - always use this
449
+
450
+ **Returns**: Session ID string (UUID v4)
451
+
452
+ **Example**:
453
+ ```javascript
454
+ // This is the ONLY way to get/create session ID
455
+ const sessionId = SessionIdManager.getOrCreate();
456
+ sessionData.sessionId = sessionId;
457
+ ```
458
+
459
+ ---
460
+
461
+ #### `SessionIdManager.syncFromStorage()`
462
+ **Purpose**: Sync session ID from storage if there's a mismatch.
463
+
464
+ **Logic**:
465
+ - Loads session from storage
466
+ - If storage has different ID than `sessionData.sessionId`, sync it
467
+ - Fixes inconsistencies between memory and storage
468
+
469
+ **When to Use**:
470
+ - When you suspect session ID mismatch
471
+ - After loading session from storage
472
+ - To fix inconsistencies
473
+
474
+ **Returns**: `true` if synced, `false` if no sync needed
475
+
476
+ **Example**:
477
+ ```javascript
478
+ if (SessionIdManager.syncFromStorage()) {
479
+ console.log('Session ID synced from storage');
480
+ }
481
+ ```
482
+
483
+ ---
484
+
485
+ #### `SessionIdManager.initialize()`
486
+ **Purpose**: Initialize session data with session ID.
487
+
488
+ **Logic**:
489
+ - Calls `getOrCreate()` to get/create session ID
490
+ - Sets `sessionData.sessionId` and `userSession.sessionId`
491
+ - Ensures session ID is never null/undefined
492
+ - Has fallbacks if initialization fails
493
+
494
+ **When to Use**:
495
+ - On SDK initialization
496
+ - When you need to ensure session is initialized
497
+ - Usually called by `initSessionOnce()`
498
+
499
+ **Example**:
500
+ ```javascript
501
+ SessionIdManager.initialize();
502
+ // sessionData.sessionId is now set
503
+ ```
504
+
505
+ ---
506
+
507
+ ### Initialization Guard: `initSessionOnce()`
508
+
509
+ #### `initSessionOnce()`
510
+ **Purpose**: Initialize session once - prevents race conditions and duplicate initialization.
511
+
512
+ **Logic**:
513
+ - Uses lock mechanism to ensure only one initialization happens
514
+ - Checks if already initialized
515
+ - If locked, waits and retries
516
+ - Ensures session ID is set before returning
517
+
518
+ **When to Use**:
519
+ - On SDK startup
520
+ - Should be called before any tracking begins
521
+ - Prevents multiple initializations in multiple tabs
522
+
523
+ **Example**:
524
+ ```javascript
525
+ initSessionOnce();
526
+ // Session is now initialized, safe to start tracking
527
+ ```
528
+
529
+ ---
530
+
531
+ ### Utility Functions (Used by Session ID Management)
532
+
533
+ #### `retryWithDelay(fn, maxAttempts, delayMs)`
534
+ **Purpose**: Retry a function with delays between attempts.
535
+
536
+ **Logic**:
537
+ - Calls function up to `maxAttempts` times
538
+ - Waits `delayMs` milliseconds between attempts
539
+ - Returns first successful result
540
+ - Returns `null` if all attempts fail
541
+
542
+ **When to Use**:
543
+ - Handling timing issues during fast page navigation
544
+ - Retrying storage operations
545
+ - Any operation that might fail due to timing
546
+
547
+ **Parameters**:
548
+ - `fn`: Function to retry (should return truthy value on success)
549
+ - `maxAttempts`: Maximum number of attempts (default: 3)
550
+ - `delayMs`: Delay between attempts in milliseconds (default: 5)
551
+
552
+ **Returns**: Result from function or `null`
553
+
554
+ **Example**:
555
+ ```javascript
556
+ const session = retryWithDelay(() => {
557
+ return StorageManager.loadSession();
558
+ }, 3, 5);
559
+ ```
560
+
561
+ ---
562
+
563
+ #### `ensureArray(value, defaultValue)`
564
+ **Purpose**: Ensure value is an array, return default if not.
565
+
566
+ **When to Use**:
567
+ - Normalizing data that might be array or not
568
+ - Ensuring arrays exist before operations
569
+
570
+ **Returns**: Array (original or default)
571
+
572
+ **Example**:
573
+ ```javascript
574
+ const visits = ensureArray(sessionData.pageVisits, []);
575
+ // visits is guaranteed to be an array
576
+ ```
577
+
578
+ ---
579
+
580
+ #### `ensureObject(value, defaultValue)`
581
+ **Purpose**: Ensure value is an object, return default if not.
582
+
583
+ **When to Use**:
584
+ - Normalizing data that might be object or not
585
+ - Ensuring objects exist before operations
586
+
587
+ **Returns**: Object (original or default)
588
+
589
+ **Example**:
590
+ ```javascript
591
+ const data = ensureObject(rawData, {});
592
+ // data is guaranteed to be an object
593
+ ```
594
+
595
+ ---
596
+
597
+ #### `nowIso()`
598
+ **Purpose**: Get ISO timestamp string.
599
+
600
+ **Returns**: ISO 8601 timestamp string (e.g., `"2024-01-15T10:30:00.000Z"`)
601
+
602
+ **When to Use**:
603
+ - Storing timestamps in ISO format
604
+ - Normalizing timestamps
605
+ - API payloads requiring ISO format
606
+
607
+ **Example**:
608
+ ```javascript
609
+ const timestamp = nowIso();
610
+ // "2024-01-15T10:30:00.000Z"
611
+ ```
612
+
613
+ ---
614
+
615
+ #### `getUTMParameters()`
616
+ **Purpose**: Extract UTM parameters from URL.
617
+
618
+ **Returns**: Object with UTM parameters:
619
+ ```javascript
620
+ {
621
+ source: 'google',
622
+ medium: 'cpc',
623
+ campaign: 'summer_sale',
624
+ term: 'keyword',
625
+ content: 'ad_variant',
626
+ utm_id: '12345'
627
+ }
628
+ ```
629
+
630
+ **When to Use**:
631
+ - Tracking campaign sources
632
+ - Session initialization
633
+ - UTM event logging
634
+
635
+ **Example**:
636
+ ```javascript
637
+ const utmData = getUTMParameters();
638
+ if (utmData.source) {
639
+ console.log('User came from:', utmData.source);
640
+ }
641
+ ```
642
+
643
+ ---
644
+
645
+ #### `getProperReferrer()`
646
+ **Purpose**: Get referrer, prioritizing UTM source over document.referrer.
647
+
648
+ **Logic**:
649
+ - If UTM source exists, return it
650
+ - Otherwise, return stored referrer or document.referrer or "direct"
651
+
652
+ **When to Use**:
653
+ - Session initialization
654
+ - Traffic source tracking
655
+ - When you need the best referrer value
656
+
657
+ **Returns**: Referrer string
658
+
659
+ **Example**:
660
+ ```javascript
661
+ const referrer = getProperReferrer();
662
+ // Returns UTM source if available, otherwise stored/browser referrer
663
+ ```
664
+
665
+ ---
666
+
667
+ ### Reusability
668
+
669
+ ✅ **SessionIdManager.getOrCreate()**: **MUST USE** - This is the ONLY function that should create session IDs. Never call `generate()` directly.
670
+
671
+ ✅ **SessionIdManager.isSessionValid()**: Reusable for checking session validity anywhere.
672
+
673
+ ✅ **Utility Functions**: All utility functions are reusable across the SDK.
674
+
675
+ ---
676
+
677
+ ## Data Structures
678
+
679
+ ### `sessionData`
680
+ Minimal structure for Session ID Management:
681
+ ```javascript
682
+ {
683
+ sessionId: null, // Set by SessionIdManager
684
+ siteId: string,
685
+ userId: null, // Set from StorageManager
686
+ referrer: "direct",
687
+ utmData: {},
688
+ startTime: null,
689
+ lastActivity: null,
690
+ isFirstPage: true
691
+ }
692
+ ```
693
+
694
+ ### `userSession`
695
+ Synced with sessionData:
696
+ ```javascript
697
+ {
698
+ sessionId: null, // Synced with sessionData.sessionId
699
+ userId: null // Synced with sessionData.userId
700
+ }
701
+ ```
702
+
703
+ ---
704
+
705
+ ## Best Practices
706
+
707
+ ### ✅ DO:
708
+ - Use `StorageManager` for all storage operations
709
+ - Use `SessionIdManager.getOrCreate()` to get/create session IDs
710
+ - Use `CONFIG` for all configuration values
711
+ - Use `initSessionOnce()` before starting tracking
712
+ - Check `SessionIdManager.isSessionValid()` before reusing sessions
713
+
714
+ ### ❌ DON'T:
715
+ - Don't access `localStorage` or `sessionStorage` directly
716
+ - Don't call `SessionIdManager.generate()` directly
717
+ - Don't create session IDs in multiple places
718
+ - Don't hardcode storage keys or API URLs
719
+ - Don't skip initialization guard
720
+
721
+ ---
722
+
723
+ ## Quick Reference
724
+
725
+ ### Getting Session ID
726
+ ```javascript
727
+ const sessionId = SessionIdManager.getOrCreate();
728
+ ```
729
+
730
+ ### Loading Session
731
+ ```javascript
732
+ const session = StorageManager.loadSession();
733
+ ```
734
+
735
+ ### Saving Session
736
+ ```javascript
737
+ StorageManager.saveSession(session);
738
+ ```
739
+
740
+ ### Getting User ID
741
+ ```javascript
742
+ const userId = StorageManager.getUserId();
743
+ ```
744
+
745
+ ### Checking Consent
746
+ ```javascript
747
+ if (StorageManager.getConsent()) {
748
+ // User consented
749
+ }
750
+ ```
751
+
752
+ ### Acquiring Lock
753
+ ```javascript
754
+ if (StorageManager.acquireLock('operation_name')) {
755
+ // Do operation
756
+ StorageManager.releaseLock('operation_name');
757
+ }
758
+ ```
759
+
760
+ ---
761
+
762
+ ## Section 4: Session Duration Calculation
763
+
764
+ ### Purpose
765
+ Single source of truth for session duration calculations. Ensures accurate session duration tracking and consistency between page durations and session duration.
766
+
767
+ ### Why It Matters
768
+ - Prevents inaccurate session times
769
+ - Ensures consistency between page and session data
770
+ - Proper bounce detection
771
+ - Single place to fix duration bugs
772
+
773
+ ### DurationManager Object
774
+
775
+ #### `DurationManager.calculateSeconds(startTime, endTime)`
776
+ **Purpose**: Calculate duration in seconds between two timestamps (rounded).
777
+
778
+ **Logic**:
779
+ - Converts timestamps to Date objects
780
+ - Calculates difference in milliseconds
781
+ - Converts to seconds
782
+ - Rounds to nearest second
783
+
784
+ **When to Use**:
785
+ - General duration calculations where rounding is acceptable
786
+ - Session duration from start time
787
+
788
+ **Parameters**:
789
+ - `startTime`: Start timestamp (Date object or string/number)
790
+ - `endTime`: End timestamp (optional, defaults to current time)
791
+
792
+ **Returns**: Duration in seconds (rounded)
793
+
794
+ **Example**:
795
+ ```javascript
796
+ const duration = DurationManager.calculateSeconds(sessionData.startTime);
797
+ // Returns rounded duration in seconds
798
+ ```
799
+
800
+ ---
801
+
802
+ #### `DurationManager.calculateSecondsFloor(startTime, endTime)`
803
+ **Purpose**: Calculate duration in seconds between two timestamps (floored).
804
+
805
+ **Logic**: Same as `calculateSeconds()` but uses `Math.floor()` instead of `Math.round()`
806
+
807
+ **When to Use**:
808
+ - Page durations (more conservative, prevents over-counting)
809
+ - When you need exact seconds without rounding up
810
+
811
+ **Returns**: Duration in seconds (floored)
812
+
813
+ **Example**:
814
+ ```javascript
815
+ const pageDuration = DurationManager.calculateSecondsFloor(page.mountTime, page.unmountTime);
816
+ // Returns floored duration in seconds
817
+ ```
818
+
819
+ ---
820
+
821
+ #### `DurationManager.calculateFromPages(pageVisits)`
822
+ **Purpose**: Calculate session duration from page mount/unmount times (PREFERRED METHOD).
823
+
824
+ **Logic**:
825
+ 1. Get first page `mountTime` (session start)
826
+ 2. Get last page `unmountTime` or current time (session end)
827
+ 3. Calculate: `endTime - startTime`
828
+
829
+ **When to Use**:
830
+ - When you have page visit data with mount/unmount times
831
+ - Most accurate calculation method
832
+
833
+ **Parameters**: `pageVisits` - Array of page visit objects with `mountTime` and `unmountTime`
834
+
835
+ **Returns**: Duration in seconds or `null` if can't calculate
836
+
837
+ **Example**:
838
+ ```javascript
839
+ const duration = DurationManager.calculateFromPages(sessionData.pageVisits);
840
+ if (duration !== null) {
841
+ // Successfully calculated from page times
842
+ }
843
+ ```
844
+
845
+ ---
846
+
847
+ #### `DurationManager.updateSessionDuration(pageVisits, startTime)`
848
+ **Purpose**: Update `sessionData.duration` - THE SINGLE SOURCE OF TRUTH.
849
+
850
+ **Logic**:
851
+ 1. Try to calculate from page mount/unmount times (preferred)
852
+ 2. If that fails, calculate from session start time (fallback)
853
+ 3. Update `sessionData.duration`
854
+ 4. Return duration
855
+
856
+ **When to Use**:
857
+ - **ONLY function that should modify sessionData.duration**
858
+ - Whenever you need to update session duration
859
+ - Before sending data to backend
860
+
861
+ **Parameters**:
862
+ - `pageVisits`: Optional, defaults to `sessionData.pageVisits`
863
+ - `startTime`: Optional, defaults to `sessionData.startTime`
864
+
865
+ **Returns**: Duration in seconds
866
+
867
+ **Example**:
868
+ ```javascript
869
+ // This is the ONLY way to update session duration
870
+ const duration = DurationManager.updateSessionDuration();
871
+ sessionData.duration = duration; // Already set by function
872
+ ```
873
+
874
+ ---
875
+
876
+ #### `DurationManager.calculateAllPageDurations(pageVisits, currentTime)`
877
+ **Purpose**: Calculate duration for all pages in the session.
878
+
879
+ **Logic for each page**:
880
+ 1. If has `mountTime` and `unmountTime`: use mount→unmount
881
+ 2. If has `mountTime` but no `unmountTime`: use mount→current
882
+ 3. If no `mountTime`: use timestamp fallback
883
+ 4. If no data: use minimum 1 second
884
+
885
+ **When to Use**:
886
+ - When you need to calculate/update all page durations
887
+ - Before aligning page durations with session duration
888
+ - On page navigation
889
+
890
+ **Parameters**:
891
+ - `pageVisits`: Array of page visit objects
892
+ - `currentTime`: Optional, defaults to `Date.now()`
893
+
894
+ **Returns**: Array of page visits with calculated durations
895
+
896
+ **Example**:
897
+ ```javascript
898
+ const updatedPageVisits = DurationManager.calculateAllPageDurations(sessionData.pageVisits);
899
+ sessionData.pageVisits = updatedPageVisits;
900
+ ```
901
+
902
+ ---
903
+
904
+ #### `DurationManager.alignPageDurations(pageVisits, sessionDuration)`
905
+ **Purpose**: Ensure sum of page durations matches session duration exactly.
906
+
907
+ **Logic**:
908
+ 1. Sum all page durations
909
+ 2. Compare sum to session duration
910
+ 3. If different, adjust last page duration by the difference
911
+ 4. Ensure minimum 1 second
912
+
913
+ **When to Use**:
914
+ - Before sending data to backend (ensures consistency)
915
+ - After calculating session duration
916
+ - To fix discrepancies between page and session durations
917
+
918
+ **Parameters**:
919
+ - `pageVisits`: Array of page visit objects
920
+ - `sessionDuration`: Target session duration in seconds
921
+
922
+ **Returns**: Updated page visits array
923
+
924
+ **Example**:
925
+ ```javascript
926
+ const alignedPageVisits = DurationManager.alignPageDurations(
927
+ sessionData.pageVisits,
928
+ sessionData.duration
929
+ );
930
+ sessionData.pageVisits = alignedPageVisits;
931
+ ```
932
+
933
+ ---
934
+
935
+ #### `DurationManager.calculateBounceStatus(duration, pagesViewed)`
936
+ **Purpose**: Determine if session is a bounce.
937
+
938
+ **Logic**:
939
+ - Bounce = duration < 30 seconds AND pagesViewed <= 1
940
+ - Uses `CONFIG.SESSION.BOUNCE_THRESHOLD_SECONDS` (30 seconds)
941
+
942
+ **When to Use**:
943
+ - When you need to check if session is a bounce
944
+ - Before sending data to backend
945
+ - For bounce rate calculations
946
+
947
+ **Parameters**:
948
+ - `duration`: Session duration in seconds
949
+ - `pagesViewed`: Number of pages viewed
950
+
951
+ **Returns**: `true` if bounce, `false` if not
952
+
953
+ **Example**:
954
+ ```javascript
955
+ const isBounce = DurationManager.calculateBounceStatus(
956
+ sessionData.duration,
957
+ sessionData.pagesViewed
958
+ );
959
+ sessionData.isBounce = isBounce;
960
+ ```
961
+
962
+ ---
963
+
964
+ #### `DurationManager.ensureValid(duration)`
965
+ **Purpose**: Ensure duration is always a valid number.
966
+
967
+ **Logic**:
968
+ - Converts to number
969
+ - If null, undefined, NaN, or <= 0: return 1 (minimum)
970
+ - Otherwise: return floored value
971
+
972
+ **When to Use**:
973
+ - Before using duration values
974
+ - When validating duration data
975
+ - To prevent invalid durations
976
+
977
+ **Parameters**: `duration` - Duration value (any type)
978
+
979
+ **Returns**: Valid duration number (minimum 1 second)
980
+
981
+ **Example**:
982
+ ```javascript
983
+ const validDuration = DurationManager.ensureValid(page.duration);
984
+ // Always returns valid number (minimum 1)
985
+ ```
986
+
987
+ ---
988
+
989
+ ### Calculation Methods
990
+
991
+ #### Method A: From Page Mount/Unmount Times (Preferred)
992
+ - **Uses**: `mountTime` and `unmountTime` of pages
993
+ - **Accuracy**: Most accurate
994
+ - **Logic**: `lastPage.unmountTime - firstPage.mountTime`
995
+ - **When**: If page visits have `mountTime` data
996
+
997
+ #### Method B: From Session Start Time (Fallback)
998
+ - **Uses**: `sessionData.startTime` and current time
999
+ - **Accuracy**: Less accurate (includes navigation time)
1000
+ - **Logic**: `currentTime - startTime`
1001
+ - **When**: If no page mount/unmount times available
1002
+
1003
+ ### Key Principles
1004
+
1005
+ 1. **Single Source of Truth**: Only `updateSessionDuration()` modifies `sessionData.duration`
1006
+ 2. **Preferred Method**: Use page mount/unmount times when available
1007
+ 3. **Fallback Logic**: Always have a fallback calculation method
1008
+ 4. **Consistency**: Page durations must sum to session duration
1009
+ 5. **Validation**: Always validate durations before use
1010
+ 6. **Minimum Values**: Never allow 0 or negative durations
1011
+
1012
+ ### Reusability
1013
+
1014
+ ✅ **DurationManager.updateSessionDuration()**: **MUST USE** - This is the ONLY function that should modify `sessionData.duration`. Never modify duration directly.
1015
+
1016
+ ✅ **DurationManager.calculateBounceStatus()**: Reusable for bounce detection anywhere.
1017
+
1018
+ ✅ **DurationManager.ensureValid()**: Reusable for validating any duration value.
1019
+
1020
+ ---
1021
+
1022
+ ## Section 5: Location/Geolocation Management
1023
+
1024
+ ### Purpose
1025
+ Single source of truth for location/geolocation data fetching and storage. Handles IP-based geolocation via ipinfo.io API.
1026
+
1027
+ ### Why It Matters
1028
+ - Centralized location data management
1029
+ - Caching prevents unnecessary API calls
1030
+ - Fallback ensures we always have location data
1031
+ - Single place to fix location bugs
1032
+
1033
+ ### LocationManager Object
1034
+
1035
+ #### `LocationManager.fetchLocationData()`
1036
+ **Purpose**: Fetch location data from ipinfo.io API.
1037
+
1038
+ **Logic Flow**:
1039
+ 1. Try primary URL with timeout
1040
+ 2. If fails, try backup URL
1041
+ 3. If both fail, return default values
1042
+ 4. Parse and store location data
1043
+
1044
+ **When to Use**:
1045
+ - Initializing location data
1046
+ - Refreshing location data
1047
+ - When location data is missing
1048
+
1049
+ **Returns**: Promise that resolves with location data object
1050
+
1051
+ **Location Data Structure**:
1052
+ ```javascript
1053
+ {
1054
+ country: "US",
1055
+ ip_address: "192.168.1.1",
1056
+ city: "New York",
1057
+ region: "NY",
1058
+ latitude: "40.7128",
1059
+ longitude: "-74.0060",
1060
+ timezone: "America/New_York",
1061
+ org: "AS12345 Example Org",
1062
+ postal: "10001"
1063
+ }
1064
+ ```
1065
+
1066
+ ---
1067
+
1068
+ #### `LocationManager.storeLocationData(locationData)`
1069
+ **Purpose**: Store location data in sessionData (flattened fields).
1070
+
1071
+ **Logic**:
1072
+ - Stores all location fields directly on sessionData:
1073
+ - `ip_address`, `city`, `region`, `country`, `latitude`, `longitude`, `timezone`, `org`, `postal`
1074
+ - Also stores in `sessionData.locationData` object (for structured access)
1075
+ - Updates cached country name
1076
+
1077
+ **When to Use**:
1078
+ - After fetching location data
1079
+ - When location data is updated
1080
+
1081
+ **Parameters**: `locationData` - Location data object
1082
+
1083
+ ---
1084
+
1085
+ #### `LocationManager.getCountryName()`
1086
+ **Purpose**: Get country name (cached or fetch).
1087
+
1088
+ **Logic**:
1089
+ 1. Check runtimeState.countryName cache
1090
+ 2. Check sessionData.country
1091
+ 3. If not available, fetch and cache
1092
+
1093
+ **Returns**: Promise that resolves with country name string
1094
+
1095
+ ---
1096
+
1097
+ #### `LocationManager.getLocationData()`
1098
+ **Purpose**: Get full location data (cached or fetch).
1099
+
1100
+ **Logic**:
1101
+ 1. Check sessionData.locationData
1102
+ 2. If not available or invalid, fetch
1103
+ 3. Return location data object
1104
+
1105
+ **Returns**: Promise that resolves with location data
1106
+
1107
+ ---
1108
+
1109
+ #### `LocationManager.initialize()`
1110
+ **Purpose**: Initialize location data (non-blocking).
1111
+
1112
+ **When to Use**:
1113
+ - On SDK initialization
1114
+ - Should be called early but doesn't block other operations
1115
+
1116
+ ---
1117
+
1118
+ ### Reusability
1119
+
1120
+ ✅ **LocationManager.fetchLocationData()**: Reusable for fetching location anywhere.
1121
+
1122
+ ✅ **LocationManager.storeLocationData()**: Reusable for storing location data.
1123
+
1124
+ ---
1125
+
1126
+ ## Section 6: Session Data Structure & Normalization
1127
+
1128
+ ### Purpose
1129
+ Complete sessionData structure initialization and data normalization for backend compatibility. Handles field mapping (camelCase → snake_case) and ensures all required fields are present.
1130
+
1131
+ ### Why It Matters
1132
+ - Ensures all required fields are present (even if null)
1133
+ - Handles field mapping consistently (camelCase → snake_case)
1134
+ - Single place to manage session data structure
1135
+ - Prevents missing fields errors
1136
+
1137
+ ### Complete SessionData Structure
1138
+
1139
+ ```javascript
1140
+ let sessionData = {
1141
+ // IDs
1142
+ sessionId: null, // UUID v4 (internal camelCase)
1143
+ siteId: SITE_ID,
1144
+ teamId: null, // May be set externally or from backend
1145
+ userId: null,
1146
+
1147
+ // Time fields
1148
+ startTime: null, // ISO string (internal)
1149
+ endTime: null, // ISO string (internal)
1150
+ lastActivity: null, // Timestamp (internal)
1151
+ duration: 0, // Seconds
1152
+
1153
+ // Basic session data
1154
+ pagesViewed: 0, // Internal camelCase
1155
+ isBounce: true, // Internal camelCase
1156
+ previousSessionId: null,
1157
+ timeSinceLastSession: null,
1158
+
1159
+ // Entry/Exit pages
1160
+ entryPage: null,
1161
+ exitPage: null,
1162
+ referrer: "direct",
1163
+
1164
+ // Location fields (FLATTENED - stored directly on sessionData)
1165
+ ip_address: null, // snake_case for backend
1166
+ city: null,
1167
+ region: null,
1168
+ country: "",
1169
+ latitude: null,
1170
+ longitude: null,
1171
+ timezone: null,
1172
+ org: null,
1173
+ postal: null,
1174
+
1175
+ // Browser fields (FLATTENED)
1176
+ browser_name: null,
1177
+ browser_version: null,
1178
+
1179
+ // Device fields (FLATTENED)
1180
+ device_type: null,
1181
+ os: null,
1182
+ resolution: null,
1183
+ user_agent: null,
1184
+ language: null,
1185
+
1186
+ // Wallet fields (FLATTENED)
1187
+ wallet_address: null,
1188
+ wallet_type: null,
1189
+ chain_name: null,
1190
+ is_web3_user: false,
1191
+ wallet_connected: false,
1192
+
1193
+ // UTM fields (FLATTENED)
1194
+ utm_source: null,
1195
+ utm_medium: null,
1196
+ utm_campaign: null,
1197
+ utm_term: null,
1198
+ utm_content: null,
1199
+ utm_id: null,
1200
+
1201
+ // JSONB fields
1202
+ interactions: {},
1203
+ visited_pages: []
1204
+ };
1205
+ ```
1206
+
1207
+ ### SessionDataManager Object
1208
+
1209
+ #### `SessionDataManager.initialize()`
1210
+ **Purpose**: Initialize complete sessionData structure.
1211
+
1212
+ **Logic**:
1213
+ - Ensures all required fields exist (some may already be set)
1214
+ - Sets default values for missing fields
1215
+ - Initializes time fields (startTime, endTime, lastActivity, duration)
1216
+ - Initializes basic session data (pagesViewed, isBounce, etc.)
1217
+ - Initializes all location, browser, device, wallet, and UTM fields
1218
+ - Initializes JSONB fields (interactions, visited_pages)
1219
+
1220
+ **When to Use**:
1221
+ - On SDK initialization
1222
+ - When sessionData structure needs to be validated
1223
+ - Before sending data to backend
1224
+
1225
+ **Example**:
1226
+ ```javascript
1227
+ SessionDataManager.initialize();
1228
+ // Ensures all fields are present and properly initialized
1229
+ ```
1230
+
1231
+ ---
1232
+
1233
+ #### `SessionDataManager.toSnakeCase(camelCase)`
1234
+ **Purpose**: Convert camelCase field name to snake_case.
1235
+
1236
+ **Examples**:
1237
+ - `sessionId` → `session_id`
1238
+ - `pagesViewed` → `pages_viewed`
1239
+ - `isBounce` → `is_bounce`
1240
+
1241
+ **Parameters**: `camelCase` - Field name in camelCase
1242
+
1243
+ **Returns**: Field name in snake_case
1244
+
1245
+ ---
1246
+
1247
+ #### `SessionDataManager.toCamelCase(snakeCase)`
1248
+ **Purpose**: Convert snake_case field name to camelCase.
1249
+
1250
+ **Examples**:
1251
+ - `session_id` → `sessionId`
1252
+ - `pages_viewed` → `pagesViewed`
1253
+ - `is_bounce` → `isBounce`
1254
+
1255
+ **Parameters**: `snakeCase` - Field name in snake_case
1256
+
1257
+ **Returns**: Field name in camelCase
1258
+
1259
+ ---
1260
+
1261
+ #### `SessionDataManager.mapFieldName(internalName)`
1262
+ **Purpose**: Map internal field names to backend field names.
1263
+
1264
+ **Logic**:
1265
+ - Uses predefined field map for special cases
1266
+ - Falls back to `toSnakeCase()` for unmapped fields
1267
+ - Handles special cases where mapping isn't straightforward
1268
+
1269
+ **Field Map**:
1270
+ - `sessionId` → `session_id`
1271
+ - `siteId` → `site_id`
1272
+ - `teamId` → `team_id`
1273
+ - `userId` → `user_id`
1274
+ - `startTime` → `start_time`
1275
+ - `endTime` → `end_time`
1276
+ - `lastActivity` → `last_activity`
1277
+ - `pagesViewed` → `pages_viewed`
1278
+ - `isBounce` → `is_bounce`
1279
+ - `previousSessionId` → `previous_session_id`
1280
+ - `timeSinceLastSession` → `time_since_last_session`
1281
+ - `entryPage` → `entry_page`
1282
+ - `exitPage` → `exit_page`
1283
+
1284
+ **Parameters**: `internalName` - Internal field name (camelCase)
1285
+
1286
+ **Returns**: Backend field name (snake_case)
1287
+
1288
+ ---
1289
+
1290
+ ### Field Mapping Strategy
1291
+
1292
+ **Internal (JavaScript - camelCase)**:
1293
+ - `sessionId` → Backend: `id` (auto-generated by PostgreSQL) and `session_id`
1294
+ - `siteId` → Backend: `site_id`
1295
+ - `userId` → Backend: `user_id`
1296
+ - `startTime` → Backend: `start_time`
1297
+ - `pagesViewed` → Backend: `pages_viewed`
1298
+ - `isBounce` → Backend: `is_bounce`
1299
+ - `lastActivity` → Backend: `last_activity`
1300
+ - `previousSessionId` → Backend: `previous_session_id`
1301
+ - `timeSinceLastSession` → Backend: `time_since_last_session`
1302
+ - `entryPage` → Backend: `entry_page`
1303
+ - `exitPage` → Backend: `exit_page`
1304
+
1305
+ **Location fields**: Already in snake_case (stored directly)
1306
+
1307
+ **Browser/Device/Wallet/UTM fields**: Already in snake_case (stored directly)
1308
+
1309
+ ---
1310
+
1311
+ ## Section 7: Browser/Device Detection
1312
+
1313
+ ### Purpose
1314
+ Extract and store browser/device information as flattened fields. Centralized browser and device detection for consistent data collection.
1315
+
1316
+ ### Why It Matters
1317
+ - Centralized browser/device detection
1318
+ - Consistent field structure
1319
+ - Single place to fix detection bugs
1320
+ - Handles modern User-Agent Client Hints API with fallbacks
1321
+
1322
+ ### BrowserDeviceManager Object
1323
+
1324
+ #### `BrowserDeviceManager.detect()`
1325
+ **Purpose**: Detect browser and device information.
1326
+
1327
+ **Logic**:
1328
+ 1. Detects device type (desktop/mobile/tablet) from user agent
1329
+ 2. Extracts browser name using modern User-Agent Client Hints API (if available)
1330
+ 3. Falls back to parsing user agent string for browser name
1331
+ 4. Extracts OS, resolution, user agent, and language
1332
+
1333
+ **Device Type Detection**:
1334
+ - Mobile: `/Mobi|Android/i` in user agent
1335
+ - Tablet: `/Tablet|iPad/i` in user agent
1336
+ - Desktop: Default (if not mobile or tablet)
1337
+
1338
+ **Browser Detection**:
1339
+ - Primary: `navigator.userAgentData?.brands?.[0]?.brand` (modern API)
1340
+ - Fallback: Parse user agent string (Chrome, Firefox, Safari, Edge, Opera)
1341
+ - Final fallback: `navigator.appName`
1342
+
1343
+ **Returns**: Object with browser/device fields (all snake_case):
1344
+ ```javascript
1345
+ {
1346
+ browser_name: "Chrome", // Browser name
1347
+ browser_version: "120.0.0.0", // Browser version
1348
+ device_type: "desktop", // "desktop" | "mobile" | "tablet"
1349
+ os: "Win32", // Operating system
1350
+ resolution: "1920x1080", // Screen resolution
1351
+ user_agent: navigator.userAgent, // Full user agent string
1352
+ language: "en-US" // Browser language
1353
+ }
1354
+ ```
1355
+
1356
+ **When to Use**:
1357
+ - On SDK initialization
1358
+ - When browser/device info needs to be refreshed
1359
+ - Before sending data to backend
1360
+
1361
+ **Example**:
1362
+ ```javascript
1363
+ const browserDeviceData = BrowserDeviceManager.detect();
1364
+ // Returns: { browser_name: "Chrome", device_type: "desktop", ... }
1365
+ ```
1366
+
1367
+ ---
1368
+
1369
+ #### `BrowserDeviceManager.store(data)`
1370
+ **Purpose**: Store browser/device data in sessionData (flattened).
1371
+
1372
+ **Logic**:
1373
+ - Stores all fields directly on sessionData (flattened for backend compatibility)
1374
+ - If no data provided, calls `detect()` first
1375
+ - All fields stored in snake_case format
1376
+
1377
+ **Stores on sessionData**:
1378
+ - `browser_name` - Browser name
1379
+ - `browser_version` - Browser version
1380
+ - `device_type` - Device type (desktop/mobile/tablet)
1381
+ - `os` - Operating system
1382
+ - `resolution` - Screen resolution (e.g., "1920x1080")
1383
+ - `user_agent` - Full user agent string
1384
+ - `language` - Browser language
1385
+
1386
+ **Parameters**: `data` (optional) - Browser/device data object. If not provided, calls `detect()`.
1387
+
1388
+ **When to Use**:
1389
+ - After detecting browser/device info
1390
+ - On SDK initialization
1391
+ - When browser/device data needs to be updated
1392
+
1393
+ **Example**:
1394
+ ```javascript
1395
+ BrowserDeviceManager.store(); // Auto-detects and stores
1396
+ // OR
1397
+ const data = BrowserDeviceManager.detect();
1398
+ BrowserDeviceManager.store(data);
1399
+ ```
1400
+
1401
+ ---
1402
+
1403
+ #### `BrowserDeviceManager.initialize()`
1404
+ **Purpose**: Initialize browser/device detection.
1405
+
1406
+ **Logic**:
1407
+ - Calls `detect()` to get browser/device information
1408
+ - Calls `store()` to save data to sessionData
1409
+
1410
+ **When to Use**:
1411
+ - On SDK initialization
1412
+ - Should be called early in initialization flow
1413
+
1414
+ **Example**:
1415
+ ```javascript
1416
+ BrowserDeviceManager.initialize();
1417
+ // Detects and stores browser/device info in sessionData
1418
+ ```
1419
+
1420
+ ---
1421
+
1422
+ ### Reusability
1423
+
1424
+ ✅ **BrowserDeviceManager.detect()**: Reusable for detecting browser/device anywhere.
1425
+
1426
+ ✅ **BrowserDeviceManager.store()**: Reusable for storing browser/device data.
1427
+
1428
+ ✅ **BrowserDeviceManager.initialize()**: Reusable for initialization.
1429
+
1430
+ ---
1431
+
1432
+ ## Section 8: UTM Parameter Management
1433
+
1434
+ ### Purpose
1435
+ Extract and store UTM parameters as flattened fields. Centralized UTM parameter extraction from URL query string.
1436
+
1437
+ ### Why It Matters
1438
+ - Centralized UTM parameter extraction
1439
+ - Consistent field structure
1440
+ - Single place to fix UTM bugs
1441
+ - Handles missing parameters gracefully
1442
+
1443
+ ### UTMManager Object
1444
+
1445
+ #### `UTMManager.extract()`
1446
+ **Purpose**: Extract UTM parameters from URL query string.
1447
+
1448
+ **Logic**:
1449
+ - Uses `URLSearchParams` to parse query string
1450
+ - Extracts all 6 UTM parameters
1451
+ - Returns null for missing parameters (not empty strings)
1452
+
1453
+ **Returns**: Object with UTM fields (all snake_case):
1454
+ ```javascript
1455
+ {
1456
+ utm_source: "google", // or null
1457
+ utm_medium: "cpc", // or null
1458
+ utm_campaign: "summer_sale", // or null
1459
+ utm_term: "keyword", // or null
1460
+ utm_content: "ad_variant", // or null
1461
+ utm_id: "12345" // or null
1462
+ }
1463
+ ```
1464
+
1465
+ **When to Use**:
1466
+ - On SDK initialization
1467
+ - When UTM parameters need to be refreshed
1468
+ - Before sending data to backend
1469
+
1470
+ **Example**:
1471
+ ```javascript
1472
+ const utmData = UTMManager.extract();
1473
+ // Returns: { utm_source: "google", utm_medium: "cpc", ... }
1474
+ ```
1475
+
1476
+ ---
1477
+
1478
+ #### `UTMManager.store(data)`
1479
+ **Purpose**: Store UTM data in sessionData (flattened).
1480
+
1481
+ **Logic**:
1482
+ - Stores all 6 UTM fields directly on sessionData (flattened)
1483
+ - Also stores in `sessionData.utmData` object (for backward compatibility)
1484
+ - If no data provided, calls `extract()` first
1485
+
1486
+ **Stores on sessionData**:
1487
+ - `utm_source` - UTM source parameter
1488
+ - `utm_medium` - UTM medium parameter
1489
+ - `utm_campaign` - UTM campaign parameter
1490
+ - `utm_term` - UTM term parameter
1491
+ - `utm_content` - UTM content parameter
1492
+ - `utm_id` - UTM ID parameter
1493
+
1494
+ **Parameters**: `data` (optional) - UTM data object. If not provided, calls `extract()`.
1495
+
1496
+ **When to Use**:
1497
+ - After extracting UTM parameters
1498
+ - On SDK initialization
1499
+ - When UTM data needs to be updated
1500
+
1501
+ **Example**:
1502
+ ```javascript
1503
+ UTMManager.store(); // Auto-extracts and stores
1504
+ // OR
1505
+ const data = UTMManager.extract();
1506
+ UTMManager.store(data);
1507
+ ```
1508
+
1509
+ ---
1510
+
1511
+ #### `UTMManager.initialize()`
1512
+ **Purpose**: Initialize UTM parameter extraction.
1513
+
1514
+ **Logic**:
1515
+ - Calls `extract()` to get UTM parameters
1516
+ - Calls `store()` to save data to sessionData
1517
+
1518
+ **When to Use**:
1519
+ - On SDK initialization
1520
+ - Should be called early in initialization flow
1521
+
1522
+ **Example**:
1523
+ ```javascript
1524
+ UTMManager.initialize();
1525
+ // Extracts and stores UTM parameters in sessionData
1526
+ ```
1527
+
1528
+ ---
1529
+
1530
+ ### Reusability
1531
+
1532
+ ✅ **UTMManager.extract()**: Reusable for extracting UTM parameters anywhere.
1533
+
1534
+ ✅ **UTMManager.store()**: Reusable for storing UTM data.
1535
+
1536
+ ✅ **UTMManager.initialize()**: Reusable for initialization.
1537
+
1538
+ ---
1539
+
1540
+ ## Section 9: Wallet/Web3 Management
1541
+
1542
+ ### Purpose
1543
+ Detect and store wallet/Web3 information as flattened fields. Comprehensive support for EVM wallets and chains with real-time tracking.
1544
+
1545
+ ### Why It Matters
1546
+ - **Comprehensive Wallet Detection**: Supports 30+ EVM wallets
1547
+ - **Multi-Chain Support**: Recognizes 40+ EVM-compatible chains
1548
+ - **EIP-6963 Support**: Modern multi-wallet detection standard
1549
+ - **Real-Time Tracking**: Listens for wallet events (account changes, chain changes)
1550
+ - **Non-Intrusive**: Detects wallets without prompting user
1551
+ - **Single Source of Truth**: Centralized wallet state management
1552
+
1553
+ ### WalletManager Object
1554
+
1555
+ #### Supported Wallets (30+ EVM Wallets)
1556
+
1557
+ **Major Wallets:**
1558
+ - ✅ **MetaMask** - Most popular Ethereum wallet
1559
+ - ✅ **Trust Wallet** - Popular mobile wallet
1560
+ - ✅ **Coinbase Wallet** - Coinbase's official wallet
1561
+ - ✅ **Brave Wallet** - Built into Brave browser
1562
+ - ✅ **Frame** - Privacy-focused wallet
1563
+ - ✅ **Phantom** - Solana wallet (EVM support)
1564
+ - ✅ **TronLink** - Tron wallet
1565
+
1566
+ **Additional Wallets:**
1567
+ - ✅ **OKX Wallet** - OKX exchange wallet
1568
+ - ✅ **TokenPocket** - Multi-chain wallet
1569
+ - ✅ **SafePal** - Hardware wallet software
1570
+ - ✅ **MathWallet** - Multi-chain wallet
1571
+ - ✅ **1inch Wallet** - DEX aggregator wallet
1572
+ - ✅ **Alpha Wallet** - Mobile wallet
1573
+ - ✅ **AToken** - Multi-chain wallet
1574
+ - ✅ **BitKeep** - Popular DeFi wallet
1575
+ - ✅ **BlockWallet** - Privacy wallet
1576
+ - ✅ **Coin98** - Vietnamese wallet
1577
+ - ✅ **Dawn** - Ethereum wallet
1578
+ - ✅ **Enkrypt** - Multi-chain wallet
1579
+ - ✅ **Exodus** - Desktop wallet
1580
+ - ✅ **Frontier** - DeFi wallet
1581
+ - ✅ **Gamestop** - GameStop wallet
1582
+ - ✅ **HyperPay** - Payment wallet
1583
+ - ✅ **ImToken** - Chinese wallet
1584
+ - ✅ **Infinity Wallet** - Multi-chain wallet
1585
+ - ✅ **Liquality** - Atomic swap wallet
1586
+ - ✅ **MEW CX** - MyEtherWallet
1587
+ - ✅ **Opera** - Opera browser wallet
1588
+ - ✅ **Portal** - WalletConnect wallet
1589
+ - ✅ **Rabby** - DeFi wallet
1590
+ - ✅ **Rainbow** - Beautiful mobile wallet
1591
+ - ✅ **Status** - Mobile wallet
1592
+ - ✅ **Tally** - Community wallet
1593
+ - ✅ **Tokenary** - iOS wallet
1594
+ - ✅ **Torus** - Social login wallet
1595
+ - ✅ **XDEFI** - Multi-chain wallet
1596
+ - ✅ **Zerion** - DeFi portfolio wallet
1597
+
1598
+ **Detection Methods:**
1599
+ 1. **EIP-6963** (Modern Standard): Detects wallets via `eip6963:announceProvider` event
1600
+ 2. **window.ethereum Properties**: Checks wallet-specific properties (e.g., `isMetaMask`)
1601
+ 3. **Global Wallet Objects**: Checks for wallet-specific global objects (e.g., `window.okxwallet`)
1602
+
1603
+ ---
1604
+
1605
+ #### Supported Chains (40+ EVM-Compatible Chains)
1606
+
1607
+ **Mainnets:**
1608
+ - ✅ **Ethereum Mainnet** (Chain ID: 1)
1609
+ - ✅ **Binance Smart Chain** (Chain ID: 56)
1610
+ - ✅ **Polygon** (Chain ID: 137)
1611
+ - ✅ **Optimism** (Chain ID: 10)
1612
+ - ✅ **Arbitrum One** (Chain ID: 42161)
1613
+ - ✅ **Avalanche C-Chain** (Chain ID: 43114)
1614
+ - ✅ **Fantom Opera** (Chain ID: 250)
1615
+ - ✅ **Gnosis Chain** (Chain ID: 100)
1616
+ - ✅ **Aurora** (Chain ID: 1313161554)
1617
+ - ✅ **Base** (Chain ID: 8453)
1618
+ - ✅ **zkSync Era** (Chain ID: 324)
1619
+ - ✅ **Linea** (Chain ID: 59144)
1620
+ - ✅ **Scroll** (Chain ID: 534352)
1621
+ - ✅ **Mantle** (Chain ID: 5000)
1622
+ - ✅ **Celo** (Chain ID: 42220)
1623
+ - ✅ **Moonbeam** (Chain ID: 1284)
1624
+ - ✅ **Moonriver** (Chain ID: 1285)
1625
+ - ✅ **Harmony** (Chain ID: 1666600000)
1626
+ - ✅ **Cronos** (Chain ID: 25)
1627
+ - ✅ **Metis** (Chain ID: 1088)
1628
+ - ✅ **Polygon zkEVM** (Chain ID: 1101)
1629
+ - ✅ **opBNB** (Chain ID: 204)
1630
+ - ✅ **OKXChain** (Chain ID: 196)
1631
+ - ✅ **Blast** (Chain ID: 81457)
1632
+ - ✅ **Chiliz Chain** (Chain ID: 88888)
1633
+ - ✅ **ZetaChain** (Chain ID: 7001)
1634
+ - ✅ **Core** (Chain ID: 1116)
1635
+ - ✅ **Astar zkEVM** (Chain ID: 3776)
1636
+
1637
+ **Testnets:**
1638
+ - ✅ **Holesky** (Chain ID: 17000)
1639
+ - ✅ **Sepolia** (Chain ID: 11155111)
1640
+ - ✅ **Goerli** (Chain ID: 5)
1641
+ - ✅ **BSC Testnet** (Chain ID: 97)
1642
+ - ✅ **Mumbai** (Chain ID: 80001)
1643
+ - ✅ **Arbitrum Sepolia** (Chain ID: 421614)
1644
+ - ✅ **Optimism Sepolia** (Chain ID: 11155420)
1645
+ - ✅ **Base Sepolia** (Chain ID: 84532)
1646
+ - ✅ **Avalanche Fuji** (Chain ID: 43113)
1647
+ - ✅ **Fantom Testnet** (Chain ID: 4002)
1648
+
1649
+ **Unknown Chains:**
1650
+ - ✅ Automatically displays as `Unknown Chain (ID: <chainId>)` for unrecognized chains
1651
+
1652
+ ---
1653
+
1654
+ #### `WalletManager.detectWalletType()`
1655
+ **Purpose**: Detect wallet type from available providers.
1656
+
1657
+ **Logic**:
1658
+ 1. Checks EIP-6963 providers first (modern standard)
1659
+ 2. Checks `window.ethereum` wallet patterns (30+ wallets)
1660
+ 3. Checks global wallet objects (OKX, TokenPocket, etc.)
1661
+ 4. Falls back to "Web3 Wallet" if `window.ethereum` exists but no specific wallet detected
1662
+ 5. Returns "No Wallet Detected" if no wallet found
1663
+
1664
+ **Returns**: Wallet name string (e.g., "MetaMask", "Trust Wallet", "No Wallet Detected")
1665
+
1666
+ **When to Use**:
1667
+ - On SDK initialization
1668
+ - When wallet type needs to be refreshed
1669
+ - Before sending data to backend
1670
+
1671
+ **Example**:
1672
+ ```javascript
1673
+ const walletType = WalletManager.detectWalletType();
1674
+ // Returns: "MetaMask" or "Trust Wallet" or "No Wallet Detected"
1675
+ ```
1676
+
1677
+ ---
1678
+
1679
+ #### `WalletManager.getChainNameFromId(chainId)`
1680
+ **Purpose**: Convert chain ID to human-readable chain name.
1681
+
1682
+ **Logic**:
1683
+ - Handles hex string chain IDs (e.g., "0x1" → 1)
1684
+ - Handles decimal string chain IDs (e.g., "1" → 1)
1685
+ - Looks up chain name in `CHAIN_NAMES` mapping
1686
+ - Returns "Unknown Chain (ID: <chainId>)" for unrecognized chains
1687
+
1688
+ **Parameters**: `chainId` - Chain ID (number, hex string, or decimal string)
1689
+
1690
+ **Returns**: Chain name string (e.g., "Ethereum Mainnet", "Polygon")
1691
+
1692
+ **Example**:
1693
+ ```javascript
1694
+ const chainName = WalletManager.getChainNameFromId(1);
1695
+ // Returns: "Ethereum Mainnet"
1696
+
1697
+ const chainName = WalletManager.getChainNameFromId("0x38");
1698
+ // Returns: "Binance Smart Chain"
1699
+ ```
1700
+
1701
+ ---
1702
+
1703
+ #### `WalletManager.detectChainId()`
1704
+ **Purpose**: Detect chain ID from provider.
1705
+
1706
+ **Logic**:
1707
+ 1. Checks `window.ethereum.chainId` property (modern providers)
1708
+ 2. Requests chain ID via `eth_chainId` method
1709
+ 3. Falls back to Web3.js if available
1710
+ 4. Returns null if no provider or error
1711
+
1712
+ **Returns**: Promise that resolves to chain ID (hex string) or null
1713
+
1714
+ **When to Use**:
1715
+ - When chain ID needs to be detected
1716
+ - Before converting to chain name
1717
+
1718
+ **Example**:
1719
+ ```javascript
1720
+ const chainId = await WalletManager.detectChainId();
1721
+ // Returns: "0x1" (Ethereum) or null
1722
+ ```
1723
+
1724
+ ---
1725
+
1726
+ #### `WalletManager.detectChainName()`
1727
+ **Purpose**: Detect chain name from provider.
1728
+
1729
+ **Logic**:
1730
+ 1. Gets chain ID via `detectChainId()`
1731
+ 2. Converts chain ID to chain name via `getChainNameFromId()`
1732
+ 3. Returns "Not Connected" if no chain ID
1733
+
1734
+ **Returns**: Promise that resolves to chain name string
1735
+
1736
+ **When to Use**:
1737
+ - On SDK initialization
1738
+ - When chain name needs to be refreshed
1739
+ - After chain change events
1740
+
1741
+ **Example**:
1742
+ ```javascript
1743
+ const chainName = await WalletManager.detectChainName();
1744
+ // Returns: "Ethereum Mainnet" or "Not Connected"
1745
+ ```
1746
+
1747
+ ---
1748
+
1749
+ #### `WalletManager.checkWalletConnected()`
1750
+ **Purpose**: Check if wallet is connected (non-intrusive).
1751
+
1752
+ **Logic**:
1753
+ - Uses `eth_accounts` method (doesn't prompt user)
1754
+ - Returns true if accounts exist, false otherwise
1755
+ - Returns false if no provider
1756
+
1757
+ **Returns**: Promise that resolves to boolean
1758
+
1759
+ **When to Use**:
1760
+ - On SDK initialization (silent check)
1761
+ - Before updating wallet info
1762
+ - To check connection status without prompting
1763
+
1764
+ **Example**:
1765
+ ```javascript
1766
+ const isConnected = await WalletManager.checkWalletConnected();
1767
+ // Returns: true or false
1768
+ ```
1769
+
1770
+ ---
1771
+
1772
+ #### `WalletManager.getWalletAddress()`
1773
+ **Purpose**: Get connected wallet address (non-intrusive).
1774
+
1775
+ **Logic**:
1776
+ - Uses `eth_accounts` method (doesn't prompt user)
1777
+ - Returns first account address or null
1778
+ - Returns null if no provider or error
1779
+
1780
+ **Returns**: Promise that resolves to wallet address (hex string) or null
1781
+
1782
+ **When to Use**:
1783
+ - When wallet address needs to be retrieved
1784
+ - After wallet connection
1785
+ - On account change events
1786
+
1787
+ **Example**:
1788
+ ```javascript
1789
+ const address = await WalletManager.getWalletAddress();
1790
+ // Returns: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb" or null
1791
+ ```
1792
+
1793
+ ---
1794
+
1795
+ #### `WalletManager.updateWalletInfo()`
1796
+ **Purpose**: Update all wallet information (comprehensive).
1797
+
1798
+ **Logic**:
1799
+ 1. Detects wallet type
1800
+ 2. Checks if wallet is connected
1801
+ 3. Gets wallet address if connected
1802
+ 4. Gets chain name if connected
1803
+ 5. Determines if user is Web3 user (has wallet installed)
1804
+ 6. Stores all fields in sessionData (flattened)
1805
+
1806
+ **Stores on sessionData**:
1807
+ - `wallet_address` - Connected wallet address (or null)
1808
+ - `wallet_type` - Wallet name (e.g., "MetaMask")
1809
+ - `chain_name` - Chain name (e.g., "Ethereum Mainnet")
1810
+ - `is_web3_user` - Boolean (true if wallet installed, even if not connected)
1811
+ - `wallet_connected` - Boolean (true only if wallet is connected)
1812
+
1813
+ **Returns**: Promise that resolves to wallet info object or null on error
1814
+
1815
+ **When to Use**:
1816
+ - On SDK initialization
1817
+ - After wallet connection
1818
+ - On account change events
1819
+ - On chain change events
1820
+ - Before sending data to backend
1821
+
1822
+ **Example**:
1823
+ ```javascript
1824
+ const walletInfo = await WalletManager.updateWalletInfo();
1825
+ // Returns: {
1826
+ // wallet_address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
1827
+ // wallet_type: "MetaMask",
1828
+ // chain_name: "Ethereum Mainnet",
1829
+ // is_web3_user: true,
1830
+ // wallet_connected: true
1831
+ // }
1832
+ ```
1833
+
1834
+ ---
1835
+
1836
+ #### `WalletManager.setupEventListeners()`
1837
+ **Purpose**: Setup wallet event listeners for real-time tracking.
1838
+
1839
+ **Logic**:
1840
+ - Listens for `accountsChanged` event (wallet connect/disconnect, account switch)
1841
+ - Listens for `chainChanged` event (network switch)
1842
+ - Updates wallet info automatically on events
1843
+ - Handles wallet disconnection gracefully
1844
+
1845
+ **When to Use**:
1846
+ - On SDK initialization
1847
+ - Should be called once to setup listeners
1848
+
1849
+ **Example**:
1850
+ ```javascript
1851
+ WalletManager.setupEventListeners();
1852
+ // Now automatically tracks wallet changes
1853
+ ```
1854
+
1855
+ ---
1856
+
1857
+ #### `WalletManager.initialize()`
1858
+ **Purpose**: Initialize wallet detection and tracking.
1859
+
1860
+ **Logic**:
1861
+ 1. Calls `updateWalletInfo()` (non-blocking, initial detection)
1862
+ 2. Calls `setupEventListeners()` (setup real-time tracking)
1863
+
1864
+ **When to Use**:
1865
+ - On SDK initialization
1866
+ - Should be called early but doesn't block other operations
1867
+
1868
+ **Example**:
1869
+ ```javascript
1870
+ await WalletManager.initialize();
1871
+ // Detects wallet, sets up listeners, tracks changes
1872
+ ```
1873
+
1874
+ ---
1875
+
1876
+ ### Wallet Detection Flow
1877
+
1878
+ ```
1879
+ 1. SDK Initialization
1880
+
1881
+ 2. WalletManager.initialize()
1882
+
1883
+ 3. Check EIP-6963 providers (modern standard)
1884
+
1885
+ 4. Check window.ethereum wallet patterns (30+ wallets)
1886
+
1887
+ 5. Check global wallet objects
1888
+
1889
+ 6. Detect wallet type
1890
+
1891
+ 7. Check connection status (non-intrusive)
1892
+
1893
+ 8. Get wallet address (if connected)
1894
+
1895
+ 9. Get chain ID and convert to chain name
1896
+
1897
+ 10. Store all fields in sessionData
1898
+
1899
+ 11. Setup event listeners (accountsChanged, chainChanged)
1900
+
1901
+ 12. Real-time tracking active
1902
+ ```
1903
+
1904
+ ---
1905
+
1906
+ ### Key Features
1907
+
1908
+ ✅ **Non-Intrusive Detection**: Never prompts user for wallet connection
1909
+ ✅ **EIP-6963 Support**: Modern multi-wallet detection standard
1910
+ ✅ **30+ Wallet Support**: Comprehensive EVM wallet detection
1911
+ ✅ **40+ Chain Support**: Recognizes all major EVM chains
1912
+ ✅ **Real-Time Tracking**: Automatically updates on wallet events
1913
+ ✅ **Error Handling**: Graceful fallbacks on errors
1914
+ ✅ **Flattened Storage**: All fields stored directly on sessionData
1915
+
1916
+ ---
1917
+
1918
+ ### Reusability
1919
+
1920
+ ✅ **WalletManager.detectWalletType()**: Reusable for detecting wallet anywhere.
1921
+
1922
+ ✅ **WalletManager.getChainNameFromId()**: Reusable for chain ID to name conversion.
1923
+
1924
+ ✅ **WalletManager.updateWalletInfo()**: Reusable for updating wallet state.
1925
+
1926
+ ✅ **WalletManager.initialize()**: Reusable for initialization.
1927
+
1928
+ ---
1929
+
1930
+ ## Section 10: Interaction Management
1931
+
1932
+ ### Purpose
1933
+ Single source of truth for interaction tracking and management. Handles all user interactions (clicks, forms, scroll, hover, etc.) with automatic timestamping, categorization, and chronological sorting.
1934
+
1935
+ ### Why It Matters
1936
+ - Centralized interaction tracking
1937
+ - Consistent data structure
1938
+ - Single place to fix interaction bugs
1939
+ - Prevents repeating interactions
1940
+ - Automatic timestamping and categorization
1941
+ - Immediate session storage updates
1942
+
1943
+ ### InteractionManager Object
1944
+
1945
+ #### Interaction Categories (19 Categories)
1946
+
1947
+ **User Actions:**
1948
+ - `clicks` - Click events
1949
+ - `hoverEvents` - Hover/mouseover events
1950
+ - `touchEvents` - Touch events (mobile)
1951
+ - `keyboardEvents` - Keyboard input events
1952
+ - `copyPasteEvents` - Copy/paste events
1953
+ - `contextMenuEvents` - Right-click context menu events
1954
+ - `dragDropEvents` - Drag and drop events
1955
+
1956
+ **Form Interactions:**
1957
+ - `formInteractions` - General form interactions
1958
+ - `formSubmissions` - Form submission events
1959
+ - `fieldChanges` - Form field value changes
1960
+ - `validationErrors` - Form validation errors
1961
+ - `formAnalytics` - Form analytics data
1962
+
1963
+ **Media & Content:**
1964
+ - `mediaInteractions` - Video/audio player interactions
1965
+
1966
+ **Navigation & Scrolling:**
1967
+ - `scrollEvents` - Scroll events
1968
+ - `focusEvents` - Focus/blur events
1969
+ - `windowEvents` - Window resize, visibility, etc.
1970
+
1971
+ **Performance & Errors:**
1972
+ - `performanceEvents` - Performance metrics
1973
+ - `errorEvents` - JavaScript errors
1974
+ - `networkEvents` - Network request events
1975
+
1976
+ ---
1977
+
1978
+ #### `InteractionManager.initialize()`
1979
+ **Purpose**: Initialize interactions structure.
1980
+
1981
+ **Logic**:
1982
+ - Creates empty interactions object with all 19 categories
1983
+ - Sets `totalInteractions` to 0
1984
+ - Initializes all category arrays as empty arrays
1985
+
1986
+ **When to Use**:
1987
+ - On SDK initialization
1988
+ - When interactions need to be reset
1989
+ - Before adding interactions
1990
+
1991
+ **Example**:
1992
+ ```javascript
1993
+ InteractionManager.initialize();
1994
+ // Creates empty interactions structure
1995
+ ```
1996
+
1997
+ ---
1998
+
1999
+ #### `InteractionManager.add(category, interactionData)`
2000
+ **Purpose**: Add interaction to appropriate category.
2001
+
2002
+ **Logic**:
2003
+ 1. Ensures interactions are initialized
2004
+ 2. Validates category
2005
+ 3. Adds timestamp if not provided
2006
+ 4. Adds to specific category array
2007
+ 5. Updates total interactions count
2008
+ 6. Updates session activity
2009
+ 7. Immediately updates session storage
2010
+
2011
+ **Parameters**:
2012
+ - `category` - Interaction category (e.g., 'clicks', 'formInteractions')
2013
+ - `interactionData` - Interaction data object (can include any fields)
2014
+
2015
+ **Interaction Data Structure**:
2016
+ ```javascript
2017
+ {
2018
+ timestamp: "2024-12-15T10:30:00.000Z", // Auto-added if not provided
2019
+ elementId: "button-123", // Optional: Element identifier
2020
+ target: "button", // Optional: Target element
2021
+ selector: "#submit-btn", // Optional: CSS selector
2022
+ // ... any other fields specific to interaction type
2023
+ }
2024
+ ```
2025
+
2026
+ **When to Use**:
2027
+ - When tracking any user interaction
2028
+ - Called by event trackers (Section 14)
2029
+ - For custom interaction tracking
2030
+
2031
+ **Example**:
2032
+ ```javascript
2033
+ // Track a click
2034
+ InteractionManager.add('clicks', {
2035
+ elementId: 'submit-button',
2036
+ target: 'button',
2037
+ selector: '#submit-btn',
2038
+ x: 100,
2039
+ y: 200
2040
+ });
2041
+
2042
+ // Track a form submission
2043
+ InteractionManager.add('formSubmissions', {
2044
+ formId: 'contact-form',
2045
+ fields: ['name', 'email', 'message'],
2046
+ success: true
2047
+ });
2048
+ ```
2049
+
2050
+ ---
2051
+
2052
+ #### `InteractionManager.updateTotalCount()`
2053
+ **Purpose**: Update total interactions count.
2054
+
2055
+ **Logic**:
2056
+ - Calculates total from all category arrays
2057
+ - Updates `sessionData.interactions.totalInteractions`
2058
+
2059
+ **When to Use**:
2060
+ - Automatically called by `add()`
2061
+ - After manual interaction modifications
2062
+ - After deduplication
2063
+
2064
+ ---
2065
+
2066
+ #### `InteractionManager.updateSessionStorage()`
2067
+ **Purpose**: Update session storage with interactions.
2068
+
2069
+ **Logic**:
2070
+ - Loads current session from storage
2071
+ - Updates interactions in session data
2072
+ - Saves session back to storage
2073
+
2074
+ **When to Use**:
2075
+ - Automatically called by `add()`
2076
+ - After bulk interaction updates
2077
+
2078
+ ---
2079
+
2080
+ #### `InteractionManager.getChronological()`
2081
+ **Purpose**: Get all interactions sorted chronologically.
2082
+
2083
+ **Logic**:
2084
+ 1. Collects all interactions from all categories
2085
+ 2. Adds category identifiers (`category`, `originalCategory`)
2086
+ 3. Sorts by timestamp (oldest first)
2087
+
2088
+ **Returns**: Array of interactions sorted by timestamp
2089
+
2090
+ **Interaction Structure in Chronological Array**:
2091
+ ```javascript
2092
+ [
2093
+ {
2094
+ timestamp: "2024-12-15T10:30:00.000Z",
2095
+ category: "click", // Normalized category name
2096
+ originalCategory: "clicks", // Original category array name
2097
+ elementId: "button-123",
2098
+ // ... other interaction data
2099
+ },
2100
+ {
2101
+ timestamp: "2024-12-15T10:30:05.000Z",
2102
+ category: "scrollEvent",
2103
+ originalCategory: "scrollEvents",
2104
+ scrollY: 100,
2105
+ // ... other interaction data
2106
+ }
2107
+ ]
2108
+ ```
2109
+
2110
+ **When to Use**:
2111
+ - Before sending data to backend
2112
+ - For analytics/reporting
2113
+ - For chronological interaction analysis
2114
+
2115
+ **Example**:
2116
+ ```javascript
2117
+ const chronological = InteractionManager.getChronological();
2118
+ // Returns: Array of all interactions sorted by time
2119
+ ```
2120
+
2121
+ ---
2122
+
2123
+ #### `InteractionManager.getChronologicalForBackend()`
2124
+ **Purpose**: Get chronological interactions for backend.
2125
+
2126
+ **Logic**:
2127
+ - Gets chronological array via `getChronological()`
2128
+ - Returns both chronological and categorized structures
2129
+
2130
+ **Returns**: Object with:
2131
+ ```javascript
2132
+ {
2133
+ chronological: [...], // Sorted array
2134
+ categorized: {...} // Original categorized structure
2135
+ }
2136
+ ```
2137
+
2138
+ **When to Use**:
2139
+ - When sending data to backend
2140
+ - When both formats are needed
2141
+
2142
+ **Example**:
2143
+ ```javascript
2144
+ const interactions = InteractionManager.getChronologicalForBackend();
2145
+ // Returns: { chronological: [...], categorized: {...} }
2146
+ ```
2147
+
2148
+ ---
2149
+
2150
+ #### `InteractionManager.deduplicate()`
2151
+ **Purpose**: Remove duplicate interactions.
2152
+
2153
+ **Logic**:
2154
+ - Compares interactions by timestamp, category, and element identifier
2155
+ - Keeps first occurrence of duplicates
2156
+ - Updates total count after deduplication
2157
+ - Updates session storage
2158
+
2159
+ **Deduplication Key**: `${timestamp}_${category}_${elementId}`
2160
+
2161
+ **When to Use**:
2162
+ - Before sending data to backend
2163
+ - After bulk interaction imports
2164
+ - To clean up duplicate events
2165
+
2166
+ **Example**:
2167
+ ```javascript
2168
+ InteractionManager.deduplicate();
2169
+ // Removes duplicate interactions
2170
+ ```
2171
+
2172
+ ---
2173
+
2174
+ #### `InteractionManager.getByCategory(category)`
2175
+ **Purpose**: Get interactions by category.
2176
+
2177
+ **Parameters**: `category` - Interaction category name
2178
+
2179
+ **Returns**: Array of interactions for that category
2180
+
2181
+ **When to Use**:
2182
+ - When analyzing specific interaction types
2183
+ - For category-specific analytics
2184
+
2185
+ **Example**:
2186
+ ```javascript
2187
+ const clicks = InteractionManager.getByCategory('clicks');
2188
+ // Returns: Array of all click interactions
2189
+ ```
2190
+
2191
+ ---
2192
+
2193
+ #### `InteractionManager.getTotalCount()`
2194
+ **Purpose**: Get total interactions count.
2195
+
2196
+ **Returns**: Total number of interactions across all categories
2197
+
2198
+ **When to Use**:
2199
+ - For analytics/reporting
2200
+ - To check interaction volume
2201
+
2202
+ **Example**:
2203
+ ```javascript
2204
+ const total = InteractionManager.getTotalCount();
2205
+ // Returns: 42 (total interactions)
2206
+ ```
2207
+
2208
+ ---
2209
+
2210
+ #### `InteractionManager.clear()`
2211
+ **Purpose**: Clear all interactions.
2212
+
2213
+ **Logic**:
2214
+ - Resets all category arrays to empty
2215
+ - Sets total count to 0
2216
+ - Updates session storage
2217
+
2218
+ **When to Use**:
2219
+ - For testing/reset
2220
+ - When starting fresh session
2221
+
2222
+ **Example**:
2223
+ ```javascript
2224
+ InteractionManager.clear();
2225
+ // Clears all interactions
2226
+ ```
2227
+
2228
+ ---
2229
+
2230
+ ### Reusability
2231
+
2232
+ ✅ **InteractionManager.add()**: Reusable for tracking any interaction type.
2233
+
2234
+ ✅ **InteractionManager.getChronological()**: Reusable for chronological analysis.
2235
+
2236
+ ✅ **InteractionManager.deduplicate()**: Reusable for cleaning duplicate interactions.
2237
+
2238
+ ✅ **InteractionManager.getByCategory()**: Reusable for category-specific queries.
2239
+
2240
+ ---
2241
+
2242
+ ## Section 11: Page Visit Management
2243
+
2244
+ ### Purpose
2245
+ Track and manage page visits with durations. Handles entry/exit pages, mount/unmount times, and page duration calculations.
2246
+
2247
+ ### Why It Matters
2248
+ - Centralized page visit tracking
2249
+ - Accurate page duration calculations
2250
+ - Proper entry/exit page tracking
2251
+ - Single place to fix page visit bugs
2252
+ - Prevents duplicate page visits
2253
+
2254
+ ### PageVisitManager Object
2255
+
2256
+ #### `PageVisitManager.track(path, timestamp)`
2257
+ **Purpose**: Track a page visit.
2258
+
2259
+ **Logic**:
2260
+ 1. Ensures session ID exists
2261
+ 2. Gets current path and URL
2262
+ 3. Checks if page already visited (prevents duplicates)
2263
+ 4. Creates page visit entry with mount time
2264
+ 5. Updates previous page's unmount time and duration
2265
+ 6. Sets entry page if first page
2266
+ 7. Updates pagesViewed count
2267
+ 8. Calculates session duration
2268
+ 9. Updates session activity
2269
+ 10. Saves to storage
2270
+
2271
+ **Parameters**:
2272
+ - `path` (optional) - Page path. Defaults to `window.location.pathname + search`
2273
+ - `timestamp` (optional) - Page visit timestamp. Defaults to current time
2274
+
2275
+ **Stores in `visited_pages` array**:
2276
+ ```javascript
2277
+ {
2278
+ path: "/home",
2279
+ timestamp: "2024-12-15T10:30:00.000Z",
2280
+ duration: 180,
2281
+ isEntry: true,
2282
+ isExit: false,
2283
+ mountTime: 1702641000000, // Milliseconds
2284
+ unmountTime: 1702641180000 // Milliseconds
2285
+ }
2286
+ ```
2287
+
2288
+ **When to Use**:
2289
+ - On page load
2290
+ - On SPA navigation
2291
+ - When tracking page visits
2292
+
2293
+ **Example**:
2294
+ ```javascript
2295
+ PageVisitManager.track();
2296
+ // Tracks current page visit
2297
+ ```
2298
+
2299
+ ---
2300
+
2301
+ #### `PageVisitManager.trackUnmount()`
2302
+ **Purpose**: Track page unmount (when user navigates away).
2303
+
2304
+ **Logic**:
2305
+ - Finds current page in page visits
2306
+ - Sets unmount time
2307
+ - Calculates page duration using DurationManager
2308
+ - Recalculates session duration
2309
+ - Saves to storage
2310
+
2311
+ **When to Use**:
2312
+ - Automatically called on `beforeunload` event
2313
+ - Automatically called on `visibilitychange` event (SPA navigation)
2314
+ - Can be called manually if needed
2315
+
2316
+ **Example**:
2317
+ ```javascript
2318
+ PageVisitManager.trackUnmount();
2319
+ // Tracks current page unmount
2320
+ ```
2321
+
2322
+ ---
2323
+
2324
+ #### `PageVisitManager.getAll()`
2325
+ **Purpose**: Get all page visits.
2326
+
2327
+ **Returns**: Array of all page visits
2328
+
2329
+ **When to Use**:
2330
+ - For analytics/reporting
2331
+ - To check page visit history
2332
+
2333
+ **Example**:
2334
+ ```javascript
2335
+ const visits = PageVisitManager.getAll();
2336
+ // Returns: Array of all page visits
2337
+ ```
2338
+
2339
+ ---
2340
+
2341
+ #### `PageVisitManager.getEntryPage()`
2342
+ **Purpose**: Get entry page (first page visited).
2343
+
2344
+ **Returns**: First page visit object or null
2345
+
2346
+ **When to Use**:
2347
+ - To get entry page information
2348
+ - For analytics
2349
+
2350
+ **Example**:
2351
+ ```javascript
2352
+ const entryPage = PageVisitManager.getEntryPage();
2353
+ // Returns: First page visit or null
2354
+ ```
2355
+
2356
+ ---
2357
+
2358
+ #### `PageVisitManager.getExitPage()`
2359
+ **Purpose**: Get exit page (last page visited).
2360
+
2361
+ **Returns**: Last page visit object or null
2362
+
2363
+ **When to Use**:
2364
+ - To get exit page information
2365
+ - For analytics
2366
+
2367
+ **Example**:
2368
+ ```javascript
2369
+ const exitPage = PageVisitManager.getExitPage();
2370
+ // Returns: Last page visit or null
2371
+ ```
2372
+
2373
+ ---
2374
+
2375
+ #### `PageVisitManager.initialize()`
2376
+ **Purpose**: Initialize page visit tracking.
2377
+
2378
+ **Logic**:
2379
+ - Tracks initial page visit
2380
+ - Sets up `beforeunload` listener for page unmount
2381
+ - Sets up `visibilitychange` listener for SPA navigation
2382
+
2383
+ **When to Use**:
2384
+ - On SDK initialization
2385
+ - Should be called early in initialization flow
2386
+
2387
+ **Example**:
2388
+ ```javascript
2389
+ PageVisitManager.initialize();
2390
+ // Tracks initial page and sets up listeners
2391
+ ```
2392
+
2393
+ ---
2394
+
2395
+ ### Reusability
2396
+
2397
+ ✅ **PageVisitManager.track()**: Reusable for tracking any page visit.
2398
+
2399
+ ✅ **PageVisitManager.trackUnmount()**: Reusable for tracking page unmount.
2400
+
2401
+ ✅ **PageVisitManager.getAll()**: Reusable for getting page visit data.
2402
+
2403
+ ---
2404
+
2405
+ ## Section 12: Data Transformation/Normalization
2406
+
2407
+ ### Purpose
2408
+ Transform sessionData from internal format (camelCase) to backend format (snake_case). Handles data normalization, field mapping, and ensures all required fields are present.
2409
+
2410
+ ### Why It Matters
2411
+ - Consistent data format for backend
2412
+ - Single place to handle data transformation
2413
+ - Prevents missing fields errors
2414
+ - Handles data shape normalization
2415
+ - Ensures proper timestamp formatting
2416
+
2417
+ ### DataTransformer Object
2418
+
2419
+ #### `DataTransformer.normalizeShape(raw)`
2420
+ **Purpose**: Normalize client session shape.
2421
+
2422
+ **Logic**:
2423
+ 1. Handles field aliases:
2424
+ - `pageViews` → `pagesViewed`
2425
+ - `visitedPages` → `pageVisits`
2426
+ - `id` → `sessionId`
2427
+ 2. Ensures arrays exist (`pageVisits`, `visited_pages`, `interactions`)
2428
+ 3. Normalizes timestamps to ISO strings
2429
+ 4. Normalizes page visit timestamps
2430
+
2431
+ **Parameters**: `raw` - Raw session data object
2432
+
2433
+ **Returns**: Normalized session data object
2434
+
2435
+ **When to Use**:
2436
+ - Before transforming to backend format
2437
+ - When loading data from storage
2438
+ - To ensure consistent data shape
2439
+
2440
+ **Example**:
2441
+ ```javascript
2442
+ const normalized = DataTransformer.normalizeShape(rawData);
2443
+ // Returns: Normalized data with aliases fixed and timestamps formatted
2444
+ ```
2445
+
2446
+ ---
2447
+
2448
+ #### `DataTransformer.toBackendFormat(data)`
2449
+ **Purpose**: Transform sessionData to backend-compatible format.
2450
+
2451
+ **Logic**:
2452
+ 1. Normalizes data shape using `normalizeShape()`
2453
+ 2. Maps camelCase fields to snake_case
2454
+ 3. Ensures `id` and `session_id` both set to sessionId value
2455
+ 4. Flattens nested structures
2456
+ 5. Removes internal-only fields (`utmData`, `isFirstPage`, `locationData`)
2457
+ 6. Adds chronological interactions
2458
+ 7. Ensures all required fields are present (even if null)
2459
+
2460
+ **Parameters**: `data` (optional) - Session data object. Defaults to `sessionData`.
2461
+
2462
+ **Returns**: Transformed object ready for backend
2463
+
2464
+ **Field Mapping**:
2465
+ - `sessionId` → `id` and `session_id` (both set to same value)
2466
+ - `siteId` → `site_id`
2467
+ - `userId` → `user_id`
2468
+ - `startTime` → `start_time`
2469
+ - `pagesViewed` → `pages_viewed`
2470
+ - `isBounce` → `is_bounce`
2471
+ - `entryPage` → `entry_page`
2472
+ - `exitPage` → `exit_page`
2473
+ - All location, browser, device, wallet, UTM fields already in snake_case
2474
+
2475
+ **Removed Fields**:
2476
+ - `utmData` (internal object, already flattened to utm_* fields)
2477
+ - `isFirstPage` (internal tracking flag)
2478
+ - `locationData` (internal object, already flattened)
2479
+
2480
+ **Example**:
2481
+ ```javascript
2482
+ // Internal format
2483
+ {
2484
+ sessionId: "abc-123",
2485
+ pagesViewed: 3,
2486
+ isBounce: false,
2487
+ startTime: "2024-12-15T10:30:00.000Z"
2488
+ }
2489
+
2490
+ // Backend format
2491
+ {
2492
+ id: "abc-123", // Same as session_id (PostgreSQL auto-generates)
2493
+ session_id: "abc-123",
2494
+ pages_viewed: 3,
2495
+ is_bounce: false,
2496
+ start_time: "2024-12-15T10:30:00.000Z",
2497
+ // ... all other fields in snake_case
2498
+ interactions: {
2499
+ ...interactions,
2500
+ chronological: [...] // Added chronological interactions
2501
+ }
2502
+ }
2503
+ ```
2504
+
2505
+ **When to Use**:
2506
+ - Before sending data to backend API
2507
+ - When preparing session data for storage
2508
+ - For data export/analytics
2509
+
2510
+ **Example**:
2511
+ ```javascript
2512
+ const backendData = DataTransformer.toBackendFormat();
2513
+ // Returns: Transformed data ready for backend
2514
+ ```
2515
+
2516
+ ---
2517
+
2518
+ #### `DataTransformer.toOverviewFormat(data)`
2519
+ **Purpose**: Transform for overview API (simplified format).
2520
+
2521
+ **Logic**:
2522
+ - Creates simplified format for overview/analytics endpoint
2523
+ - Includes essential fields only
2524
+ - Formats data for overview payload
2525
+
2526
+ **Parameters**: `data` (optional) - Session data object. Defaults to `sessionData`.
2527
+
2528
+ **Returns**: Transformed object for overview API
2529
+
2530
+ **When to Use**:
2531
+ - When sending data to overview/analytics endpoint
2532
+ - For summary/aggregated data
2533
+
2534
+ **Example**:
2535
+ ```javascript
2536
+ const overviewData = DataTransformer.toOverviewFormat();
2537
+ // Returns: Simplified format for overview API
2538
+ ```
2539
+
2540
+ ---
2541
+
2542
+ ### Reusability
2543
+
2544
+ ✅ **DataTransformer.normalizeShape()**: Reusable for normalizing any session data.
2545
+
2546
+ ✅ **DataTransformer.toBackendFormat()**: Reusable for transforming data to backend format.
2547
+
2548
+ ✅ **DataTransformer.toOverviewFormat()**: Reusable for overview/analytics data.
2549
+
2550
+ ---
2551
+
2552
+ ## Section 13: API Communication
2553
+
2554
+ ### Purpose
2555
+ Unified API client for all backend communication. Handles sending session data, overview data, custom events, and UTM events with proper error handling and retry logic.
2556
+
2557
+ ### Why It Matters
2558
+ - Single place to handle all API communication
2559
+ - Consistent error handling
2560
+ - Retry logic for reliability
2561
+ - Proper use of sendBeacon vs fetch
2562
+ - Debouncing to reduce network noise
2563
+
2564
+ ### APIClient Object
2565
+
2566
+ #### `APIClient.determineTrafficSource()`
2567
+ **Purpose**: Determine traffic source for overview data.
2568
+
2569
+ **Logic**:
2570
+ 1. Checks UTM source (highest priority)
2571
+ 2. Checks external referrer
2572
+ 3. Defaults to "direct"
2573
+
2574
+ **Returns**: Traffic source string
2575
+
2576
+ **When to Use**:
2577
+ - When building overview payload
2578
+ - For traffic source analysis
2579
+
2580
+ **Example**:
2581
+ ```javascript
2582
+ const source = APIClient.determineTrafficSource();
2583
+ // Returns: "google", "example.com", or "direct"
2584
+ ```
2585
+
2586
+ ---
2587
+
2588
+ #### `APIClient.send(endpoint, data, options)`
2589
+ **Purpose**: Send data to API endpoint (unified method).
2590
+
2591
+ **Logic**:
2592
+ 1. Transforms data using DataTransformer if needed
2593
+ 2. Uses sendBeacon if `useBeacon` is true (for beforeunload)
2594
+ 3. Uses fetch with keepalive for regular sends
2595
+ 4. Handles errors gracefully
2596
+ 5. Retries on failure (if retries > 0)
2597
+
2598
+ **Parameters**:
2599
+ - `endpoint` - API endpoint URL
2600
+ - `data` - Data to send
2601
+ - `options` (optional) - Configuration object:
2602
+ - `useBeacon` (default: false) - Use sendBeacon instead of fetch
2603
+ - `retries` (default: 0) - Number of retry attempts
2604
+ - `timeout` (default: 5000) - Request timeout in milliseconds
2605
+ - `transform` (default: true) - Transform data before sending
2606
+
2607
+ **Returns**: Promise that resolves on success
2608
+
2609
+ **When to Use**:
2610
+ - For all API communication
2611
+ - When sending any data to backend
2612
+
2613
+ **Example**:
2614
+ ```javascript
2615
+ // Regular send with retries
2616
+ await APIClient.send(CONFIG.API.TRACK, payload, {
2617
+ retries: 2,
2618
+ timeout: 5000
2619
+ });
2620
+
2621
+ // SendBeacon for beforeunload
2622
+ await APIClient.send(CONFIG.API.OVERVIEW, payload, {
2623
+ useBeacon: true,
2624
+ retries: 0
2625
+ });
2626
+ ```
2627
+
2628
+ ---
2629
+
2630
+ #### `APIClient.sendSessionData(data)`
2631
+ **Purpose**: Send session data to TRACK endpoint.
2632
+
2633
+ **Logic**:
2634
+ 1. Ensures session ID exists
2635
+ 2. Transforms data using DataTransformer.toBackendFormat()
2636
+ 3. Sends to TRACK endpoint
2637
+ 4. Retries on failure (2 attempts)
2638
+
2639
+ **Parameters**: `data` (optional) - Session data object. Defaults to `sessionData`.
2640
+
2641
+ **When to Use**:
2642
+ - On session initialization
2643
+ - Periodically during session (via interval)
2644
+ - On session updates
2645
+
2646
+ **Example**:
2647
+ ```javascript
2648
+ await APIClient.sendSessionData();
2649
+ // Sends current session data to TRACK endpoint
2650
+ ```
2651
+
2652
+ ---
2653
+
2654
+ #### `APIClient.sendOverviewData(useBeacon)`
2655
+ **Purpose**: Send overview data to OVERVIEW endpoint.
2656
+
2657
+ **Logic**:
2658
+ 1. Recalculates session duration
2659
+ 2. Updates bounce status
2660
+ 3. Builds overview payload with user journey
2661
+ 4. Determines traffic source
2662
+ 5. Sends to OVERVIEW endpoint
2663
+
2664
+ **Parameters**: `useBeacon` (optional, default: false) - Use sendBeacon instead of fetch
2665
+
2666
+ **Overview Payload Structure**:
2667
+ ```javascript
2668
+ {
2669
+ siteId: SITE_ID,
2670
+ userId: userId,
2671
+ sessionId: sessionId,
2672
+ sessionStartDate: "2024-12-15",
2673
+ totalSessions: 1,
2674
+ bounceSessions: 0,
2675
+ totalPagesVisited: 3,
2676
+ isBounce: false,
2677
+ userJourney: {
2678
+ [userId]: {
2679
+ currentSessionId: sessionId,
2680
+ country: "US",
2681
+ isWeb3User: true,
2682
+ walletAddress: "0x...",
2683
+ walletConnected: true,
2684
+ visitTimes: [Date],
2685
+ walletConnectedInVisit: [boolean],
2686
+ visitDuration: [number], // Seconds
2687
+ sessionPaths: [[paths]], // Array of arrays
2688
+ trafficSource: "google"
2689
+ }
2690
+ }
2691
+ }
2692
+ ```
2693
+
2694
+ **When to Use**:
2695
+ - At session end
2696
+ - Periodically (debounced)
2697
+ - On beforeunload (with useBeacon: true)
2698
+
2699
+ **Example**:
2700
+ ```javascript
2701
+ // Regular send
2702
+ await APIClient.sendOverviewData();
2703
+
2704
+ // Beforeunload send
2705
+ await APIClient.sendOverviewData(true);
2706
+ ```
2707
+
2708
+ ---
2709
+
2710
+ #### `APIClient.scheduleSendOverview(debounceMs, useBeacon)`
2711
+ **Purpose**: Schedule overview data send (debounced).
2712
+
2713
+ **Logic**:
2714
+ - Clears existing timeout if any
2715
+ - Sets new timeout to send overview data
2716
+ - Debounces to reduce network noise
2717
+
2718
+ **Parameters**:
2719
+ - `debounceMs` (optional, default: 10000) - Debounce time in milliseconds
2720
+ - `useBeacon` (optional, default: false) - Use sendBeacon
2721
+
2722
+ **When to Use**:
2723
+ - During session tracking interval
2724
+ - To debounce overview sends
2725
+
2726
+ **Example**:
2727
+ ```javascript
2728
+ APIClient.scheduleSendOverview(10000, false);
2729
+ // Schedules overview send in 10 seconds
2730
+ ```
2731
+
2732
+ ---
2733
+
2734
+ #### `APIClient.sendCustomEvent(eventKey, eventName, eventType, parameters)`
2735
+ **Purpose**: Send custom event to CUSTOM_EVENTS endpoint.
2736
+
2737
+ **Logic**:
2738
+ 1. Validates eventKey and eventName
2739
+ 2. Gets location data (non-blocking)
2740
+ 3. Updates session activity
2741
+ 4. Updates wallet info (non-blocking)
2742
+ 5. Converts parameters to array format
2743
+ 6. Builds custom event payload
2744
+ 7. Sends to CUSTOM_EVENTS endpoint
2745
+
2746
+ **Parameters**:
2747
+ - `eventKey` - Event key/identifier
2748
+ - `eventName` - Event name
2749
+ - `eventType` - Event type
2750
+ - `parameters` (optional) - Event parameters (object or array)
2751
+
2752
+ **Custom Event Payload Structure**:
2753
+ ```javascript
2754
+ {
2755
+ siteId: SITE_ID,
2756
+ eventKey: "evt_123",
2757
+ eventName: "Button Click",
2758
+ eventType: "click",
2759
+ eventDescription: "",
2760
+ parameters: [{ name: "buttonId", value: "submit", paramType: "string" }],
2761
+ pagePath: "/home",
2762
+ sessionIds: [sessionId],
2763
+ userIds: [userId],
2764
+ datetimes: ["2024-12-15T10:30:00.000Z"],
2765
+ geography: [{ city, country, region, timezone }],
2766
+ source: ["google"],
2767
+ web3user: [true],
2768
+ walletAddress: ["0x..."]
2769
+ }
2770
+ ```
2771
+
2772
+ **When to Use**:
2773
+ - When tracking custom events
2774
+ - For user-defined events
2775
+
2776
+ **Example**:
2777
+ ```javascript
2778
+ await APIClient.sendCustomEvent(
2779
+ "evt_123",
2780
+ "Button Click",
2781
+ "click",
2782
+ { buttonId: "submit", page: "/home" }
2783
+ );
2784
+ ```
2785
+
2786
+ ---
2787
+
2788
+ #### `APIClient.sendUTMEvent()`
2789
+ **Purpose**: Send UTM event to UTM_EVENTS endpoint.
2790
+
2791
+ **Logic**:
2792
+ 1. Extracts UTM parameters
2793
+ 2. Only sends if UTM parameters exist
2794
+ 3. Builds UTM event payload
2795
+ 4. Sends to UTM_EVENTS endpoint
2796
+
2797
+ **When to Use**:
2798
+ - On page load with UTM parameters
2799
+ - For UTM campaign tracking
2800
+
2801
+ **Example**:
2802
+ ```javascript
2803
+ await APIClient.sendUTMEvent();
2804
+ // Sends UTM data if UTM parameters exist
2805
+ ```
2806
+
2807
+ ---
2808
+
2809
+ ### Error Handling
2810
+
2811
+ **Retry Logic**:
2812
+ - Automatic retries on failure (configurable)
2813
+ - Exponential backoff (1 second delay)
2814
+ - Maximum retry attempts configurable
2815
+
2816
+ **sendBeacon vs fetch**:
2817
+ - **sendBeacon**: Used for beforeunload (fire-and-forget, no response)
2818
+ - **fetch**: Used for regular sends (with keepalive, can retry)
2819
+
2820
+ **Error Logging**:
2821
+ - Comprehensive error logging
2822
+ - Network error detection
2823
+ - CORS error detection
2824
+ - Ad blocker detection
2825
+
2826
+ ---
2827
+
2828
+ ### Reusability
2829
+
2830
+ ✅ **APIClient.send()**: Reusable for sending data to any endpoint.
2831
+
2832
+ ✅ **APIClient.sendSessionData()**: Reusable for session tracking.
2833
+
2834
+ ✅ **APIClient.sendOverviewData()**: Reusable for overview/analytics.
2835
+
2836
+ ✅ **APIClient.sendCustomEvent()**: Reusable for custom event tracking.
2837
+
2838
+ ---
2839
+
2840
+ ## Section 14: Event Trackers
2841
+
2842
+ ### Purpose
2843
+ Individual tracking modules for different event types. All trackers listen to DOM events and use `InteractionManager.add()` to store interactions.
2844
+
2845
+ ### Why It Matters
2846
+ - Modular tracking (can enable/disable individual trackers)
2847
+ - Single source of truth for interaction storage
2848
+ - Easy to add new trackers
2849
+ - Consistent interaction data structure
2850
+ - Error handling prevents tracker failures from breaking SDK
2851
+
2852
+ ### EventTrackers Object
2853
+
2854
+ All trackers are methods of the `EventTrackers` object. Each tracker:
2855
+ - Listens to specific DOM events
2856
+ - Extracts relevant data
2857
+ - Uses `InteractionManager.add()` to store interactions
2858
+ - Handles errors gracefully
2859
+
2860
+ ---
2861
+
2862
+ #### `EventTrackers.startClickTracking()`
2863
+ **Purpose**: Track click events on interactive elements.
2864
+
2865
+ **Logic**:
2866
+ 1. Listens to click events on document body
2867
+ 2. Finds closest interactive element (a, button, [role="button"], [data-cryptique-id])
2868
+ 3. Extracts element data (tagName, id, className, href, etc.)
2869
+ 4. Captures click coordinates
2870
+ 5. Stores interaction using `InteractionManager.add('clicks', ...)`
2871
+
2872
+ **Tracks**:
2873
+ - Click coordinates (x, y)
2874
+ - Element details (tagName, id, className, href, aria-label, role)
2875
+ - Path where click occurred
2876
+
2877
+ **When to Use**: Automatically called during initialization.
2878
+
2879
+ **Example**:
2880
+ ```javascript
2881
+ EventTrackers.startClickTracking();
2882
+ // Now tracking all clicks on interactive elements
2883
+ ```
2884
+
2885
+ ---
2886
+
2887
+ #### `EventTrackers.startFormTracking()`
2888
+ **Purpose**: Track form interactions (submissions, field changes, focus/blur, validation errors).
2889
+
2890
+ **Logic**:
2891
+ 1. Listens to form submit events
2892
+ 2. Listens to input/change events on form fields
2893
+ 3. Listens to focus/blur events on form fields
2894
+ 4. Listens to invalid events for validation errors
2895
+ 5. Stores interactions using `InteractionManager.add()`
2896
+
2897
+ **Tracks**:
2898
+ - Form submissions (formId, formAction, formMethod, fieldCount)
2899
+ - Field changes (fieldType, fieldName, fieldId, valueLength)
2900
+ - Focus/blur events (fieldType, fieldName, fieldId, formId)
2901
+ - Validation errors (fieldType, fieldName, validationMessage)
2902
+
2903
+ **When to Use**: Automatically called during initialization.
2904
+
2905
+ **Example**:
2906
+ ```javascript
2907
+ EventTrackers.startFormTracking();
2908
+ // Now tracking all form interactions
2909
+ ```
2910
+
2911
+ ---
2912
+
2913
+ #### `EventTrackers.startMediaTracking()`
2914
+ **Purpose**: Track media interactions (video play/pause, image clicks/loads).
2915
+
2916
+ **Logic**:
2917
+ 1. Listens to play/pause events on video elements
2918
+ 2. Listens to click events on image elements
2919
+ 3. Tracks existing images on page load
2920
+ 4. Stores interactions using `InteractionManager.add('mediaInteractions', ...)`
2921
+
2922
+ **Tracks**:
2923
+ - Video play/pause (mediaType, mediaId, mediaSrc, currentTime)
2924
+ - Image clicks (imageId, imageSrc, imageAlt, imageWidth, imageHeight)
2925
+ - Image loads (imageWidth, imageHeight)
2926
+
2927
+ **When to Use**: Automatically called during initialization.
2928
+
2929
+ **Example**:
2930
+ ```javascript
2931
+ EventTrackers.startMediaTracking();
2932
+ // Now tracking all media interactions
2933
+ ```
2934
+
2935
+ ---
2936
+
2937
+ #### `EventTrackers.startScrollTracking()`
2938
+ **Purpose**: Track scroll events with debouncing.
2939
+
2940
+ **Logic**:
2941
+ 1. Listens to scroll events
2942
+ 2. Debounces scroll events (150ms)
2943
+ 3. Calculates scroll position and percentage
2944
+ 4. Only tracks if scroll position changed significantly (>50px)
2945
+ 5. Stores interactions using `InteractionManager.add('scrollEvents', ...)`
2946
+
2947
+ **Tracks**:
2948
+ - Scroll position (scrollY, scrollPercent)
2949
+ - Window and document dimensions
2950
+ - Path where scroll occurred
2951
+
2952
+ **When to Use**: Automatically called during initialization.
2953
+
2954
+ **Example**:
2955
+ ```javascript
2956
+ EventTrackers.startScrollTracking();
2957
+ // Now tracking scroll events (debounced)
2958
+ ```
2959
+
2960
+ ---
2961
+
2962
+ #### `EventTrackers.startHoverTracking()`
2963
+ **Purpose**: Track hover events on interactive elements.
2964
+
2965
+ **Logic**:
2966
+ 1. Listens to mouseenter events
2967
+ 2. Only tracks hovers longer than 200ms
2968
+ 3. Tracks hover duration
2969
+ 4. Updates hover duration on mouseleave
2970
+ 5. Stores interactions using `InteractionManager.add('hoverEvents', ...)`
2971
+
2972
+ **Tracks**:
2973
+ - Element details (elementType, elementId, elementClass)
2974
+ - Hover duration (updated on mouseleave)
2975
+ - Path where hover occurred
2976
+
2977
+ **When to Use**: Automatically called during initialization.
2978
+
2979
+ **Example**:
2980
+ ```javascript
2981
+ EventTrackers.startHoverTracking();
2982
+ // Now tracking hover events (200ms threshold)
2983
+ ```
2984
+
2985
+ ---
2986
+
2987
+ #### `EventTrackers.startKeyboardTracking()`
2988
+ **Purpose**: Track keyboard shortcuts and special keys.
2989
+
2990
+ **Logic**:
2991
+ 1. Listens to keydown events
2992
+ 2. Tracks significant keys (Enter, Escape, Tab, Arrows, F-keys, etc.)
2993
+ 3. Tracks modifier key combinations (Ctrl, Alt, Shift, Meta)
2994
+ 4. Stores interactions using `InteractionManager.add('keyboardEvents', ...)`
2995
+
2996
+ **Tracks**:
2997
+ - Key pressed (key, keyCode)
2998
+ - Modifier keys (ctrlKey, altKey, shiftKey, metaKey)
2999
+ - Target element (tagName, id, className)
3000
+
3001
+ **When to Use**: Automatically called during initialization.
3002
+
3003
+ **Example**:
3004
+ ```javascript
3005
+ EventTrackers.startKeyboardTracking();
3006
+ // Now tracking keyboard shortcuts
3007
+ ```
3008
+
3009
+ ---
3010
+
3011
+ #### `EventTrackers.startCopyPasteTracking()`
3012
+ **Purpose**: Track copy and paste actions.
3013
+
3014
+ **Logic**:
3015
+ 1. Listens to copy events
3016
+ 2. Listens to paste events
3017
+ 3. Extracts selected text (copy) or target element (paste)
3018
+ 4. Stores interactions using `InteractionManager.add('copyPasteEvents', ...)`
3019
+
3020
+ **Tracks**:
3021
+ - Copy actions (selectedText, target element)
3022
+ - Paste actions (target element)
3023
+
3024
+ **When to Use**: Automatically called during initialization.
3025
+
3026
+ **Example**:
3027
+ ```javascript
3028
+ EventTrackers.startCopyPasteTracking();
3029
+ // Now tracking copy/paste actions
3030
+ ```
3031
+
3032
+ ---
3033
+
3034
+ #### `EventTrackers.startContextMenuTracking()`
3035
+ **Purpose**: Track right-click context menu usage.
3036
+
3037
+ **Logic**:
3038
+ 1. Listens to contextmenu events
3039
+ 2. Captures click coordinates
3040
+ 3. Extracts target element details
3041
+ 4. Stores interactions using `InteractionManager.add('contextMenuEvents', ...)`
3042
+
3043
+ **Tracks**:
3044
+ - Target element (tagName, id, className)
3045
+ - Click coordinates (x, y)
3046
+
3047
+ **When to Use**: Automatically called during initialization.
3048
+
3049
+ **Example**:
3050
+ ```javascript
3051
+ EventTrackers.startContextMenuTracking();
3052
+ // Now tracking context menu usage
3053
+ ```
3054
+
3055
+ ---
3056
+
3057
+ #### `EventTrackers.startDragDropTracking()`
3058
+ **Purpose**: Track drag and drop operations.
3059
+
3060
+ **Logic**:
3061
+ 1. Listens to dragstart events
3062
+ 2. Listens to drop events
3063
+ 3. Extracts dataTransfer information
3064
+ 4. Stores interactions using `InteractionManager.add('dragDropEvents', ...)`
3065
+
3066
+ **Tracks**:
3067
+ - Drag start (target element, dataTransfer types, files count)
3068
+ - Drop action (target element, dataTransfer types, files count)
3069
+
3070
+ **When to Use**: Automatically called during initialization.
3071
+
3072
+ **Example**:
3073
+ ```javascript
3074
+ EventTrackers.startDragDropTracking();
3075
+ // Now tracking drag/drop operations
3076
+ ```
3077
+
3078
+ ---
3079
+
3080
+ #### `EventTrackers.startTouchTracking()`
3081
+ **Purpose**: Track touch events for mobile devices.
3082
+
3083
+ **Logic**:
3084
+ 1. Listens to touchstart events
3085
+ 2. Listens to touchmove events
3086
+ 3. Listens to touchend events
3087
+ 4. Extracts touch coordinates and count
3088
+ 5. Stores interactions using `InteractionManager.add('touchEvents', ...)`
3089
+
3090
+ **Tracks**:
3091
+ - Touch start (touches count, coordinates, target element)
3092
+ - Touch move (touches count)
3093
+ - Touch end (touches count)
3094
+
3095
+ **When to Use**: Automatically called during initialization.
3096
+
3097
+ **Example**:
3098
+ ```javascript
3099
+ EventTrackers.startTouchTracking();
3100
+ // Now tracking touch events
3101
+ ```
3102
+
3103
+ ---
3104
+
3105
+ #### `EventTrackers.startWindowTracking()`
3106
+ **Purpose**: Track window resize, orientation changes, focus/blur.
3107
+
3108
+ **Logic**:
3109
+ 1. Listens to resize events (debounced 250ms)
3110
+ 2. Listens to orientationchange events
3111
+ 3. Listens to window focus/blur events
3112
+ 4. Extracts window dimensions and focused element
3113
+ 5. Stores interactions using `InteractionManager.add('windowEvents', ...)`
3114
+
3115
+ **Tracks**:
3116
+ - Window resize (dimensions, focused element)
3117
+ - Orientation change (orientation, focused element)
3118
+ - Window focus/blur (focused element)
3119
+
3120
+ **When to Use**: Automatically called during initialization.
3121
+
3122
+ **Example**:
3123
+ ```javascript
3124
+ EventTrackers.startWindowTracking();
3125
+ // Now tracking window events
3126
+ ```
3127
+
3128
+ ---
3129
+
3130
+ #### `EventTrackers.startPerformanceTracking()`
3131
+ **Purpose**: Track page load performance metrics.
3132
+
3133
+ **Logic**:
3134
+ 1. Listens to window load event
3135
+ 2. Waits 1 second for all resources to load
3136
+ 3. Extracts performance metrics (loadTime, domContentLoaded, firstPaint)
3137
+ 4. Stores interactions using `InteractionManager.add('performanceEvents', ...)`
3138
+
3139
+ **Tracks**:
3140
+ - Load time (navigationStart to loadEventEnd)
3141
+ - DOM content loaded time
3142
+ - First paint time
3143
+ - First contentful paint time
3144
+
3145
+ **When to Use**: Automatically called during initialization.
3146
+
3147
+ **Example**:
3148
+ ```javascript
3149
+ EventTrackers.startPerformanceTracking();
3150
+ // Now tracking page load performance
3151
+ ```
3152
+
3153
+ ---
3154
+
3155
+ #### `EventTrackers.startErrorTracking()`
3156
+ **Purpose**: Track JavaScript errors and unhandled promise rejections.
3157
+
3158
+ **Logic**:
3159
+ 1. Listens to window error events
3160
+ 2. Listens to unhandledrejection events
3161
+ 3. Extracts error details (message, filename, line, column, stack)
3162
+ 4. Stores interactions using `InteractionManager.add('errorEvents', ...)`
3163
+
3164
+ **Tracks**:
3165
+ - JavaScript errors (message, filename, lineno, colno, stack, errorElement)
3166
+ - Unhandled promise rejections (message, error)
3167
+
3168
+ **When to Use**: Automatically called during initialization.
3169
+
3170
+ **Example**:
3171
+ ```javascript
3172
+ EventTrackers.startErrorTracking();
3173
+ // Now tracking JavaScript errors
3174
+ ```
3175
+
3176
+ ---
3177
+
3178
+ #### `EventTrackers.startNetworkTracking()`
3179
+ **Purpose**: Track network errors (fetch and XMLHttpRequest).
3180
+
3181
+ **Logic**:
3182
+ 1. Wraps window.fetch to intercept requests
3183
+ 2. Wraps XMLHttpRequest.open and send
3184
+ 3. Only tracks error status codes (4xx, 5xx) and network errors
3185
+ 4. Extracts error details (url, method, status, error message, duration)
3186
+ 5. Stores interactions using `InteractionManager.add('networkEvents', ...)`
3187
+
3188
+ **Tracks**:
3189
+ - API errors (url, method, status, error, duration)
3190
+ - Network errors (url, method, status: 0, error, duration)
3191
+
3192
+ **When to Use**: Automatically called during initialization.
3193
+
3194
+ **Example**:
3195
+ ```javascript
3196
+ EventTrackers.startNetworkTracking();
3197
+ // Now tracking network errors (4xx, 5xx, network failures)
3198
+ ```
3199
+
3200
+ ---
3201
+
3202
+ #### `EventTrackers.startAdvancedFormTracking()`
3203
+ **Purpose**: Track form completion rates and abandonment.
3204
+
3205
+ **Logic**:
3206
+ 1. Tracks form start time on first field focus
3207
+ 2. Tracks form completion time on submit
3208
+ 3. Calculates completion time
3209
+ 4. Stores interactions using `InteractionManager.add('formAnalytics', ...)`
3210
+
3211
+ **Tracks**:
3212
+ - Form completion (formId, completionTime, fieldCount)
3213
+
3214
+ **When to Use**: Automatically called during initialization.
3215
+
3216
+ **Example**:
3217
+ ```javascript
3218
+ EventTrackers.startAdvancedFormTracking();
3219
+ // Now tracking form analytics
3220
+ ```
3221
+
3222
+ ---
3223
+
3224
+ #### `EventTrackers.initialize()`
3225
+ **Purpose**: Initialize all event trackers.
3226
+
3227
+ **Logic**:
3228
+ - Calls all tracker start methods in sequence
3229
+ - All trackers are started automatically
3230
+
3231
+ **When to Use**: Called during SDK initialization.
3232
+
3233
+ **Example**:
3234
+ ```javascript
3235
+ EventTrackers.initialize();
3236
+ // Starts all event trackers
3237
+ ```
3238
+
3239
+ ---
3240
+
3241
+ ### Tracker Categories
3242
+
3243
+ Each tracker stores interactions in specific categories:
3244
+ - `clicks` - Click events
3245
+ - `formSubmissions` - Form submissions
3246
+ - `fieldChanges` - Form field changes
3247
+ - `focusEvents` - Focus/blur events
3248
+ - `validationErrors` - Form validation errors
3249
+ - `mediaInteractions` - Video/audio/image interactions
3250
+ - `scrollEvents` - Scroll events
3251
+ - `hoverEvents` - Hover events
3252
+ - `keyboardEvents` - Keyboard shortcuts
3253
+ - `copyPasteEvents` - Copy/paste actions
3254
+ - `contextMenuEvents` - Context menu usage
3255
+ - `dragDropEvents` - Drag/drop operations
3256
+ - `touchEvents` - Touch events
3257
+ - `windowEvents` - Window events (resize, orientation, focus/blur)
3258
+ - `performanceEvents` - Performance metrics
3259
+ - `errorEvents` - JavaScript errors
3260
+ - `networkEvents` - Network errors
3261
+ - `formAnalytics` - Form analytics
3262
+
3263
+ ---
3264
+
3265
+ ### Error Handling
3266
+
3267
+ All trackers have try-catch blocks to prevent failures from breaking the SDK:
3268
+ - Errors are logged to console
3269
+ - Tracker failures don't affect other trackers
3270
+ - SDK continues to function even if a tracker fails
3271
+
3272
+ ---
3273
+
3274
+ ### Reusability
3275
+
3276
+ ✅ **Modular Design**: Each tracker is independent and can be enabled/disabled.
3277
+
3278
+ ✅ **Consistent API**: All trackers use `InteractionManager.add()` to store interactions.
3279
+
3280
+ ✅ **Easy to Extend**: Add new trackers by following the same pattern.
3281
+
3282
+ ✅ **Error Resilient**: Trackers handle errors gracefully without breaking the SDK.
3283
+
3284
+ ---
3285
+
3286
+ ## Section 15: Initialization
3287
+
3288
+ ### Purpose
3289
+ Orchestrates all sections in the correct order. Handles initialization, session tracking intervals, beforeunload events, and error recovery.
3290
+
3291
+ ### Why It Matters
3292
+ - Single entry point for SDK initialization
3293
+ - Clear initialization order
3294
+ - Error recovery and fallbacks
3295
+ - Prevents duplicate initialization
3296
+ - Handles unsent session data from previous page loads
3297
+
3298
+ ### Initializer Object
3299
+
3300
+ The `Initializer` object contains all initialization functions and orchestrates the SDK startup.
3301
+
3302
+ ---
3303
+
3304
+ #### `Initializer.checkForUnsentData()`
3305
+ **Purpose**: Check for unsent session data from previous page loads.
3306
+
3307
+ **Logic**:
3308
+ 1. Checks localStorage for `cryptique_last_session`
3309
+ 2. Sends stored session data if found
3310
+ 3. Clears stored data after successful send
3311
+
3312
+ **When to Use**: Called during SDK initialization.
3313
+
3314
+ **Example**:
3315
+ ```javascript
3316
+ await Initializer.checkForUnsentData();
3317
+ // Sends any unsent session data from previous page load
3318
+ ```
3319
+
3320
+ ---
3321
+
3322
+ #### `Initializer.initializeSessionData()`
3323
+ **Purpose**: Initialize session data structure.
3324
+
3325
+ **Logic**:
3326
+ 1. Gets or creates session ID
3327
+ 2. Gets or creates user ID
3328
+ 3. Initializes session data structure
3329
+ 4. Initializes interactions
3330
+ 5. Initializes page visits
3331
+
3332
+ **When to Use**: Called during SDK initialization.
3333
+
3334
+ **Example**:
3335
+ ```javascript
3336
+ Initializer.initializeSessionData();
3337
+ // Initializes all session data structures
3338
+ ```
3339
+
3340
+ ---
3341
+
3342
+ #### `Initializer.initializeLocation()`
3343
+ **Purpose**: Initialize location data (non-blocking).
3344
+
3345
+ **Logic**:
3346
+ - Starts location fetch asynchronously
3347
+ - Doesn't block initialization
3348
+ - Errors are non-critical
3349
+
3350
+ **When to Use**: Called during SDK initialization.
3351
+
3352
+ **Example**:
3353
+ ```javascript
3354
+ Initializer.initializeLocation();
3355
+ // Starts location fetch (non-blocking)
3356
+ ```
3357
+
3358
+ ---
3359
+
3360
+ #### `Initializer.initializeBrowserDevice()`
3361
+ **Purpose**: Initialize browser/device detection.
3362
+
3363
+ **Logic**:
3364
+ - Calls BrowserDeviceManager.detect()
3365
+ - Extracts browser/device information
3366
+ - Stores in sessionData
3367
+
3368
+ **When to Use**: Called during SDK initialization.
3369
+
3370
+ **Example**:
3371
+ ```javascript
3372
+ Initializer.initializeBrowserDevice();
3373
+ // Detects and stores browser/device info
3374
+ ```
3375
+
3376
+ ---
3377
+
3378
+ #### `Initializer.initializeUTM()`
3379
+ **Purpose**: Initialize UTM parameters.
3380
+
3381
+ **Logic**:
3382
+ - Calls UTMManager.extract()
3383
+ - Extracts UTM parameters from URL
3384
+ - Stores in sessionData
3385
+
3386
+ **When to Use**: Called during SDK initialization.
3387
+
3388
+ **Example**:
3389
+ ```javascript
3390
+ Initializer.initializeUTM();
3391
+ // Extracts and stores UTM parameters
3392
+ ```
3393
+
3394
+ ---
3395
+
3396
+ #### `Initializer.initializeWallet()`
3397
+ **Purpose**: Initialize wallet/Web3 detection.
3398
+
3399
+ **Logic**:
3400
+ - Calls WalletManager.initialize()
3401
+ - Detects wallets and chains
3402
+ - Sets up wallet event listeners
3403
+
3404
+ **When to Use**: Called during SDK initialization.
3405
+
3406
+ **Example**:
3407
+ ```javascript
3408
+ Initializer.initializeWallet();
3409
+ // Initializes wallet detection
3410
+ ```
3411
+
3412
+ ---
3413
+
3414
+ #### `Initializer.trackInitialPage()`
3415
+ **Purpose**: Track initial page visit.
3416
+
3417
+ **Logic**:
3418
+ - Calls PageVisitManager.track()
3419
+ - Records page mount time
3420
+ - Sets entry page flag
3421
+
3422
+ **When to Use**: Called during SDK initialization.
3423
+
3424
+ **Example**:
3425
+ ```javascript
3426
+ Initializer.trackInitialPage();
3427
+ // Tracks the initial page visit
3428
+ ```
3429
+
3430
+ ---
3431
+
3432
+ #### `Initializer.startSessionTracking()`
3433
+ **Purpose**: Start session tracking interval.
3434
+
3435
+ **Logic**:
3436
+ 1. Clears any existing interval
3437
+ 2. Sets up interval (every 15 seconds)
3438
+ 3. In each interval:
3439
+ - Updates session duration
3440
+ - Updates wallet info (non-blocking)
3441
+ - Updates session activity
3442
+ - Syncs data from storage
3443
+ - Updates bounce status
3444
+ - Saves session to storage
3445
+ - Sends session data
3446
+ - Schedules overview send (debounced)
3447
+
3448
+ **Interval**: 15 seconds (CONFIG.INTERVALS.SESSION_TRACKING_MS)
3449
+
3450
+ **When to Use**: Called during SDK initialization.
3451
+
3452
+ **Example**:
3453
+ ```javascript
3454
+ Initializer.startSessionTracking();
3455
+ // Starts periodic session tracking
3456
+ ```
3457
+
3458
+ ---
3459
+
3460
+ #### `Initializer.setupBeforeUnload()`
3461
+ **Purpose**: Set up beforeunload handler for final data send.
3462
+
3463
+ **Logic**:
3464
+ 1. Listens to beforeunload event
3465
+ 2. Syncs all data from storage
3466
+ 3. Tracks page unmount
3467
+ 4. Updates final session duration
3468
+ 5. Updates bounce status
3469
+ 6. Clears pending debounced sends
3470
+ 7. Sends final overview data (sendBeacon)
3471
+ 8. Sends final session data (sendBeacon)
3472
+ 9. Stores backup in localStorage if send fails
3473
+ 10. Clears tracking interval
3474
+
3475
+ **When to Use**: Called during SDK initialization.
3476
+
3477
+ **Example**:
3478
+ ```javascript
3479
+ Initializer.setupBeforeUnload();
3480
+ // Sets up beforeunload handler
3481
+ ```
3482
+
3483
+ ---
3484
+
3485
+ #### `Initializer.sendInitialSessionData()`
3486
+ **Purpose**: Send initial session data after initialization.
3487
+
3488
+ **Logic**:
3489
+ 1. Waits 500ms for location data to load
3490
+ 2. Sends initial session data
3491
+ 3. Errors are non-critical (will retry in interval)
3492
+
3493
+ **When to Use**: Called during SDK initialization.
3494
+
3495
+ **Example**:
3496
+ ```javascript
3497
+ await Initializer.sendInitialSessionData();
3498
+ // Sends initial session data
3499
+ ```
3500
+
3501
+ ---
3502
+
3503
+ #### `Initializer.initialize()`
3504
+ **Purpose**: Main initialization function that orchestrates all sections.
3505
+
3506
+ **Initialization Order**:
3507
+ 1. Check sessionStorage availability
3508
+ 2. Check for unsent session data
3509
+ 3. Initialize session data structure
3510
+ 4. Initialize location (non-blocking)
3511
+ 5. Initialize browser/device detection
3512
+ 6. Initialize UTM parameters
3513
+ 7. Initialize wallet/Web3 detection
3514
+ 8. Track initial page visit
3515
+ 9. Start event trackers
3516
+ 10. Start session tracking interval
3517
+ 11. Set up beforeunload handler
3518
+ 12. Mark SDK as initialized
3519
+ 13. Send initial session data (non-blocking)
3520
+
3521
+ **When to Use**: Called automatically on DOMContentLoaded or immediately if DOM already loaded.
3522
+
3523
+ **Example**:
3524
+ ```javascript
3525
+ await Initializer.initialize();
3526
+ // Initializes entire SDK
3527
+ ```
3528
+
3529
+ ---
3530
+
3531
+ ### Auto-Initialization
3532
+
3533
+ The SDK automatically initializes when:
3534
+ - DOM is ready (DOMContentLoaded event)
3535
+ - DOM is already loaded (immediate initialization)
3536
+
3537
+ **No manual initialization required** - the SDK initializes automatically when the script loads.
3538
+
3539
+ ---
3540
+
3541
+ ### Error Handling
3542
+
3543
+ All initialization functions have try-catch blocks:
3544
+ - Errors in one section don't break other sections
3545
+ - Non-critical errors are logged as warnings
3546
+ - Critical errors are logged as errors
3547
+ - SDK continues to function even if some sections fail
3548
+
3549
+ ---
3550
+
3551
+ ### Reusability
3552
+
3553
+ ✅ **Modular Design**: Each initialization step is independent.
3554
+
3555
+ ✅ **Error Resilient**: Failures in one section don't break others.
3556
+
3557
+ ✅ **Auto-Initialization**: SDK initializes automatically.
3558
+
3559
+ ✅ **Recovery**: Handles unsent session data from previous page loads.
3560
+
3561
+ ---
3562
+
3563
+ ## Notes
3564
+
3565
+ - All functions are designed to be self-contained and reusable
3566
+ - Error handling is built into each function
3567
+ - Functions follow consistent naming conventions
3568
+ - Documentation is kept in sync with code
3569
+ - This guide is a living document - update as you add new functions
3570
+ - **Field Naming**: Internal uses camelCase, backend uses snake_case
3571
+ - **Transformation**: Data is transformed on send, not stored
3572
+ - **Flattening**: All nested objects are flattened before sending to backend
3573
+
3574
+ ## Notes
3575
+
3576
+ - All functions are designed to be self-contained and reusable
3577
+ - Error handling is built into each function
3578
+ - Functions follow consistent naming conventions
3579
+ - Documentation is kept in sync with code
3580
+ - This guide is a living document - update as you add new functions