User Presence Tracker (JS)
Real-time user online/offline/activity tracking with WebSocket + REST API. Tracks connections, heartbeats, and inactivity with Redis persistence. Pure JavaScript version.
Overview
A plug-and-play real-time user presence system for Express apps. Tracks online/offline status, activity timestamps, and heartbeats using WebSocket + Redis.
Call one endpoint from ANY frontend event ('POST /api/presence/activity') to register user activity. Auto-handles WebSocket connect/disconnect for instant status updates. Perfect for chat apps, dashboards, and social platforms.
Installation
What This Does
Installs a complete user presence tracking system with Redis persistence, WebSocket real-time updates, and REST API for manual activity pings.
Files & Folders Created
| File / Path | Description |
|---|---|
| /src/config/redis.js | Redis connection with TTL cleanup |
| /src/services/presenceService.js | Core presence logic |
| /src/routes/presence.js | REST API + WebSocket integration |
| /src/socket/presenceSocket.js | Real-time socket handlers |
| /server.js.example | 3-line integration demo |
| /.env.example | Redis + timeout configuration |
Files to be modified
| File / Path | Description |
|---|---|
| server.js | Add `app.use('/api/presence', presenceRoutes)` + `setSocketIO(io)` |
| .env | Add Redis connection (REDIS_HOST, REDIS_PORT) |
Configuration
# Redis Configuration (required) REDIS_HOST=127.0.0.1 REDIS_PORT=6379 # Timeout Settings INACTIVITY_TIMEOUT=300000 # 5 minutes in ms # Server PORT=3001
Frontend Integration
Connect via WebSocket for **auto online/offline** or ping REST API from **any frontend event** (clicks, scrolls, typing). Receive real-time updates when other users go online/offline.
Call from ANY frontend event (click, scroll, type, etc.)
Get single user online status + last activity
Get total online users count
Get list of all online user IDs
Example
1// app/components/PresenceTracker.jsx (React/Next.js)
2'use client';
3import { useState, useEffect } from 'react';
4import io from 'socket.io-client';
5
6export default function PresenceTracker({ userId }) {
7 const [status, setStatus] = useState('');
8 const [onlineCount, setOnlineCount] = useState(0);
9 let socket = null;
10
11 // WebSocket for real-time (optional)
12 useEffect(() => {
13 socket = io('/', { query: { userId } });
14
15 socket.on('status', (data) => setStatus('🟢 Online'));
16 socket.on('user_offline', (data) => console.log('User offline:', data.userId));
17 socket.on('user_activity', (data) => console.log('User active:', data.userId));
18
19 return () => socket?.disconnect();
20 }, [userId]);
21
22 // Activity ping on ANY event
23 const trackActivity = async () => {
24 try {
25 const res = await fetch('/api/presence/activity', {
26 method: 'POST',
27 headers: { 'Content-Type': 'application/json' },
28 body: JSON.stringify({ userId })
29 });
30 if (res.ok) setStatus('✅ Activity tracked');
31 } catch {
32 setStatus('⚠️ Activity tracking failed');
33 }
34 };
35
36 // Check online count
37 const checkOnlineCount = async () => {
38 const res = await fetch('/api/presence/online/count');
39 const data = await res.json();
40 setOnlineCount(data.data.count);
41 };
42
43 return (
44 <div className="p-6 border border-white/10 rounded-xl bg-gradient-to-r from-black/50 to-gray-900">
45 <div className="flex gap-4 mb-4">
46 <button
47 onClick={trackActivity}
48 className="bg-emerald-600 hover:bg-emerald-700 text-white px-6 py-2 rounded-lg font-medium"
49 >
50 Track Activity
51 </button>
52 <button
53 onClick={checkOnlineCount}
54 className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg font-medium"
55 >
56 Online Count
57 </button>
58 </div>
59
60 <div className="space-y-2 text-sm">
61 <p><strong>Status:</strong> {status}</p>
62 <p><strong>Online Users:</strong> {onlineCount}</p>
63 <p className="text-xs text-gray-400">
64 💡 Click ANYWHERE on page → auto-tracks activity via REST API<br/>
65 🔌 WebSocket auto-handles online/offline
66 </p>
67 </div>
68 </div>
69 );
70}Usage
1// From ANY frontend event (click, scroll, mouse move, etc.)
2fetch('/api/presence/activity', {
3 method: 'POST',
4 body: JSON.stringify({ userId: 'user_123' })
5});
6
7// Check user status
8fetch('/api/presence/status/user_123').then(r => r.json());
9
10// WebSocket (auto online/offline)
11const socket = io('/', { query: { userId: 'user_123' } });
12socket.on('user_offline', handleUserOffline);