user-analytics-tracker 1.2.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/CHANGELOG.md +59 -0
- package/LICENSE +22 -0
- package/README.md +696 -0
- package/dist/index.cjs.js +1835 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.cts +415 -0
- package/dist/index.d.ts +415 -0
- package/dist/index.esm.js +1811 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +111 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for the analytics tracker package
|
|
3
|
+
*/
|
|
4
|
+
type NetworkType = 'wifi' | 'hotspot' | 'cellular' | 'ethernet' | 'unknown';
|
|
5
|
+
type DeviceType = 'mobile' | 'tablet' | 'desktop' | 'unknown';
|
|
6
|
+
interface NetworkInfo {
|
|
7
|
+
type: NetworkType;
|
|
8
|
+
effectiveType?: string;
|
|
9
|
+
downlink?: number;
|
|
10
|
+
rtt?: number;
|
|
11
|
+
saveData?: boolean;
|
|
12
|
+
connectionType?: string;
|
|
13
|
+
}
|
|
14
|
+
interface DeviceInfo {
|
|
15
|
+
type: DeviceType;
|
|
16
|
+
os: string;
|
|
17
|
+
osVersion: string;
|
|
18
|
+
browser: string;
|
|
19
|
+
browserVersion: string;
|
|
20
|
+
screenResolution: string;
|
|
21
|
+
deviceModel: string;
|
|
22
|
+
deviceBrand: string;
|
|
23
|
+
language: string;
|
|
24
|
+
timezone: string;
|
|
25
|
+
userAgent: string;
|
|
26
|
+
deviceMemory?: number;
|
|
27
|
+
hardwareConcurrency?: number;
|
|
28
|
+
touchSupport: boolean;
|
|
29
|
+
pixelRatio: number;
|
|
30
|
+
colorDepth: number;
|
|
31
|
+
orientation: string;
|
|
32
|
+
cpuArchitecture: string;
|
|
33
|
+
}
|
|
34
|
+
interface LocationInfo {
|
|
35
|
+
lat?: number | null;
|
|
36
|
+
lon?: number | null;
|
|
37
|
+
accuracy?: number | null;
|
|
38
|
+
permission?: 'granted' | 'denied' | 'prompt' | 'unsupported';
|
|
39
|
+
source: 'gps' | 'ip' | 'unknown';
|
|
40
|
+
ts?: string;
|
|
41
|
+
ip?: string | null;
|
|
42
|
+
country?: string;
|
|
43
|
+
countryCode?: string;
|
|
44
|
+
city?: string;
|
|
45
|
+
region?: string;
|
|
46
|
+
timezone?: string;
|
|
47
|
+
}
|
|
48
|
+
interface AttributionInfo {
|
|
49
|
+
landingUrl: string;
|
|
50
|
+
path: string;
|
|
51
|
+
hostname: string;
|
|
52
|
+
referrerUrl: string | null;
|
|
53
|
+
referrerDomain: string | null;
|
|
54
|
+
navigationType: 'navigate' | 'reload' | 'back_forward' | 'prerender' | 'unknown';
|
|
55
|
+
isReload: boolean;
|
|
56
|
+
isBackForward: boolean;
|
|
57
|
+
sessionStart?: string | null;
|
|
58
|
+
utm_source?: string | null;
|
|
59
|
+
utm_medium?: string | null;
|
|
60
|
+
utm_campaign?: string | null;
|
|
61
|
+
utm_term?: string | null;
|
|
62
|
+
utm_content?: string | null;
|
|
63
|
+
gclid?: string | null;
|
|
64
|
+
fbclid?: string | null;
|
|
65
|
+
ttclid?: string | null;
|
|
66
|
+
msclkid?: string | null;
|
|
67
|
+
dmclid?: string | null;
|
|
68
|
+
firstTouch?: Record<string, string | null> | null;
|
|
69
|
+
lastTouch?: Record<string, string | null> | null;
|
|
70
|
+
}
|
|
71
|
+
interface IPLocation {
|
|
72
|
+
ip: string;
|
|
73
|
+
country?: string;
|
|
74
|
+
countryCode?: string;
|
|
75
|
+
region?: string;
|
|
76
|
+
regionName?: string;
|
|
77
|
+
city?: string;
|
|
78
|
+
lat?: number;
|
|
79
|
+
lon?: number;
|
|
80
|
+
timezone?: string;
|
|
81
|
+
isp?: string;
|
|
82
|
+
org?: string;
|
|
83
|
+
as?: string;
|
|
84
|
+
query?: string;
|
|
85
|
+
}
|
|
86
|
+
interface AnalyticsConfig {
|
|
87
|
+
apiEndpoint: string;
|
|
88
|
+
autoSend?: boolean;
|
|
89
|
+
enableLocation?: boolean;
|
|
90
|
+
enableIPGeolocation?: boolean;
|
|
91
|
+
enableNetworkDetection?: boolean;
|
|
92
|
+
enableDeviceDetection?: boolean;
|
|
93
|
+
enableAttribution?: boolean;
|
|
94
|
+
sessionStoragePrefix?: string;
|
|
95
|
+
localStoragePrefix?: string;
|
|
96
|
+
}
|
|
97
|
+
interface AnalyticsEvent {
|
|
98
|
+
sessionId: string;
|
|
99
|
+
pageUrl: string;
|
|
100
|
+
timestamp: Date | string;
|
|
101
|
+
networkInfo?: NetworkInfo;
|
|
102
|
+
deviceInfo?: DeviceInfo;
|
|
103
|
+
location?: LocationInfo;
|
|
104
|
+
attribution?: AttributionInfo;
|
|
105
|
+
ipLocation?: IPLocation;
|
|
106
|
+
userId?: string;
|
|
107
|
+
customData?: Record<string, any>;
|
|
108
|
+
eventId?: string;
|
|
109
|
+
eventName?: string;
|
|
110
|
+
eventParameters?: Record<string, any>;
|
|
111
|
+
}
|
|
112
|
+
interface UseAnalyticsReturn {
|
|
113
|
+
sessionId: string | null;
|
|
114
|
+
networkInfo: NetworkInfo | null;
|
|
115
|
+
deviceInfo: DeviceInfo | null;
|
|
116
|
+
location: LocationInfo | null;
|
|
117
|
+
attribution: AttributionInfo | null;
|
|
118
|
+
pageVisits: number;
|
|
119
|
+
interactions: number;
|
|
120
|
+
logEvent: (customData?: Record<string, any>) => Promise<void>;
|
|
121
|
+
trackEvent: (eventName: string, parameters?: Record<string, any>) => Promise<void>;
|
|
122
|
+
trackPageView: (pageName?: string, parameters?: Record<string, any>) => Promise<void>;
|
|
123
|
+
incrementInteraction: () => void;
|
|
124
|
+
refresh: () => Promise<{
|
|
125
|
+
net: NetworkInfo;
|
|
126
|
+
dev: DeviceInfo;
|
|
127
|
+
attr: AttributionInfo;
|
|
128
|
+
loc: LocationInfo;
|
|
129
|
+
}>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Network Type Detector
|
|
134
|
+
* Detects WiFi, Mobile Data (Cellular), Hotspot, Ethernet, or Unknown
|
|
135
|
+
*/
|
|
136
|
+
declare class NetworkDetector {
|
|
137
|
+
static detect(): NetworkInfo;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Device Information Detector
|
|
142
|
+
* Detects device type, OS, browser, and hardware specs
|
|
143
|
+
*/
|
|
144
|
+
declare class DeviceDetector {
|
|
145
|
+
private static getRealDeviceInfo;
|
|
146
|
+
private static detectBrowser;
|
|
147
|
+
static detect(): Promise<DeviceInfo>;
|
|
148
|
+
private static detectBrand;
|
|
149
|
+
private static getDefaultDeviceInfo;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Location Detector
|
|
154
|
+
* Detects GPS location with consent management, falls back to IP-based location API
|
|
155
|
+
* IP-based location works automatically without user permission
|
|
156
|
+
*/
|
|
157
|
+
declare class LocationDetector {
|
|
158
|
+
private static locationFetchingRef;
|
|
159
|
+
private static lastLocationRef;
|
|
160
|
+
private static locationConsentLoggedRef;
|
|
161
|
+
private static ipLocationFetchingRef;
|
|
162
|
+
private static lastIPLocationRef;
|
|
163
|
+
/**
|
|
164
|
+
* Detect location using IP-based API only (no GPS, no permission needed)
|
|
165
|
+
* Fast and automatic - works immediately without user interaction
|
|
166
|
+
*/
|
|
167
|
+
static detectIPOnly(): Promise<LocationInfo>;
|
|
168
|
+
/**
|
|
169
|
+
* Detect location with automatic consent granted
|
|
170
|
+
* Tries GPS first (if available), then falls back to IP-based location
|
|
171
|
+
* Automatically sets location consent to bypass permission checks
|
|
172
|
+
*/
|
|
173
|
+
static detectWithAutoConsent(): Promise<LocationInfo>;
|
|
174
|
+
/**
|
|
175
|
+
* Get browser GPS location
|
|
176
|
+
* Respects location consent (set via MSISDN entry)
|
|
177
|
+
* Falls back to IP-based location automatically if GPS fails
|
|
178
|
+
*/
|
|
179
|
+
static detect(): Promise<LocationInfo>;
|
|
180
|
+
/**
|
|
181
|
+
* Get location from IP-based public API (client-side)
|
|
182
|
+
* Works without user permission, good fallback when GPS is unavailable
|
|
183
|
+
* Uses ip-api.com free tier (no API key required, 45 requests/minute)
|
|
184
|
+
*/
|
|
185
|
+
private static getIPBasedLocation;
|
|
186
|
+
/**
|
|
187
|
+
* Clear location cache (useful when consent is granted)
|
|
188
|
+
*/
|
|
189
|
+
static clearCache(): void;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Attribution Detector
|
|
194
|
+
* Detects UTM parameters, referrer, navigation type, and tracks first/last touch
|
|
195
|
+
*/
|
|
196
|
+
declare class AttributionDetector {
|
|
197
|
+
static detect(): AttributionInfo;
|
|
198
|
+
private static getDefaultAttribution;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Analytics Service
|
|
203
|
+
* Sends analytics events to your backend API
|
|
204
|
+
*
|
|
205
|
+
* Supports both relative paths (e.g., '/api/analytics') and full URLs (e.g., 'https://your-server.com/api/analytics')
|
|
206
|
+
*/
|
|
207
|
+
declare class AnalyticsService {
|
|
208
|
+
private static apiEndpoint;
|
|
209
|
+
/**
|
|
210
|
+
* Configure the analytics API endpoint
|
|
211
|
+
*
|
|
212
|
+
* @param config - Configuration object
|
|
213
|
+
* @param config.apiEndpoint - Your backend API endpoint URL
|
|
214
|
+
* - Relative path: '/api/analytics' (sends to same domain)
|
|
215
|
+
* - Full URL: 'https://your-server.com/api/analytics' (sends to your server)
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```typescript
|
|
219
|
+
* // Use your own server
|
|
220
|
+
* AnalyticsService.configure({
|
|
221
|
+
* apiEndpoint: 'https://api.yourcompany.com/analytics'
|
|
222
|
+
* });
|
|
223
|
+
*
|
|
224
|
+
* // Or use relative path (same domain)
|
|
225
|
+
* AnalyticsService.configure({
|
|
226
|
+
* apiEndpoint: '/api/analytics'
|
|
227
|
+
* });
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
static configure(config: {
|
|
231
|
+
apiEndpoint: string;
|
|
232
|
+
}): void;
|
|
233
|
+
/**
|
|
234
|
+
* Generate a random event ID
|
|
235
|
+
*/
|
|
236
|
+
private static generateEventId;
|
|
237
|
+
/**
|
|
238
|
+
* Track user journey/analytics event
|
|
239
|
+
*/
|
|
240
|
+
static trackEvent(event: Omit<AnalyticsEvent, 'eventId' | 'timestamp'>): Promise<void>;
|
|
241
|
+
/**
|
|
242
|
+
* Track user journey with full context
|
|
243
|
+
*/
|
|
244
|
+
static trackUserJourney({ sessionId, pageUrl, networkInfo, deviceInfo, location, attribution, ipLocation, userId, customData, pageVisits, interactions, }: {
|
|
245
|
+
sessionId: string;
|
|
246
|
+
pageUrl: string;
|
|
247
|
+
networkInfo?: NetworkInfo;
|
|
248
|
+
deviceInfo?: DeviceInfo;
|
|
249
|
+
location?: any;
|
|
250
|
+
attribution?: AttributionInfo;
|
|
251
|
+
ipLocation?: any;
|
|
252
|
+
userId?: string;
|
|
253
|
+
customData?: Record<string, any>;
|
|
254
|
+
pageVisits?: number;
|
|
255
|
+
interactions?: number;
|
|
256
|
+
}): Promise<void>;
|
|
257
|
+
/**
|
|
258
|
+
* Track a custom event (Firebase/GA-style)
|
|
259
|
+
* Automatically collects device, network, location context if available
|
|
260
|
+
*
|
|
261
|
+
* @param eventName - Name of the event (e.g., 'button_click', 'purchase', 'sign_up')
|
|
262
|
+
* @param parameters - Event-specific parameters (optional)
|
|
263
|
+
* @param context - Optional context override (auto-collected if not provided)
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```typescript
|
|
267
|
+
* // Simple event tracking
|
|
268
|
+
* AnalyticsService.logEvent('button_click', {
|
|
269
|
+
* button_name: 'signup',
|
|
270
|
+
* button_location: 'header'
|
|
271
|
+
* });
|
|
272
|
+
*
|
|
273
|
+
* // Purchase event
|
|
274
|
+
* AnalyticsService.logEvent('purchase', {
|
|
275
|
+
* transaction_id: 'T12345',
|
|
276
|
+
* value: 29.99,
|
|
277
|
+
* currency: 'USD',
|
|
278
|
+
* items: [{ id: 'item1', name: 'Product 1', price: 29.99 }]
|
|
279
|
+
* });
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
static logEvent(eventName: string, parameters?: Record<string, any>, context?: {
|
|
283
|
+
sessionId?: string;
|
|
284
|
+
pageUrl?: string;
|
|
285
|
+
networkInfo?: NetworkInfo;
|
|
286
|
+
deviceInfo?: DeviceInfo;
|
|
287
|
+
location?: any;
|
|
288
|
+
attribution?: AttributionInfo;
|
|
289
|
+
userId?: string;
|
|
290
|
+
}): Promise<void>;
|
|
291
|
+
/**
|
|
292
|
+
* Track a page view event (Firebase/GA-style)
|
|
293
|
+
* Automatically collects device, network, location context
|
|
294
|
+
*
|
|
295
|
+
* @param pageName - Optional page name (defaults to current URL pathname)
|
|
296
|
+
* @param parameters - Optional page view parameters
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```typescript
|
|
300
|
+
* // Track current page view
|
|
301
|
+
* AnalyticsService.trackPageView();
|
|
302
|
+
*
|
|
303
|
+
* // Track with custom page name
|
|
304
|
+
* AnalyticsService.trackPageView('/dashboard', {
|
|
305
|
+
* page_title: 'Dashboard',
|
|
306
|
+
* user_type: 'premium'
|
|
307
|
+
* });
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
static trackPageView(pageName?: string, parameters?: Record<string, any>): Promise<void>;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
interface UseAnalyticsOptions {
|
|
314
|
+
autoSend?: boolean;
|
|
315
|
+
config?: Partial<AnalyticsConfig>;
|
|
316
|
+
onReady?: (data: {
|
|
317
|
+
sessionId: string;
|
|
318
|
+
networkInfo: NetworkInfo;
|
|
319
|
+
deviceInfo: DeviceInfo;
|
|
320
|
+
location: LocationInfo;
|
|
321
|
+
attribution: AttributionInfo;
|
|
322
|
+
}) => void;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* React hook for analytics tracking
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```tsx
|
|
329
|
+
* const { sessionId, networkInfo, deviceInfo, logEvent } = useAnalytics({
|
|
330
|
+
* autoSend: true,
|
|
331
|
+
* config: { apiEndpoint: '/api/analytics' }
|
|
332
|
+
* });
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
declare function useAnalytics(options?: UseAnalyticsOptions): UseAnalyticsReturn;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Storage utilities for analytics tracking
|
|
339
|
+
*/
|
|
340
|
+
declare const loadJSON: <T>(key: string) => T | null;
|
|
341
|
+
declare const saveJSON: (key: string, obj: unknown) => void;
|
|
342
|
+
declare const loadSessionJSON: <T>(key: string) => T | null;
|
|
343
|
+
declare const saveSessionJSON: (key: string, obj: unknown) => void;
|
|
344
|
+
/**
|
|
345
|
+
* Generate or retrieve a user ID from localStorage
|
|
346
|
+
*/
|
|
347
|
+
declare function getOrCreateUserId(length?: number): string;
|
|
348
|
+
/**
|
|
349
|
+
* Track page visits with localStorage
|
|
350
|
+
*/
|
|
351
|
+
declare function trackPageVisit(): number;
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Location Consent Manager
|
|
355
|
+
* When user enters MSISDN, they implicitly consent to location tracking
|
|
356
|
+
* This utility manages the consent state and prevents unnecessary permission prompts
|
|
357
|
+
*/
|
|
358
|
+
/**
|
|
359
|
+
* Set location consent as granted (when MSISDN is provided)
|
|
360
|
+
*/
|
|
361
|
+
declare function setLocationConsentGranted(): void;
|
|
362
|
+
/**
|
|
363
|
+
* Check if location consent has been granted
|
|
364
|
+
*/
|
|
365
|
+
declare function hasLocationConsent(): boolean;
|
|
366
|
+
/**
|
|
367
|
+
* Get location consent timestamp
|
|
368
|
+
*/
|
|
369
|
+
declare function getLocationConsentTimestamp(): string | null;
|
|
370
|
+
/**
|
|
371
|
+
* Clear location consent (for testing or user revocation)
|
|
372
|
+
*/
|
|
373
|
+
declare function clearLocationConsent(): void;
|
|
374
|
+
/**
|
|
375
|
+
* Check if MSISDN is provided and set consent accordingly
|
|
376
|
+
* Call this whenever MSISDN is detected
|
|
377
|
+
*/
|
|
378
|
+
declare function checkAndSetLocationConsent(msisdn?: string | null): boolean;
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* IP Geolocation Service
|
|
382
|
+
* Fetches location data (country, region, city) from user's IP address
|
|
383
|
+
* Uses free tier of ip-api.com (no API key required, 45 requests/minute)
|
|
384
|
+
*/
|
|
385
|
+
/**
|
|
386
|
+
* Get public IP address using ip-api.com
|
|
387
|
+
* Free tier: 45 requests/minute, no API key required
|
|
388
|
+
*
|
|
389
|
+
* @returns Promise<string | null> - The public IP address, or null if unavailable
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```typescript
|
|
393
|
+
* const ip = await getPublicIP();
|
|
394
|
+
* console.log('Your IP:', ip); // e.g., "203.0.113.42"
|
|
395
|
+
* ```
|
|
396
|
+
*/
|
|
397
|
+
declare function getPublicIP(): Promise<string | null>;
|
|
398
|
+
/**
|
|
399
|
+
* Get location from IP address using ip-api.com
|
|
400
|
+
* Free tier: 45 requests/minute, no API key required
|
|
401
|
+
*
|
|
402
|
+
* Alternative services:
|
|
403
|
+
* - ipapi.co (requires API key for production)
|
|
404
|
+
* - ipgeolocation.io (requires API key)
|
|
405
|
+
* - ip-api.com (free tier available)
|
|
406
|
+
*/
|
|
407
|
+
declare function getIPLocation(ip: string): Promise<IPLocation | null>;
|
|
408
|
+
/**
|
|
409
|
+
* Get IP address from request headers
|
|
410
|
+
* Handles various proxy headers (x-forwarded-for, x-real-ip, etc.)
|
|
411
|
+
*/
|
|
412
|
+
declare function getIPFromRequest(req: Request | any): string;
|
|
413
|
+
|
|
414
|
+
export { AnalyticsService, AttributionDetector, DeviceDetector, LocationDetector, NetworkDetector, checkAndSetLocationConsent, clearLocationConsent, useAnalytics as default, getIPFromRequest, getIPLocation, getLocationConsentTimestamp, getOrCreateUserId, getPublicIP, hasLocationConsent, loadJSON, loadSessionJSON, saveJSON, saveSessionJSON, setLocationConsentGranted, trackPageVisit, useAnalytics };
|
|
415
|
+
export type { AnalyticsConfig, AnalyticsEvent, AttributionInfo, DeviceInfo, DeviceType, IPLocation, LocationInfo, NetworkInfo, NetworkType, UseAnalyticsOptions, UseAnalyticsReturn };
|