Чтобы не открывать постоянное соединение с сервером и не пинговать каждые n секунд, можно придумать следующее:
1) Есть метод perfomance.now() который начинает отсчитывать время, прошедшее с момента загрузки страницы. Сохраняем это время как стартовое.
2) Повесить обработчик события window.beforeUnload() и в нём тем же perfomance.now() получаем время конечное, когда пользователь собирается закрыть страницы. Сохраняем его как конечное.
3) В том же методе перед закрытием окна вызываем navigator.sendBeacon(url, data). По сути это обычный POST запрос, который не требует ответа от сервера. В него и передаем инфу какую хотим (например логин пользователя и время начальное и конечное)
4) Поздравляю, вы прекрасны!
P.S.: Есть нюанс по поводу времени, оно будет считаться вплоть до тех пор, пока пользователь не закроет страницу. Даже если она сутки провесит в браузере. В таком случае можно ещё поиграться с методами onpageshow и onpagehide, чтобы фиксировать только активное время юзера.