Angular 5, how to detect user inactivity

You could try with this :

export class AppComponent {

  userActivity;
  userInactive: Subject<any> = new Subject();

  constructor() {
    this.setTimeout();
    this.userInactive.subscribe(() => console.log('user has been inactive for 3s'));
  }

  setTimeout() {
    this.userActivity = setTimeout(() => this.userInactive.next(undefined), 3000);
  }

  @HostListener('window:mousemove') refreshUserState() {
    clearTimeout(this.userActivity);
    this.setTimeout();
  }
}

Seems to work in this stackblitz : open the console, don't move your mouse for 3 seconds : you see the message.

Refresh the page, move your mouse on the preview (right side) for a couple of seconds : the message doesn't pop until you stop for 3s.

You can obviously export that into a service, because as you can see, I'm using only a class to do that.


Service that solves this problem (instead of a component as the accepted answer), handles touch, type and mouse. Emits an event N seconds after the user has been idle, and when he 'wakes up'. Works on Angular 11:

import { Injectable } from "@angular/core";
import { fromEvent, Subject } from "rxjs";

@Injectable({
    providedIn: 'root',
})
export class IdleService {

  public idle$: Subject<boolean> = new Subject();
  public wake$: Subject<boolean> = new Subject();

  isIdle = false;
  private idleAfterSeconds = 10;
  private countDown;

  constructor() {
    // Setup events
    fromEvent(document, 'mousemove').subscribe(() => this.onInteraction());
    fromEvent(document, 'touchstart').subscribe(() => this.onInteraction());
    fromEvent(document, 'keydown').subscribe(() => this.onInteraction());
  }

  onInteraction() {
    // Is idle and interacting, emit Wake
    if (this.isIdle) {
      this.isIdle = false;
      this.wake$.next(true);
    }

    // User interaction, reset start-idle-timer
    clearTimeout(this.countDown);
    this.countDown = setTimeout(() => {
      // Countdown done without interaction - emit Idle
      this.isIdle = true;
      this.idle$.next(true);
    }, this.idleAfterSeconds * 1_000)
  }
}

Usage, inject in constructor and use:

constructor(private idleService: IdleService) {  
  idleService.idle$.subscribe(s => console.log('im idle, zzz'));
  idleService.wake$.subscribe(s => console.log('im awake!'));
}

A possible solution is to use this package angular-user-idle

I have not used it in real application but might be slightly more robust than the solution proposed in the previous answer.


This solution worked fine for me. the problem I faced with the accepted answer is, it only focuses on mouse events and no keyboard keypress events

    userActivity;
    userInactive: Subject<any> = new Subject();

    constructor( ) {
        
        this.setTimeout();
        this.userInactive.subscribe(() => {
        this.router.navigate(['/auth/lock']);
        });
       
        }
  • These events check if user is idle for a specific time and then subscribe to a different ( lock ) screen

     keyPress(event: KeyboardEvent): void {
         clearTimeout(this.userActivity);
         this.setTimeout();
     }
     setTimeout(): void {
         this.userActivity = setTimeout(() => this.userInactive.next(undefined), 900000);
     }
    
     @HostListener('window:mousemove') refreshUserState() {
         clearTimeout(this.userActivity);
         this.setTimeout();
     }
    

Tags:

Angular