Hey there! Ever wondered how websites know when you’re actually looking at them, or if you’ve wandered off to make coffee? That’s presence detection in action – and it’s super useful for creating responsive, user-friendly web apps.
In this guide, I’ll walk you through everything you need to know about detecting user presence with JavaScript – from figuring out if someone’s still actively using your app to knowing if they’ve lost their internet connection. Let’s dive in!
What’s This Presence Detection Thing All About?
When we talk about presence detection in JavaScript, we’re really looking at four main things:
- Is the user still there? (Idle/inactivity detection)
- Are they connected to the internet? (Online/offline status)
- Which users are currently active? (Real-time user presence for multi-user apps)
- Is our app visible or hidden? (Tab/window focus detection)
Each of these gives us different insights into user behavior, and they’re all super useful for different reasons. Let’s break them down one by one.
1. Catching Idle Users: “Hello? Anyone There?”
What’s the deal?
This is about figuring out when someone hasn’t touched their keyboard, moved their mouse, or interacted with your app for a while. Maybe they got distracted by a cat video or went to grab lunch.
Why you’d want this:
- Auto-logout for security (so nobody messes with your banking session)
- Saving battery life by pausing heavy animations
- Showing others you’re “Away” in chat apps
- Nudging users with “Hey, are you still there?” notifications
The simple way with vanilla JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
let inactivityTime = function() { let time; // Reset the timer whenever the user does something window.onload = resetTimer; document.onmousemove = resetTimer; document.onkeypress = resetTimer; document.onclick = resetTimer; document.ontouchstart = resetTimer; document.onscroll = resetTimer; function resetTimer() { clearTimeout(time); time = setTimeout(logout, 30000); // 30 seconds until we consider them idle } function logout() { console.log("Looks like they're gone..."); // Do something - show a message, log them out, etc. } }; // Fire it up! inactivityTime(); |
Ready-made solutions that make life easier:
idle-timer.js (if you’re using jQuery)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$(document).idleTimer({ timeout: 30000, // 30 seconds idle: false }); $(document).on("idle.idleTimer", function(event, elem, obj) { console.log("User wandered off"); // Do your idle stuff here }); $(document).on("active.idleTimer", function(event, elem, obj) { console.log("They're back!"); // Welcome them back }); |
idle.js (for vanilla JS lovers)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const idle = new IdleJs({ idle: 30000, // 30 seconds onIdle: function() { console.log("Gone fishing..."); // Handle idle state }, onActive: function() { console.log("Back to work!"); // Handle active state }, events: ['mousemove', 'keydown', 'mousedown', 'touchstart', 'scroll'] }); idle.start(); |
Pro tips for idle detection:
- Don’t be too trigger-happy – Balance security with not annoying users
- Remember multiple tabs exist – They might be active elsewhere in your app
- Give fair warnings – Nobody likes being logged out without notice
- Be accessibility-friendly – Some folks need more time to interact
- Test on phones – Mobile interactions are a whole different ballgame
2. Online or Offline? “Is This Thing Connected?”
What’s the deal?
This is about figuring out if your user has an internet connection. Super important if you want your app to work smoothly when someone’s connection drops (like in an elevator or on the subway).
Why you’d want this:
- Building apps that work offline
- Saving data when someone goes offline, then syncing when they’re back
- Showing handy “You’re offline!” messages
- Disabling features that need internet when it’s not available
The easiest way (Navigator.onLine):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Check if we're online const updateConnectionStatus = () => { const status = navigator.onLine ? "online" : "offline"; console.log(`Looks like you're ${status}`); // Add a visual indicator document.body.classList.toggle('offline-mode', !navigator.onLine); }; // Listen for changes window.addEventListener('online', updateConnectionStatus); window.addEventListener('offline', updateConnectionStatus); // Check right away updateConnectionStatus(); |
A more reliable approach (actually checking if we can reach the internet):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
function checkRealConnectivity() { return fetch('https://www.example.com/ping', { method: 'HEAD', mode: 'no-cors', cache: 'no-store' }) .then(() => { console.log("Yep, we're online!"); document.body.classList.remove('offline-mode'); return true; }) .catch(() => { console.log("Nope, we're offline!"); document.body.classList.add('offline-mode'); return false; }); } // Check when the page loads checkRealConnectivity(); // Check every 30 seconds setInterval(checkRealConnectivity, 30000); |
The easy button (is-online library):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import isOnline from 'is-online'; async function checkConnection() { const online = await isOnline(); console.log(`We're ${online ? 'connected! 🎉' : 'offline 😢'}`); // Update the UI document.body.classList.toggle('offline-mode', !online); } // Check when the page loads checkConnection(); // Check periodically setInterval(checkConnection, 30000); |
Pro tips for online/offline detection:
- Don’t trust Navigator.onLine alone – It can lie (especially on some browsers)
- Belt AND suspenders – Use both methods for best results
- Be ready for reconnection – Have a plan for when users come back online
- Make it obvious – Clear indicators when someone’s offline prevent frustration
- Design assuming offline – The web is flaky, plan accordingly!
3. Who’s Here Right Now? Real-time User Presence
What’s the deal?
This is about knowing which users are currently active in multi-user applications. Think of the green dots next to names in chat apps or seeing who’s editing a Google Doc with you.
Why you’d want this:
- Chat apps showing who’s available
- Collaborative editing tools
- Multiplayer games
- Those “Someone is typing…” indicators
The popular option: Firebase
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
// Assuming Firebase is set up const uid = firebase.auth().currentUser.uid; const userStatusRef = firebase.database().ref('/status/' + uid); // Define our states const isOfflineForDatabase = { state: 'offline', last_changed: firebase.database.ServerValue.TIMESTAMP, }; const isOnlineForDatabase = { state: 'online', last_changed: firebase.database.ServerValue.TIMESTAMP, }; // The magic happens here firebase.database().ref('.info/connected').on('value', (snapshot) => { if (snapshot.val() === false) { return; } // This is the clever bit - it runs on the server even if they // close the browser or lose connection userStatusRef.onDisconnect().set(isOfflineForDatabase).then(() => { // Now we can safely mark them as online userStatusRef.set(isOnlineForDatabase); }); }); // Get a list of who's currently online firebase.database().ref('/status').on('value', (snapshot) => { const statuses = snapshot.val() || {}; const activeUsers = Object.keys(statuses).filter(key => statuses[key].state === 'online' ); console.log(`${activeUsers.length} people hanging out here`); // Update your UI with who's around }); |
The DIY approach: Socket.io
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
// Server-side code (Node.js) const io = require('socket.io')(server); const users = {}; io.on('connection', (socket) => { // Someone shows up socket.on('user-connect', (userId) => { users[userId] = { id: userId, socketId: socket.id, lastActive: new Date() }; io.emit('user-presence-update', users); }); // They did something socket.on('user-activity', (userId) => { if (users[userId]) { users[userId].lastActive = new Date(); } }); // They left socket.on('disconnect', () => { const userId = Object.keys(users).find(id => users[id].socketId === socket.id); if (userId) { delete users[userId]; io.emit('user-presence-update', users); } }); }); // Client-side code const socket = io(); const userId = 'user123'; // Usually from login // Let everyone know we're here socket.emit('user-connect', userId); // Ping periodically to show we're still active setInterval(() => { socket.emit('user-activity', userId); }, 30000); // Listen for updates about who's around socket.on('user-presence-update', (users) => { console.log(`There are ${Object.keys(users).length} people here`); // Update your UI }); |
Pro tips for real-time presence:
- Be forgiving about disconnections – Network hiccups shouldn’t mark people offline immediately
- Respect privacy – Let users go “invisible” if they want
- Add timeouts – Show “away” status before “offline”
- Think about scale – Presence updates can create lots of traffic
- Use clear indicators – Make status easy to understand at a glance
4. Are They Actually Looking At Us? Tab/Visibility Detection
What’s the deal?
This is about knowing if your web page is currently visible to the user or if it’s hidden in a background tab or minimized window. Great for conserving resources and improving performance.
Why you’d want this:
- Pausing videos when people switch tabs
- Saving battery by stopping animations
- Changing notification sounds/visuals
- Knowing actual viewing time for analytics
The modern way: Page Visibility API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// Handle visibility changes function handleVisibilityChange() { if (document.hidden) { console.log("Tab is hidden - taking a break!"); // Pause stuff document.querySelector('video')?.pause(); } else { console.log("Tab is visible - back to work!"); // Resume stuff document.querySelector('video')?.play(); } } // Listen for changes document.addEventListener('visibilitychange', handleVisibilityChange); // Check right away handleVisibilityChange(); |
The old-school approach: Focus/Blur
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
window.addEventListener('focus', () => { console.log("Window active - hello again!"); // Resume heavy stuff document.querySelector('video')?.play(); }); window.addEventListener('blur', () => { console.log("Window inactive - taking a breather"); // Pause heavy stuff document.querySelector('video')?.pause(); }); // Check right away console.log(`Window is ${document.hasFocus() ? 'focused' : 'not focused'} right now`); |
The helper library: visibilityjs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Is the page hidden? if (Visibility.hidden()) { console.log('Page is in the background'); } // Run when visibility changes Visibility.change((e, state) => { console.log(`Visibility changed to: ${state}`); }); // Run when page becomes visible Visibility.onVisible(() => { console.log('Welcome back!'); }); // Get current state console.log(`Current state: ${Visibility.state()}`); |
Pro tips for visibility detection:
- Page Visibility API > focus/blur – It’s more reliable
- Think about mobile – Mobile browsers handle visibility differently
- Test on different browsers – Implementation varies
- Hidden doesn’t mean inactive – They might be listening to your audio
- Combine with idle detection – For the full picture of user engagement
What’s the Best Option? A Quick Comparison
Here’s a no-nonsense ranking of the most popular solutions:
Solution | Popularity | Reliability | Difficulty | Best For |
---|---|---|---|---|
Extremely High | Moderate | Very Easy | Quick online/offline checks | |
Vanilla JS Idle Detection | Very High | High | Easy | Auto-logout and activity tracking |
High | Very High | Moderate | Chat apps and collaboration tools | |
High | High | Easy | Pausing videos and animations | |
Moderate | High | Moderate | Custom real-time presence systems |
How to Choose What’s Right for Your Project
When picking a solution, ask yourself:
- What exactly am I trying to detect? (Idle users? Connection status? Who’s online?)
- How many users will I have? (Some solutions don’t scale well)
- Do I need something simple or feature-rich? (Balance complexity with needs)
- Am I okay using third-party services? (Or need to keep everything in-house)
- Which browsers need to be supported? (Older browsers need different approaches)
Wrapping Up
Presence detection might seem like a small detail, but it can make a huge difference in how your app feels. Whether you’re building the next big social platform or just trying to make your web app more responsive, these techniques can help you create a better experience for your users.
Remember that you can (and often should) combine different approaches – for example, using both idle detection and visibility detection together will give you a much clearer picture of what your users are actually doing.
And always, always test on different devices and browsers! Nothing’s worse than deploying something that works great on your machine but falls apart on your users’ devices.
Want to dig deeper? Check out these resources: