Chrome Extension Idle Detection API Guide: Detect User Activity and Inactive Tabs
Building intelligent Chrome extensions often requires understanding when users are actively engaged with their browser versus when they have stepped away. The Chrome Idle Detection API provides a powerful mechanism to detect user inactivity, enabling developers to create smarter extensions that conserve system resources, optimize performance, and deliver contextual experiences based on user availability. This comprehensive guide will walk you through everything you need to know about implementing idle detection in your Chrome extensions using the chrome.idle API.
Whether you are building a tab management extension that suspends inactive tabs to save memory, a productivity tool that tracks focus time, or a notification system that respects user availability, understanding the Idle Detection API is essential. In this guide, we will cover the fundamentals of the API, implementation patterns, best practices, and real-world use cases that you can adapt for your own projects.
Understanding the Chrome Idle Detection API
The Chrome Idle Detection API, accessible through the chrome.idle namespace, allows extensions to monitor user idle state on a system-wide basis. The API detects when a user has not interacted with their device for a specified period, making it invaluable for building resource-conscious extensions that respond to user presence and absence.
How Idle Detection Works
The chrome.idle API operates by monitoring system-level user input events such as keyboard presses, mouse movements, and touch interactions. When the user stops interacting with the system for a configured threshold, Chrome reports the user’s state as “idle.” Conversely, when user activity is detected after an idle period, Chrome transitions the state back to “active.”
It is important to understand that idle detection is system-wide rather than tab-specific. This means the API monitors the user’s overall interaction with the computer, not just within a particular tab or window. This design choice makes the API particularly useful for extensions that need to make decisions based on whether the user is present at the computer at all.
The API provides three distinct states that your extension can monitor:
- Active: The user is currently interacting with the system. This is the default state when the user has recently pressed keys, moved the mouse, or touched the screen.
- Idle: The user has not interacted with the system for a specified period. This state indicates the user may have stepped away from their computer.
- Locked: The user has locked their screen or the system is in a locked state. This is a more definitive indicator of user absence than the idle state.
API Prerequisites and Permissions
To use the chrome.idle API in your extension, you must declare the “idle” permission in your manifest.json file. This permission allows your extension to query and monitor the user’s idle state. Without this permission, calls to the idle API will fail.
Here is how you add the permission to your manifest:
{
"manifest_version": 3,
"name": "My Idle Detection Extension",
"version": "1.0.0",
"description": "An extension that demonstrates idle detection",
"permissions": [
"idle"
],
"background": {
"service_worker": "background.js"
}
}
The idle permission is considered a “regular” permission rather than a host permission, which means it does not require special justification during Chrome Web Store review. However, you should still clearly describe in your extension’s description how you use idle detection to benefit users.
Core Methods of the Chrome Idle API
The chrome.idle API provides several methods that form the foundation of idle detection implementation. Understanding these methods is crucial for building robust idle-aware extensions.
Setting the Detection Interval
The setDetectionInterval method allows you to configure how frequently Chrome checks for idle state. The interval is specified in seconds, with a default of 60 seconds. The minimum allowed interval is 15 seconds.
// background.js
chrome.idle.setDetectionInterval(30);
In this example, we set the detection interval to 30 seconds. This means Chrome will check every 30 seconds whether the user has been idle. While a shorter interval provides more responsive detection, it also consumes slightly more resources. For most use cases, an interval between 30 and 60 seconds strikes a good balance.
Querying Idle State
The queryState method allows your extension to immediately retrieve the current idle state. This is useful for making one-time checks or for responding to events that require knowing the user’s current state.
// Check current idle state
chrome.idle.queryState(30, (state) => {
if (state === 'idle') {
console.log('User is currently idle');
// Perform idle-related actions
} else if (state === 'active') {
console.log('User is currently active');
// Perform active-related actions
} else if (state === 'locked') {
console.log('Screen is locked');
// Handle locked state
}
});
The callback receives a string representing the current state. It is important to note that the queryState method is asynchronous and requires a callback function to handle the result.
Listening for State Changes
The onStateChanged event is where the real power of the Idle Detection API becomes apparent. This event fires whenever Chrome detects a change in the user’s idle state, allowing your extension to respond in real-time to user presence changes.
// background.js
chrome.idle.onStateChanged.addListener((state) => {
console.log('Idle state changed to:', state);
if (state === 'idle') {
handleUserBecameIdle();
} else if (state === 'active') {
handleUserBecameActive();
} else if (state === 'locked') {
handleScreenLocked();
}
});
function handleUserBecameIdle() {
console.log('User has become idle - starting idle tasks');
// Implement your idle logic here
// Examples: suspend tabs, pause animations, save state
}
function handleUserBecameActive() {
console.log('User has returned - resuming normal operations');
// Implement your active logic here
// Examples: restore tabs, resume updates, refresh content
}
function handleScreenLocked() {
console.log('Screen is locked - user is definitely away');
// Implement locked state handling
}
This event-driven approach is ideal for extensions that need to perform actions when users come and go. For example, a tab management extension might suspend background tabs when the user becomes idle and restore them when the user returns.
Practical Implementation Patterns
Now that we understand the API methods, let us explore practical implementation patterns for common use cases. These patterns will help you build robust and efficient idle-aware extensions.
Pattern 1: Basic Idle Detection
For simple extensions that just need to know when the user is away, a basic implementation works well:
// background.js - Basic idle detection
const IDLE_THRESHOLD = 60; // seconds
chrome.idle.setDetectionInterval(IDLE_THRESHOLD);
chrome.idle.onStateChanged.addListener((state) => {
if (state === 'idle') {
console.log('User has been idle for', IDLE_THRESHOLD, 'seconds');
// Add your idle handling logic
} else if (state === 'active') {
console.log('User is active again');
// Add your active handling logic
}
});
This pattern is straightforward and suitable for extensions that do not need complex state management or persistent idle tracking.
Pattern 2: Persistent Idle Monitoring with Storage
For extensions that need to track how long users have been idle or maintain state across service worker restarts, combining idle detection with Chrome storage provides a more robust solution:
// background.js - Persistent idle monitoring
const IDLE_THRESHOLD = 60;
let isMonitoring = true;
chrome.idle.setDetectionInterval(IDLE_THRESHOLD);
// Initialize state from storage when extension starts
chrome.storage.local.get(['lastActiveTime', 'totalIdleTime'], (result) => {
if (chrome.runtime.lastError) {
console.error('Error loading state:', chrome.runtime.lastError);
return;
}
console.log('Loaded state:', result);
});
chrome.idle.onStateChanged.addListener((state) => {
if (!isMonitoring) return;
if (state === 'idle') {
const idleStartTime = Date.now();
chrome.storage.local.set({ idleStartTime: idleStartTime });
console.log('Started tracking idle time at:', new Date(idleStartTime));
// Perform tasks when user becomes idle
onUserIdle();
} else if (state === 'active' || state === 'locked') {
chrome.storage.local.get(['idleStartTime'], (result) => {
if (result.idleStartTime) {
const idleDuration = Date.now() - result.idleStartTime;
console.log('User was idle for:', idleDuration, 'ms');
// Update total idle time
chrome.storage.local.get(['totalIdleTime'], (res) => {
const totalIdle = (res.totalIdleTime || 0) + idleDuration;
chrome.storage.local.set({
totalIdleTime: totalIdle,
idleStartTime: null
});
});
}
});
// Perform tasks when user becomes active
onUserActive();
}
});
function onUserIdle() {
// Handle user becoming idle
// Example: close unnecessary connections, save state
}
function onUserActive() {
// Handle user becoming active
// Example: restore state, refresh data
}
This pattern is particularly useful for productivity tracking extensions that need to accumulate statistics over time.
Pattern 3: Tab-Specific Idle Detection
While the chrome.idle API is system-wide, you can combine it with tab tracking to implement tab-specific idle behavior. This is the pattern used by popular tab management extensions like Tab Suspender Pro:
// background.js - Tab-specific idle detection
const TAB_IDLE_THRESHOLD = 300; // 5 minutes
const tabLastActive = {};
chrome.tabs.onActivated.addListener((activeInfo) => {
tabLastActive[activeInfo.tabId] = Date.now();
});
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete' && tab.active) {
tabLastActive[tabId] = Date.now();
}
});
// Check for idle tabs periodically
setInterval(() => {
const currentTime = Date.now();
chrome.tabs.query({}, (tabs) => {
tabs.forEach((tab) => {
if (!tabLastActive[tab.id]) {
tabLastActive[tab.id] = currentTime;
return;
}
const idleTime = currentTime - tabLastActive[tab.id];
if (idleTime > TAB_IDLE_THRESHOLD * 1000) {
// Tab has been inactive for too long
handleInactiveTab(tab);
}
});
});
}, 60000); // Check every minute
chrome.idle.onStateChanged.addListener((state) => {
if (state === 'idle') {
// Aggressive tab suspension when user is idle
suspendAllInactiveTabs();
} else if (state === 'active') {
// Restore suspended tabs when user returns
restoreSuspendedTabs();
}
});
function handleInactiveTab(tab) {
console.log('Tab', tab.id, 'has been inactive');
// Implement tab suspension logic
}
function suspendAllInactiveTabs() {
console.log('User is idle - suspending inactive tabs');
// Implement suspension logic
}
function restoreSuspendedTabs() {
console.log('User is active - restoring tabs');
// Implement restoration logic
}
This hybrid approach leverages both system-wide idle detection and per-tab activity tracking to create sophisticated tab management behavior.
Best Practices and Common Pitfalls
When implementing idle detection in your Chrome extensions, following best practices will help you avoid common issues and create more reliable extensions.
Performance Considerations
Service workers in Manifest V3 have a limited lifetime and can be terminated when idle. This creates a challenge for idle detection because you need the service worker to remain active to receive state change events. However, Chrome provides a mechanism to keep your service worker alive when needed.
The idle detection API is designed to automatically wake your service worker when a state change occurs, even if it has been terminated. This means you do not need to implement complex keep-alive mechanisms.
However, you should be mindful of the following:
- Detection interval: Setting an extremely short detection interval increases CPU usage. Stick to intervals of 30 seconds or longer unless your use case specifically requires faster detection.
- Event handler efficiency: Keep your state change handlers lightweight. Perform heavy operations asynchronously or use alarms to defer work.
- Memory management: Clean up any timers or intervals when your service worker terminates to prevent memory leaks.
Handling Edge Cases
Several edge cases require special consideration when implementing idle detection:
Screen lock versus idle: On some operating systems, the locked state is reported as a separate event rather than a transition through idle. Your implementation should handle both the “idle” and “locked” states appropriately.
chrome.idle.onStateChanged.addListener((state) => {
if (state === 'idle' || state === 'locked') {
// User is away - treat both states similarly
handleUserAway();
}
});
Multiple displays: On multi-monitor setups, user activity on one display may not always trigger state changes appropriately. Test your extension with multiple monitors to ensure it behaves as expected.
Kiosk mode: In ChromeOS kiosk mode, idle detection behavior may differ. Test your extension in kiosk mode if it is intended for kiosk deployments.
Error Handling
Always implement proper error handling for API calls:
chrome.idle.queryState(30, (state) => {
if (chrome.runtime.lastError) {
console.error('Error querying idle state:', chrome.runtime.lastError.message);
return;
}
console.log('Current state:', state);
});
This pattern ensures your extension continues functioning even if there are temporary issues with the idle detection API.
Real-World Use Cases
The Chrome Idle Detection API enables a wide range of practical extensions. Here are some common use cases that demonstrate the API’s versatility.
Use Case 1: Memory Optimization
Extensions like Tab Suspender Pro use idle detection to identify when users have stepped away, then suspend tabs that have not been used for a while. Suspended tabs consume minimal memory because their content is unloaded from memory. When the user returns or activates a suspended tab, the content is automatically restored.
This approach can reduce Chrome’s memory usage by 50-80% for users who keep many tabs open. The pattern works as follows:
- Track the last active time for each tab
- When the user becomes idle, identify tabs that have not been used recently
- Suspend those tabs using the chrome.tabs.discard API or by replacing their content with a lightweight placeholder
- When the user becomes active again or clicks on a suspended tab, restore the original content
Use Case 2: Focus and Productivity Tracking
Idle detection is valuable for productivity extensions that track focus time or Pomodoro-style workflows. By detecting when users are away, these extensions can pause timers and exclude idle time from productive work statistics.
// Productivity timer with idle detection
let focusTimer = null;
let totalFocusTime = 0;
let isPaused = false;
chrome.idle.onStateChanged.addListener((state) => {
if (state === 'idle' && !isPaused) {
// Pause the timer when user becomes idle
pauseTimer();
console.log('Timer paused due to user idle');
} else if (state === 'active' && isPaused) {
// Resume when user returns
resumeTimer();
console.log('Timer resumed');
}
});
Use Case 3: Smart Notifications
Extensions that send notifications can use idle detection to avoid interrupting users when they are away. Instead of sending notifications immediately, the extension can queue them and deliver them when the user returns.
// Smart notification delivery
const pendingNotifications = [];
chrome.idle.onStateChanged.addListener((state) => {
if (state === 'active' && pendingNotifications.length > 0) {
// Deliver pending notifications when user returns
pendingNotifications.forEach(notification => {
chrome.notifications.create(notification);
});
pendingNotifications.length = 0;
}
});
function queueNotification(notification) {
chrome.idle.queryState(30, (state) => {
if (state === 'active') {
chrome.notifications.create(notification);
} else {
pendingNotifications.push(notification);
}
});
}
Use Case 4: Automatic Logout for Security
Security-focused extensions can use idle detection to automatically log users out of sensitive applications after a period of inactivity. This provides an additional layer of security for banking, email, or other sensitive web applications.
// Auto-logout on idle
const AUTO_LOGOUT_THRESHOLD = 600; // 10 minutes
chrome.idle.onStateChanged.addListener((state) => {
if (state === 'idle') {
// Start countdown to auto-logout
setTimeout(() => {
chrome.idle.queryState(AUTO_LOGOUT_THRESHOLD, (currentState) => {
if (currentState === 'idle') {
// User is still idle - perform logout
performAutoLogout();
}
});
}, 1000); // Small delay to confirm
}
});
function performAutoLogout() {
console.log('Performing automatic logout due to idle');
// Implement logout logic
}
Conclusion
The Chrome Idle Detection API is a powerful tool for building intelligent, user-aware extensions. By detecting when users are present or away, you can create extensions that conserve system resources, optimize performance, and deliver contextual experiences that respect user attention.
In this guide, we covered the fundamentals of the chrome.idle API, including how to set detection intervals, query idle state, and listen for state changes. We explored practical implementation patterns for common use cases, from basic idle detection to sophisticated tab management systems. We also discussed best practices for performance, edge case handling, and error management.
The idle detection capability opens up numerous possibilities for extension developers. Whether you are building memory-optimizing tab suspenders, productivity trackers, smart notification systems, or security-focused tools, understanding how to effectively use the chrome.idle API will make your extensions more intelligent and user-friendly.
As you build your own idle-aware extensions, remember to test thoroughly across different scenarios, including multiple monitors, screen lock states, and various idle thresholds. With proper implementation, idle detection can significantly enhance the value your extensions provide to users.
Start experimenting with the chrome.idle API today, and discover how you can make your Chrome extensions smarter about user presence and absence.
Additional Resources
To learn more about Chrome extension development and related APIs, explore these additional resources:
- Chrome Extensions Documentation
- Manifest V3 Migration Guide
- Chrome Idle API Reference
- Tab Suspender Pro - An example extension using idle detection