Project Awesome project awesome

Performance > ngx-idle-monitor

A lightweight Angular service for tracking user activity, managing session timeouts, and syncing idle state across tabs.

Package 1 stars GitHub

Angular Idle Monitor

A robust, performance-optimized Angular service for tracking user activity, handling session timeouts, and synchronizing idle states across multiple browser tabs using localStorage.

🚀 Features

  • 🔄 Multi-Tab Sync: Activity in one tab resets the timer in all other open tabs of the same application.
  • Performance Focused: Event listeners run outside of NgZone to prevent unnecessary change detection cycles.
  • ⚠️ Warning System: Emit events before the final timeout occurs (perfect for "Stay logged in?" modals).
  • 🌐 SSR Friendly: Safe for use in Universal/SSR applications (checks for isPlatformBrowser).
  • 📡 Keepalive Support: Supports heartbeat functions or Observables to ping your backend during activity.

📦 Installation

  1. install the idle-monitor into your Angular project by npm install ngx-idle-monitor.
  2. Provide the monitor in your app.config.ts (for Standalone) or AppModule.

Standalone (App Config)

import { provideIdleMonitor } from './shared/idle-monitor';

export const appConfig: ApplicationConfig = {
  providers: [
    provideIdleMonitor({
      timeout: 15 * 60 * 1000,      // 15 minutes
      warningDuration: 60 * 1000,   // 1 minute warning
      autostart: true
    })
  ]
};

Usage

Inject the IdleMonitor service into your root component to listen for state changes.

import { Component, inject } from '@angular/core';
import { IdleMonitor } from './shared/idle-monitor';

@Component({
  selector: 'app-root',
  template: `<router-outlet></router-outlet>`
})
export class AppComponent {
  private idle = inject(IdleMonitor);

  constructor() {
    // 1. Handle Inactivity (e.g., Logout)
    this.idle.inactive.subscribe(() => {
      console.log('Session expired due to inactivity.');
      // Perform logout redirect here
    });

    // 2. Handle Warning Period (e.g., Show Countdown Modal)
    this.idle.warning.subscribe((msLeft) => {
      const seconds = Math.floor(msLeft / 1000);
      console.warn(`Inactivity warning: ${seconds}s remaining.`);
    });

    // 3. Handle Return to Activity
    this.idle.active.subscribe(() => {
      console.log('User is active again! Logic to hide modal can go here.');
    });
  }
}

Configuration Options (IdleMonitorConfig)

Property Type Default Description
timeout number 7200000 (2h) Total idle time allowed in milliseconds.
warningDuration number 0 Time in ms before timeout to start emitting warnings.
events string[] ['click', 'mousemove', 'keydown', 'touchstart', 'scroll'] DOM events that trigger activity.
debounce number 200 Debounce time for activity events to save resources.
minUpdateInterval number 1000 Minimum time between writing new activity to storage.
keepaliveFn Function () => {} Executes on activity. Can return an Observable.
autostart boolean true Start monitoring as soon as the app loads.

How It Works

Multi-Tab Synchronization

The service utilizes the StorageEvent API. When activity is detected in Tab A, it updates a timestamp in localStorage (idle-monitor-last-activity). Tab B listens for this storage key change. If Tab B sees a newer timestamp, it automatically resets its own internal timer. This prevents the user from being timed out while they are active in a different window.

Performance & Zone Management

By using runOutsideAngular, high-frequency events like mousemove and scroll do not trigger Angular's change detection engine. The service only re-enters the Angular Zone when it is time to emit a state change (active, inactive, or warning), ensuring your app stays performant even with constant mouse movement.

Manual Time Checking

When a tab is hidden and then becomes visible again (or regains focus), the service performs a manual check against the lastActivity timestamp. This ensures that if the timeout occurred while the computer was asleep or the tab was backgrounded, the inactive event fires immediately upon return.

Back to Angular