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 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
- // Get location data from IP
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 free IP geolocation and accurate connection data
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 (for higher rate limits)
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
- * apiKey: '<your-api-key>',
634
- * baseUrl: 'https://ipwho.is'
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 with optional API key
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
- // Add API key as query parameter if provided
651
- if (apiKey) {
652
- url += `?key=${encodeURIComponent(apiKey)}`;
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 ipwho.is without IP parameter - it auto-detects user's IP and returns everything
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
- * apiKey: '<your-api-key>'
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 with IP and optional API key
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: { apiEndpoint: '/api/analytics' }
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);