@powerlimit/analytics
v1.1.0
Published
Simple, privacy-friendly analytics library with anonymous user tracking, location data, and IP capture
Maintainers
Readme
@ivanbondar/analytics
Simple, privacy-friendly analytics library with anonymous user tracking, location data (timezone & language), and server-side IP capture support.
Features
✅ Anonymous User Tracking - UUID-based identification stored in cookies
✅ Location Context - Automatic timezone and language collection (no permissions needed)
✅ Privacy-First - No annoying GPS permission prompts
✅ React Components - Built-in AnalyticsProvider for auto page tracking
✅ Server-Side Helpers - IP extraction and payload enrichment utilities
✅ Type-Safe - Full TypeScript support
✅ Framework Agnostic - Core works with any JavaScript framework
✅ Lightweight - Minimal dependencies (uuid + js-cookie)
Installation
npm install @ivanbondar/analytics uuid js-cookieyarn add @ivanbondar/analytics uuid js-cookiepnpm add @ivanbondar/analytics uuid js-cookieQuick Start
import { Analytics } from '@ivanbondar/analytics';
// Create analytics instance
const analytics = new Analytics({
apiUrl: '/api/analytics', // Your analytics endpoint
cookieName: 'anonymous_user_id', // Optional, default: 'anonymous_user_id'
cookieExpireDays: 365, // Optional, default: 365
});
// Track events
analytics.track('button_click', { button: 'subscribe' });
// Track page views
analytics.trackPageView('/about');
// Track clicks
analytics.trackClick('cta-button', { section: 'hero' });
// Track actions
analytics.trackAction('form_submit', 'contact', { success: true });
// Get anonymous user ID
const userId = analytics.getAnonymousId();
// Reset anonymous ID (logout, privacy)
analytics.resetAnonymousId();What Gets Tracked
Every event automatically includes:
{
"eventName": "page_view",
"userUuid": "550e8400-e29b-41d4-a716-446655440000",
"host": "example.com",
"url": "/about",
"properties": "{\"page\":\"/about\"}",
"location": "{\"timezone\":\"America/New_York\",\"language\":\"en-US\"}"
}Automatic Data Collection
| Data | Description | Permission Required |
|------|-------------|---------------------|
| userUuid | Anonymous user identifier (UUID v4) | Cookie consent |
| eventName | Name of the event | None |
| host | Website hostname | None |
| url | Current page URL | None |
| properties | Custom event properties (JSON) | None |
| location.timezone | User's timezone (e.g., "America/New_York") | None |
| location.language | Browser language (e.g., "en-US") | None |
API Reference
new Analytics(config)
Creates a new analytics instance.
Config:
{
apiUrl: string; // Required: Your analytics API endpoint
cookieName?: string; // Optional: Cookie name (default: 'anonymous_user_id')
cookieExpireDays?: number; // Optional: Cookie expiration (default: 365 days)
}track(eventName, properties?)
Tracks a custom event.
analytics.track('video_play', {
videoId: '123',
title: 'Demo Video',
duration: 120
});trackPageView(page, properties?)
Tracks a page view.
analytics.trackPageView('/about', {
referrer: document.referrer,
section: 'company'
});trackClick(element, properties?)
Tracks a click event.
analytics.trackClick('signup-button', {
location: 'hero',
variant: 'primary'
});trackAction(action, category?, properties?)
Tracks a user action with optional category.
analytics.trackAction('form_submit', 'contact', {
formId: 'contact-form',
success: true,
fields: 3
});getAnonymousId()
Returns the current anonymous user ID.
const userId = analytics.getAnonymousId();
// "550e8400-e29b-41d4-a716-446655440000"resetAnonymousId()
Resets the anonymous user ID (creates a new one).
// Useful for logout or privacy purposes
analytics.resetAnonymousId();Framework Examples
React / Next.js (App Router)
1. Create analytics instance:
// lib/analytics.ts
import { Analytics } from '@ivanbondar/analytics';
export const analytics = new Analytics({
apiUrl: process.env.NEXT_PUBLIC_ANALYTICS_API_URL || '/api/analytics',
cookieName: 'anonymous_user_id',
cookieExpireDays: 365,
});2. Add AnalyticsProvider for auto page tracking:
// components/AnalyticsProvider.tsx
'use client';
import { usePathname } from 'next/navigation';
import { AnalyticsProvider as BaseAnalyticsProvider } from '@ivanbondar/analytics/react';
import { analytics } from '@/lib/analytics';
export function AnalyticsProvider() {
const pathname = usePathname();
return <BaseAnalyticsProvider analytics={analytics} pathname={pathname} />;
}3. Add to root layout:
// app/layout.tsx
import { AnalyticsProvider } from '@/components/AnalyticsProvider';
export default function RootLayout({ children }) {
return (
<html>
<body>
<AnalyticsProvider />
{children}
</body>
</html>
);
}4. Create API route for IP tracking:
// app/api/analytics/route.ts
import { createAnalyticsHandler } from '@ivanbondar/analytics/server';
export const POST = createAnalyticsHandler({
apiUrl: process.env.ANALYTICS_API_URL!,
anonymizeIp: false, // Set to true for GDPR compliance
includeUserAgent: true,
});5. Use in components:
import { analytics } from '@/lib/analytics';
function MyComponent() {
const handleClick = () => {
analytics.trackClick('button', { label: 'Get Started' });
};
return <button onClick={handleClick}>Get Started</button>;
}Vue.js
// plugins/analytics.ts
import { Analytics } from '@ivanbondar/analytics';
export const analytics = new Analytics({
apiUrl: import.meta.env.VITE_ANALYTICS_API_URL,
});
// main.ts
import { analytics } from './plugins/analytics';
app.config.globalProperties.$analytics = analytics;
// Usage in components
<script setup>
import { analytics } from '@/plugins/analytics';
const handleClick = () => {
analytics.trackClick('button', { label: 'Submit' });
};
</script>Vanilla JavaScript
<script type="module">
import { Analytics } from '@ivanbondar/analytics';
const analytics = new Analytics({
apiUrl: '/api/analytics'
});
// Track page view
analytics.trackPageView(window.location.pathname);
// Track button clicks
document.querySelectorAll('[data-track]').forEach(button => {
button.addEventListener('click', () => {
analytics.trackClick(button.dataset.track);
});
});
</script>React Components (@ivanbondar/analytics/react)
AnalyticsProvider
Automatic page view tracking for React/Next.js:
import { AnalyticsProvider } from '@ivanbondar/analytics/react';
import { usePathname } from 'next/navigation'; // Next.js App Router
import { analytics } from './analytics-instance';
function MyAnalyticsProvider() {
const pathname = usePathname();
return (
<AnalyticsProvider
analytics={analytics}
pathname={pathname}
properties={{ customProp: 'value' }} // Optional
/>
);
}useAnalyticsPageView Hook
Manual page view tracking:
import { useAnalyticsPageView } from '@ivanbondar/analytics/react';
import { analytics } from './analytics-instance';
function MyComponent() {
useAnalyticsPageView(analytics, '/custom-page', {
section: 'dashboard',
user: 'premium'
});
return <div>Content</div>;
}Server-Side Utilities (@ivanbondar/analytics/server)
createAnalyticsHandler
Create a complete API route handler with IP tracking:
// app/api/analytics/route.ts (Next.js App Router)
import { createAnalyticsHandler } from '@ivanbondar/analytics/server';
export const POST = createAnalyticsHandler({
apiUrl: process.env.ANALYTICS_API_URL!,
anonymizeIp: false, // Set to true for GDPR compliance
includeUserAgent: true, // Include user agent in payload
onError: (error) => { // Optional error handler
console.error('Analytics error:', error);
},
});getClientIp
Extract client IP from request headers (handles CDNs, proxies):
import { getClientIp } from '@ivanbondar/analytics/server';
import { NextRequest } from 'next/server';
export async function POST(request: NextRequest) {
const ip = getClientIp(request.headers);
console.log('Client IP:', ip);
}enrichAnalyticsPayload
Enrich payload with server-side data:
import { enrichAnalyticsPayload } from '@ivanbondar/analytics/server';
import { NextRequest } from 'next/server';
export async function POST(request: NextRequest) {
const body = await request.json();
const enriched = enrichAnalyticsPayload(body, request.headers, {
anonymizeIp: true,
includeUserAgent: true,
});
// enriched now includes: ipAddress, userAgent, serverTimestamp
}anonymizeIp
Anonymize IP addresses for GDPR compliance:
import { anonymizeIp } from '@ivanbondar/analytics/server';
anonymizeIp('192.168.1.123') // Returns: '192.168.1.0'
anonymizeIp('2001:db8::1') // Returns: '2001:db8::0'isBot
Filter out bot traffic:
import { isBot } from '@ivanbondar/analytics/server';
const userAgent = request.headers.get('user-agent');
if (isBot(userAgent)) {
return Response.json({ success: true, ignored: true });
}Environment Variables:
# .env.local
NEXT_PUBLIC_ANALYTICS_API_URL=/api/analytics
ANALYTICS_API_URL=https://your-analytics-api.com/trackPrivacy & GDPR
Data Collected
- Anonymous UUID: Stored in cookie, no personal information
- Timezone: Browser timezone (e.g., "America/New_York")
- Language: Browser language preference (e.g., "en-US")
- IP Address: Only if using server-side proxy (server-side only)
- User Agent: Only if using server-side proxy (server-side only)
GDPR Compliance
Disclose in Privacy Policy
- Anonymous user tracking (UUID)
- Timezone and language collection
- IP address collection (if applicable)
- Cookie usage and expiration
Cookie Consent
- Include analytics cookies in consent banner
- Allow users to opt-out
User Rights
- Provide data export by UUID
- Allow deletion requests
- Provide
resetAnonymousId()for user control
IP Anonymization (Optional)
// In your server-side proxy function anonymizeIp(ip: string): string { const parts = ip.split('.'); parts[3] = '0'; return parts.join('.'); }
TypeScript Support
Full TypeScript support with exported types:
import {
Analytics,
AnalyticsConfig,
LocationData,
TrackEventPayload
} from '@ivanbondar/analytics';
const config: AnalyticsConfig = {
apiUrl: '/api/analytics',
cookieName: 'user_id',
cookieExpireDays: 90,
};
const analytics = new Analytics(config);Browser Support
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Opera 76+
Requires:
Intl.DateTimeFormatAPI (timezone detection)navigator.language(language detection)fetchAPI- ES2020+ features
Dependencies
uuid- UUID v4 generationjs-cookie- Cookie management
License
MIT
Author
Ivan Bondar
Contributing
Contributions welcome! Please open an issue or PR.
Support
For issues and questions, please open an issue on GitHub.
