@remcostoeten/analytics
v0.0.1
Published
Privacy-focused analytics SDK for tracking page views and custom events
Downloads
110
Maintainers
Readme
@remcostoeten/analytics
Privacy-focused analytics SDK for tracking page views and custom events in React and Next.js applications.
Features
- 🔒 Privacy-First: No cookies, no raw IP storage, GDPR-friendly
- 🚀 Lightweight: Only 1.6 KB gzipped
- ⚡ Fast: Uses
sendBeaconAPI with fetch fallback - 🎯 Type-Safe: Written in TypeScript with full type definitions
- 🔄 SSR Compatible: Works with Next.js App Router and Pages Router
- 🛡️ Built-in Protection: Opt-out support, DNT respect, client-side deduplication
- 📊 Simple API: Drop-in component + helper functions
Installation
npm install @remcostoeten/analytics
# or
yarn add @remcostoeten/analytics
# or
pnpm add @remcostoeten/analytics
# or
bun add @remcostoeten/analyticsQuick Start
Next.js App Router
// app/layout.tsx
import { Analytics } from '@remcostoeten/analytics';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Analytics />
</body>
</html>
);
}Next.js Pages Router
// pages/_app.tsx
import { Analytics } from '@remcostoeten/analytics';
export default function App({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<Analytics />
</>
);
}React SPA
// App.tsx
import { Analytics } from '@remcostoeten/analytics';
function App() {
return (
<>
<Analytics />
{/* Your app content */}
</>
);
}Configuration
Environment Variables
# .env.local
NEXT_PUBLIC_REMCO_ANALYTICS_URL=https://your-ingestion-url.comComponent Props
<Analytics
projectId="my-project" // Optional: defaults to hostname
ingestUrl="https://example.com" // Optional: override ingestion URL
disabled={false} // Optional: disable tracking
debug={false} // Optional: enable debug logging
/>API Reference
<Analytics />
React component that automatically tracks page views.
Props:
projectId?: string- Project identifier (defaults towindow.location.hostname)ingestUrl?: string- Ingestion endpoint URL (defaults to env var orhttp://localhost:3001)disabled?: boolean- Disable all tracking (default:false)debug?: boolean- Enable debug console logging (default:false)
track(type, meta?, options?)
Core tracking function for custom events.
import { track } from '@remcostoeten/analytics';
track('event', { action: 'button_click', label: 'signup' });Parameters:
type: 'pageview' | 'event' | 'click' | 'error'- Event typemeta?: Record<string, unknown>- Custom metadataoptions?: TrackOptions- Configuration options
trackPageView(meta?, options?)
Track a page view event.
import { trackPageView } from '@remcostoeten/analytics';
trackPageView({ source: 'navigation' });trackEvent(eventName, meta?, options?)
Track a custom event with a name.
import { trackEvent } from '@remcostoeten/analytics';
trackEvent('signup', { plan: 'pro', trial: true });trackClick(elementName, meta?, options?)
Track a click event.
import { trackClick } from '@remcostoeten/analytics';
trackClick('cta_button', { position: 'hero' });trackError(error, meta?, options?)
Track an error event.
import { trackError } from '@remcostoeten/analytics';
try {
// Some code
} catch (error) {
trackError(error as Error, { context: 'checkout' });
}Identity Management
import {
getVisitorId,
resetVisitorId,
getSessionId,
resetSessionId,
} from '@remcostoeten/analytics';
const visitorId = getVisitorId(); // Get current visitor ID
resetVisitorId(); // Generate new visitor ID
const sessionId = getSessionId(); // Get current session ID (30min timeout)
resetSessionId(); // Generate new session IDPrivacy Controls
import { optOut, optIn, isOptedOut } from '@remcostoeten/analytics';
optOut(); // Disable tracking for this user
optIn(); // Re-enable tracking
isOptedOut(); // Check opt-out status (returns boolean)Examples
Track Custom Events
'use client';
import { trackEvent } from '@remcostoeten/analytics';
export function SignupButton() {
function handleSignup() {
trackEvent('signup_initiated', {
plan: 'premium',
source: 'pricing_page',
});
}
return <button onClick={handleSignup}>Sign Up</button>;
}Track Errors
'use client';
import { useEffect } from 'react';
import { trackError } from '@remcostoeten/analytics';
export function ErrorBoundary({ children }) {
useEffect(() => {
function handleError(event: ErrorEvent) {
trackError(event.error, {
message: event.message,
filename: event.filename,
lineno: event.lineno,
});
}
window.addEventListener('error', handleError);
return () => window.removeEventListener('error', handleError);
}, []);
return <>{children}</>;
}Privacy Controls UI
'use client';
import { useState, useEffect } from 'react';
import { optOut, optIn, isOptedOut } from '@remcostoeten/analytics';
export function PrivacySettings() {
const [opted, setOpted] = useState(false);
useEffect(() => {
setOpted(isOptedOut());
}, []);
function handleToggle() {
if (opted) {
optIn();
setOpted(false);
} else {
optOut();
setOpted(true);
}
}
return (
<label>
<input type="checkbox" checked={opted} onChange={handleToggle} />
Opt out of analytics
</label>
);
}Conditional Tracking
<Analytics
projectId="my-app"
disabled={process.env.NODE_ENV === 'development'}
debug={process.env.NODE_ENV === 'development'}
/>How It Works
Visitor Identification
- Visitor ID: Generated on first visit, stored in
localStorage - Session ID: Generated per session, stored in
sessionStoragewith 30-minute timeout - Fallback: If storage is blocked, ephemeral IDs are generated
Data Sent
Each tracking call sends:
{
type: 'pageview' | 'event' | 'click' | 'error',
projectId: string,
path: string,
referrer: string | null,
origin: string,
host: string,
ua: string, // User agent
lang: string, // Browser language
visitorId: string, // Persistent visitor ID
sessionId: string, // Session ID
meta?: object // Custom metadata
}Privacy Features
- ✅ No HTTP cookies - Uses localStorage/sessionStorage only
- ✅ No raw IPs - IPs are hashed server-side with daily salt rotation
- ✅ Opt-out support - Users can disable tracking permanently
- ✅ DNT respect - Honors Do Not Track browser setting
- ✅ Client deduplication - Prevents duplicate events within 5 seconds
- ✅ SSR safe - Automatically skips tracking on server
Browser Support
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Opera 76+
Uses navigator.sendBeacon with automatic fallback to fetch with keepalive.
TypeScript Support
Full TypeScript support included. Types are automatically exported:
import type { TrackOptions, EventPayload } from '@remcostoeten/analytics';Performance
- Bundle size: 1.6 KB gzipped (ESM)
- Runtime overhead: < 1ms per event
- Network: Uses
sendBeaconfor non-blocking requests - Tree-shakeable: Only import what you need
License
MIT License - see LICENSE for details.
Repository
https://github.com/remcostoeten/analytics
Support
For issues, questions, or contributions, please visit the GitHub repository.
