Package Exports
- unique-visitor-tracker
- unique-visitor-tracker/middleware/express
Readme
unique-visitor-tracker
Lightweight, privacy-first unique visitor & event tracking helper (browser) + tiny Express receiver (server).
- No dependencies
- Anonymous IDs only (no cookies required, but supported)
- Works anywhere: vanilla JS, React, Vue, Svelte…
- Server optional: if you set an
endpoint, events are POSTed; otherwise you can intercept payloads in your app.
Install
npm i unique-visitor-tracker
# or
pnpm add unique-visitor-trackerQuick start (browser)
import VisitorTracker from 'unique-visitor-tracker';
const tracker = new VisitorTracker({
endpoint: '/api/track', // optional: POST destination
storage: 'auto', // 'auto' | 'localStorage' | 'cookie' | 'memory'
meta: { projectId: 'demo' } // merged into every event
});
console.log('visitor id', tracker.getId());
// page view
tracker.trackPage();
// custom event
tracker.trackEvent('button_click', { label: 'Buy now' });Single-call helper
import { trackVisit } from 'unique-visitor-tracker';
trackVisit('/api/track');Server (Express) — with analytics
import express from 'express';
import { createReceiver, createAnalytics } from 'unique-visitor-tracker/middleware/express';
const app = express();
app.use(express.json());
// naive in-memory store
const events = [];
const storage = { getAll: () => events };
const analytics = createAnalytics(storage);
// Track events
app.post('/api/track', createReceiver({
save: (evt) => events.push(evt),
// allow: (req) => req.headers['x-api-key'] === process.env.API_KEY
}));
// Analytics endpoints
app.get('/api/analytics/visitors/count', async (req, res) => {
const count = await analytics.getUniqueVisitorCount();
res.json({ uniqueVisitors: count });
});
app.get('/api/analytics/visitor/:id', async (req, res) => {
const info = await analytics.getVisitorInfo(req.params.id);
res.json(info);
});
app.listen(3000, () => console.log('listening on http://localhost:3000'));API
new VisitorTracker(options)
endpoint?: string– POST destination for events (optional).storage?: 'auto' | 'localStorage' | 'cookie' | 'memory'– where to persist the visitor id (default:auto).meta?: object– merged into every event.
Methods
getId(): string– returns the unique visitor id.trackPage(path?: string, data?: object): Promise<SendResult>– track a page view.trackEvent(name: string, data?: object): Promise<SendResult>– track a custom event.resetId(): string– clears and regenerates the visitor id.
Helpers
getVisitorId({ storage }?): stringtrackVisit(endpoint, path?, meta?, data?): Promise<SendResult>
Server
createReceiver({ save, allow? })– returns an Express-compatible handler that validates, annotates and stores events via yoursavefunction. IPs are hashed before saving.createAnalytics(storage)– returns analytics functions for counting unique visitors and getting visitor information.
Analytics
import { createAnalytics } from 'unique-visitor-tracker/middleware/express';
const analytics = createAnalytics(storage);
// Count unique visitors
const count = await analytics.getUniqueVisitorCount();
// Get detailed info about a specific visitor
const visitorInfo = await analytics.getVisitorInfo('uvt_abc123');
// Returns: { visitorId, firstSeen, lastSeen, totalEvents, client, events }Event payload shape
{
"type": "page_view",
"ts": "2025-09-07T00:00:00.000Z",
"visitorId": "uvt_d3AL4...",
"client": {
"env": "browser",
"tz": "Asia/Dhaka",
"lang": "en-US",
"ua": "Mozilla/5.0 ...",
"screen": { "w": 1920, "h": 1080, "dpr": 1 }
},
"projectId": "demo", // from meta
"data": { "path": "/" }
}Privacy
- No personal data collected by default.
- No IP stored; a non-reversible hash of the source IP is attached as
ipHashon the server. - Compliant with common privacy regimes when used properly. Always consult your legal team for your specific use-case.
Complete Feature Set
This package provides everything you need for visitor tracking and analytics:
✅ Unique Visitor Tracking
- Automatic ID generation with
uvt_prefix - Persistent storage across sessions (localStorage, cookies, or memory)
- Privacy-first approach with anonymous IDs only
✅ Event Tracking
- Page views with automatic path detection
- Custom events with flexible data payloads
- Client context (timezone, language, screen size, user agent)
✅ Analytics & Insights
- Count unique visitors across all time
- Get detailed visitor information including first/last seen, total events, and full event history
- Event aggregation and analysis capabilities
✅ Flexible Storage
- Multiple storage backends supported (see
examples/storage-adapters.js) - Database agnostic - works with MongoDB, PostgreSQL, Redis, SQLite, or simple files
- Custom storage adapters easy to implement
✅ Privacy & Security
- No personal data collected by default
- IP address hashing for privacy compliance
- Configurable data retention and opt-out flows
Examples
See the examples/ directory for complete usage examples:
complete-server-example.js- Full server with analytics dashboardclient-usage.js- Comprehensive client-side usagestorage-adapters.js- Database integration examplesreact-usage.jsx- React integration
Tips
- In SPAs, call
trackPage()inside your router listener. - For downloads,
trackEvent('download', { file: 'report.pdf' }). - For UTM analytics, merge
location.searchintodata. - Use the analytics functions to build dashboards and insights.
- Implement custom storage adapters for your preferred database.
License
MIT
---
## tests/smoke.js
```js
import VisitorTracker from '../src/index.js';
const tracker = new VisitorTracker({ endpoint: null, storage: 'memory' });
const id1 = tracker.getId();
const id2 = tracker.getId();
if (id1 !== id2) throw new Error('ID not stable across calls');
await tracker.trackPage('/');
await tracker.trackEvent('demo', { ok: true });
console.log('smoke OK', { id: id1 });examples/react-usage.jsx
import React, { useEffect } from 'react';
import VisitorTracker from 'unique-visitor-tracker';
const tracker = new VisitorTracker({ endpoint: '/api/track', meta: { app: 'example' } });
export default function App() {
useEffect(() => {
tracker.trackPage(window.location.pathname);
}, []);
return (
<button onClick={() => tracker.trackEvent('cta_click', { where: 'hero' })}>
Click me
</button>
);
}