user-analytics-tracker 4.2.0 → 4.4.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 +16 -0
- package/README.md +31 -4
- package/dist/index.cjs.js +43 -16
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.cts +40 -6
- package/dist/index.d.ts +40 -6
- package/dist/index.esm.js +43 -16
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
# [4.4.0](https://github.com/Switch-org/analytics-tracker/compare/v4.3.0...v4.4.0) (2026-01-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* update geo-location , essential data ([5511ff5](https://github.com/Switch-org/analytics-tracker/commit/5511ff545bc7850dea83e50c64270f8c112243e9))
|
|
7
|
+
* update geo-location , essential dataa ([a8f0c67](https://github.com/Switch-org/analytics-tracker/commit/a8f0c6765f6e91e19ab45cedf197d9df4820e3a7))
|
|
8
|
+
* updated key_api flow for customers ([5c58315](https://github.com/Switch-org/analytics-tracker/commit/5c58315f856ab924cc998ebfc84a88e93d5253d3))
|
|
9
|
+
|
|
10
|
+
# [4.3.0](https://github.com/Switch-org/analytics-tracker/compare/v4.2.0...v4.3.0) (2026-01-30)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* updated api_key flow for consumers ([#35](https://github.com/Switch-org/analytics-tracker/issues/35)) ([b5ce7de](https://github.com/Switch-org/analytics-tracker/commit/b5ce7de0201b69f085faf0c003427a961a4ec471))
|
|
16
|
+
|
|
1
17
|
# [4.2.0](https://github.com/Switch-org/analytics-tracker/compare/v4.1.2...v4.2.0) (2026-01-21)
|
|
2
18
|
|
|
3
19
|
|
package/README.md
CHANGED
|
@@ -95,6 +95,14 @@ const analytics = useAnalytics({
|
|
|
95
95
|
// Metrics configuration
|
|
96
96
|
enableMetrics: false, // Enable metrics collection (default: false)
|
|
97
97
|
|
|
98
|
+
// IP Geolocation - optional. Use apiKey (env var) for higher rate limits; for paid ipwhois.pro add baseUrl + ip when you have it
|
|
99
|
+
ipGeolocation: {
|
|
100
|
+
apiKey: import.meta.env.VITE_IPWHOIS_API_KEY,
|
|
101
|
+
baseUrl: 'https://ipwho.is', // or 'https://ipwhois.pro' for paid (URL: baseUrl/{IP}?key=API_KEY)
|
|
102
|
+
timeout: 5000,
|
|
103
|
+
ip: undefined, // set when you have the IP (e.g. server-side: getIPFromRequest(req))
|
|
104
|
+
},
|
|
105
|
+
|
|
98
106
|
// Field storage configuration (optional) - control which fields are stored
|
|
99
107
|
fieldStorage: {
|
|
100
108
|
ipLocation: { mode: 'essential' }, // IP location fields (includes connection data)
|
|
@@ -156,13 +164,20 @@ Use environment variables for different environments:
|
|
|
156
164
|
```tsx
|
|
157
165
|
// .env.local (development)
|
|
158
166
|
// NEXT_PUBLIC_ANALYTICS_API=https://api-dev.yourcompany.com/analytics
|
|
167
|
+
// NEXT_PUBLIC_IPWHOIS_API_KEY=your-ipwho-is-key // optional, for higher rate limits
|
|
159
168
|
|
|
160
169
|
// .env.production
|
|
161
170
|
// NEXT_PUBLIC_ANALYTICS_API=https://api.yourcompany.com/analytics
|
|
171
|
+
// NEXT_PUBLIC_IPWHOIS_API_KEY=your-ipwho-is-key
|
|
162
172
|
|
|
163
173
|
const analytics = useAnalytics({
|
|
164
174
|
config: {
|
|
165
175
|
apiEndpoint: process.env.NEXT_PUBLIC_ANALYTICS_API || '/api/analytics',
|
|
176
|
+
// Optional: your own ipwho.is API key (use env var; omit for free tier)
|
|
177
|
+
ipGeolocation: {
|
|
178
|
+
apiKey: process.env.NEXT_PUBLIC_IPWHOIS_API_KEY,
|
|
179
|
+
timeout: 5000,
|
|
180
|
+
},
|
|
166
181
|
},
|
|
167
182
|
});
|
|
168
183
|
```
|
|
@@ -341,6 +356,13 @@ interface AnalyticsConfig {
|
|
|
341
356
|
logLevel?: LogLevel; // 'silent' | 'error' | 'warn' | 'info' | 'debug' (default: 'warn')
|
|
342
357
|
// Metrics options
|
|
343
358
|
enableMetrics?: boolean; // Enable metrics collection (default: false)
|
|
359
|
+
// IP Geolocation (ipwho.is) - pass your own API key via env var for higher rate limits
|
|
360
|
+
ipGeolocation?: {
|
|
361
|
+
apiKey?: string; // Use env var. Required for paid; optional for ipwho.is free tier.
|
|
362
|
+
baseUrl?: string; // Default: 'https://ipwho.is'. Use 'https://ipwhois.pro' for paid (URL: baseUrl/{IP}?key=API_KEY)
|
|
363
|
+
timeout?: number; // Default: 5000
|
|
364
|
+
ip?: string; // When provided (paid/server-side), lookup this IP
|
|
365
|
+
};
|
|
344
366
|
// Existing options
|
|
345
367
|
autoSend?: boolean;
|
|
346
368
|
enableLocation?: boolean;
|
|
@@ -728,11 +750,16 @@ import { getIPLocation, getIPFromRequest } from 'user-analytics-tracker';
|
|
|
728
750
|
|
|
729
751
|
// In your API route (Next.js example)
|
|
730
752
|
export async function POST(req: Request) {
|
|
731
|
-
// Extract IP from request headers
|
|
732
753
|
const ip = getIPFromRequest(req);
|
|
733
|
-
|
|
734
|
-
//
|
|
754
|
+
|
|
755
|
+
// Free tier (ipwho.is)
|
|
735
756
|
const location = await getIPLocation(ip);
|
|
757
|
+
|
|
758
|
+
// Paid (ipwhois.pro): baseUrl/{IP}?key=API_KEY
|
|
759
|
+
// const location = await getIPLocation(ip, {
|
|
760
|
+
// baseUrl: 'https://ipwhois.pro',
|
|
761
|
+
// apiKey: process.env.IPWHOIS_PRO_API_KEY,
|
|
762
|
+
// });
|
|
736
763
|
// location contains: country, region, city, lat, lon, timezone, isp, etc.
|
|
737
764
|
}
|
|
738
765
|
```
|
|
@@ -981,7 +1008,7 @@ MIT © [Switch Org](https://github.com/switch-org)
|
|
|
981
1008
|
|
|
982
1009
|
## 🙏 Acknowledgments
|
|
983
1010
|
|
|
984
|
-
- Uses [ipwho.is](https://ipwho.is/) for
|
|
1011
|
+
- Uses [ipwho.is](https://ipwho.is/) for IP geolocation and connection data (free tier; consumers can pass their own API key via `config.ipGeolocation.apiKey` for higher rate limits)
|
|
985
1012
|
- Built with modern web APIs (User-Agent Client Hints, Geolocation API)
|
|
986
1013
|
|
|
987
1014
|
<!-- ## 📞 Support
|
package/dist/index.cjs.js
CHANGED
|
@@ -625,13 +625,17 @@ function checkAndSetLocationConsent(msisdn) {
|
|
|
625
625
|
*
|
|
626
626
|
* @example
|
|
627
627
|
* ```typescript
|
|
628
|
-
* // Without API key (free tier)
|
|
628
|
+
* // Without API key (free tier) - auto-detect requestor IP
|
|
629
629
|
* const location = await getCompleteIPLocation();
|
|
630
630
|
*
|
|
631
|
-
* // With API key (
|
|
631
|
+
* // With API key (higher rate limits)
|
|
632
|
+
* const location = await getCompleteIPLocation({ apiKey: '<key>', baseUrl: 'https://ipwho.is' });
|
|
633
|
+
*
|
|
634
|
+
* // Paid / server-side: provide IP + API key (e.g. ipwhois.pro)
|
|
632
635
|
* const location = await getCompleteIPLocation({
|
|
633
|
-
*
|
|
634
|
-
*
|
|
636
|
+
* baseUrl: 'https://ipwhois.pro',
|
|
637
|
+
* apiKey: '<key>',
|
|
638
|
+
* ip: '203.0.113.42',
|
|
635
639
|
* });
|
|
636
640
|
* ```
|
|
637
641
|
*/
|
|
@@ -644,17 +648,25 @@ async function getCompleteIPLocation(config) {
|
|
|
644
648
|
const baseUrl = config?.baseUrl || 'https://ipwho.is';
|
|
645
649
|
const timeout = config?.timeout || 5000;
|
|
646
650
|
const apiKey = config?.apiKey;
|
|
651
|
+
const configIp = config?.ip?.trim();
|
|
647
652
|
try {
|
|
648
|
-
// Build URL
|
|
653
|
+
// Build URL: baseUrl/{IP}?key=API_KEY when IP provided (paid/server-side); else baseUrl/ or baseUrl?key=...
|
|
649
654
|
let url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
url +=
|
|
655
|
+
if (configIp) {
|
|
656
|
+
// Paid / server-side: lookup specific IP. Format: https://ipwhois.pro/{IP}?key=YOUR_API_KEY
|
|
657
|
+
url += `/${encodeURIComponent(configIp)}`;
|
|
658
|
+
if (apiKey) {
|
|
659
|
+
url += `?key=${encodeURIComponent(apiKey)}`;
|
|
660
|
+
}
|
|
653
661
|
}
|
|
654
662
|
else {
|
|
663
|
+
// Auto-detect requestor IP (root path + optional key)
|
|
655
664
|
url += '/';
|
|
665
|
+
if (apiKey) {
|
|
666
|
+
url += `?key=${encodeURIComponent(apiKey)}`;
|
|
667
|
+
}
|
|
656
668
|
}
|
|
657
|
-
// Call
|
|
669
|
+
// Call API: with IP path it returns that IP's location; without path it returns requestor's IP
|
|
658
670
|
// This is the HIGH PRIORITY source - gets IP, location, connection, timezone, flag, etc. in one call
|
|
659
671
|
const response = await fetch(url, {
|
|
660
672
|
method: 'GET',
|
|
@@ -734,6 +746,10 @@ async function getCompleteIPLocation(config) {
|
|
|
734
746
|
* ```
|
|
735
747
|
*/
|
|
736
748
|
async function getPublicIP(config) {
|
|
749
|
+
// When consumer provides IP (paid/server-side), return it without fetching
|
|
750
|
+
if (config?.ip?.trim()) {
|
|
751
|
+
return config.ip.trim();
|
|
752
|
+
}
|
|
737
753
|
// Try to get complete location first (includes IP)
|
|
738
754
|
const completeLocation = await getCompleteIPLocation(config);
|
|
739
755
|
if (completeLocation?.ip) {
|
|
@@ -744,7 +760,7 @@ async function getPublicIP(config) {
|
|
|
744
760
|
const baseUrl = config?.baseUrl || 'https://ipwho.is';
|
|
745
761
|
const timeout = config?.timeout || 5000;
|
|
746
762
|
const apiKey = config?.apiKey;
|
|
747
|
-
// Build URL with optional API key
|
|
763
|
+
// Build URL with optional API key (auto-detect requestor IP)
|
|
748
764
|
let url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
749
765
|
if (apiKey) {
|
|
750
766
|
url += `?key=${encodeURIComponent(apiKey)}`;
|
|
@@ -791,8 +807,12 @@ async function getPublicIP(config) {
|
|
|
791
807
|
* const location = await getIPLocation('203.0.113.42');
|
|
792
808
|
*
|
|
793
809
|
* // With API key
|
|
810
|
+
* const location = await getIPLocation('203.0.113.42', { apiKey: '<key>' });
|
|
811
|
+
*
|
|
812
|
+
* // Paid ipwhois.pro: same URL format baseUrl/{IP}?key=API_KEY
|
|
794
813
|
* const location = await getIPLocation('203.0.113.42', {
|
|
795
|
-
*
|
|
814
|
+
* baseUrl: 'https://ipwhois.pro',
|
|
815
|
+
* apiKey: '<key>',
|
|
796
816
|
* });
|
|
797
817
|
* ```
|
|
798
818
|
*
|
|
@@ -816,14 +836,13 @@ async function getIPLocation(ip, config) {
|
|
|
816
836
|
const baseUrl = config?.baseUrl || 'https://ipwho.is';
|
|
817
837
|
const timeout = config?.timeout || 5000;
|
|
818
838
|
const apiKey = config?.apiKey;
|
|
819
|
-
// Build URL
|
|
839
|
+
// Build URL: baseUrl/{IP}?key=API_KEY (same format as ipwhois.pro paid: https://ipwhois.pro/{IP}?key=YOUR_API_KEY)
|
|
820
840
|
let url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
821
|
-
url += `/${ip}`;
|
|
822
|
-
// Add API key as query parameter if provided
|
|
841
|
+
url += `/${encodeURIComponent(ip)}`;
|
|
823
842
|
if (apiKey) {
|
|
824
843
|
url += `?key=${encodeURIComponent(apiKey)}`;
|
|
825
844
|
}
|
|
826
|
-
// Using ipwho.is API
|
|
845
|
+
// Using ipwho.is / ipwhois.pro API
|
|
827
846
|
const response = await fetch(url, {
|
|
828
847
|
method: 'GET',
|
|
829
848
|
headers: {
|
|
@@ -3443,11 +3462,17 @@ function initDebug() {
|
|
|
3443
3462
|
/**
|
|
3444
3463
|
* React hook for analytics tracking
|
|
3445
3464
|
*
|
|
3465
|
+
* To use your own ipwho.is API key (higher rate limits), pass ipGeolocation in config.
|
|
3466
|
+
* Use an env var so the key is not committed (e.g. VITE_IPWHOIS_API_KEY, REACT_APP_IPWHOIS_API_KEY).
|
|
3467
|
+
*
|
|
3446
3468
|
* @example
|
|
3447
3469
|
* ```tsx
|
|
3448
3470
|
* const { sessionId, networkInfo, deviceInfo, logEvent } = useAnalytics({
|
|
3449
3471
|
* autoSend: true,
|
|
3450
|
-
* config: {
|
|
3472
|
+
* config: {
|
|
3473
|
+
* apiEndpoint: '/api/analytics',
|
|
3474
|
+
* ipGeolocation: { apiKey: import.meta.env.VITE_IPWHOIS_API_KEY }, // optional; omit for free tier
|
|
3475
|
+
* },
|
|
3451
3476
|
* });
|
|
3452
3477
|
* ```
|
|
3453
3478
|
*/
|
|
@@ -3468,6 +3493,7 @@ function useAnalytics(options = {}) {
|
|
|
3468
3493
|
sessionTimeout: config.sessionTimeout,
|
|
3469
3494
|
fieldStorage: config.fieldStorage,
|
|
3470
3495
|
ipLocationFields: config.ipLocationFields, // Legacy support
|
|
3496
|
+
ipGeolocation: config.ipGeolocation, // ipwho.is API key (use env var, e.g. VITE_IPWHOIS_API_KEY)
|
|
3471
3497
|
});
|
|
3472
3498
|
}
|
|
3473
3499
|
}, [
|
|
@@ -3482,6 +3508,7 @@ function useAnalytics(options = {}) {
|
|
|
3482
3508
|
config?.sessionTimeout,
|
|
3483
3509
|
config?.fieldStorage,
|
|
3484
3510
|
config?.ipLocationFields,
|
|
3511
|
+
config?.ipGeolocation,
|
|
3485
3512
|
]);
|
|
3486
3513
|
const [networkInfo, setNetworkInfo] = react.useState(null);
|
|
3487
3514
|
const [deviceInfo, setDeviceInfo] = react.useState(null);
|