I think you would have to do this all on the client side. The idle timer (or session timeout) in Shiny Server is based on client-server interaction. Any activity on the server (like observe or reactivePoll executing) sends idle/busy messages to the client and resets this idle timer. Polling would keep the app alive forever.
From the client side, you can use Shiny's JavaScript events to track client-server interaction. The shiny:message and shiny:inputchange events would probably cover most cases. So something like:
(function() {
var timeoutWarningMsecs = 5 * 1000;
var idleTimer;
function onTimeout() {
alert('warning: session is about to time out!');
}
function startIdleTimer() {
if (idleTimer) clearTimeout(idleTimer);
idleTimer = setTimeout(onTimeout, timeoutWarningMsecs);
}
$(document).on('shiny:message shiny:inputchanged', startIdleTimer);
})();