I have a Web app which has an automatic login feature (using Cookies). The app has a lot of logging, so I can tell when users are logging in, logging out, have timed out due to inactivity, etc.
At the moment, I see a lot of logins (using the cookie) in which there appears to be “nobody home” – e.g. the user is not actually using the web app.
I think that this is due to the the browser restoring or reloading a session from before, e.g. the user has the site open in a browser tab, puts their comptuer to sleep, then wakes their computer. The browser restores the tab - and this looks to my webApp as if the user has reloaded the page, but in fact the tab is in the background and the user is not on the site at all.
Question: is there a way in a Xojo Web 2 app to detect this? I suppose I could do it with some sort of UI/UX, putting up a messageDialog saying "Are you there? Click OK to proceed’.
But I’m wondering if there is another way, perhaps detecting browser headers or something?
Also, my memory is that Xojo Web was going to implement some sort of “session restoration” but that this feature was never released. Or was it?
I don’t see what’s wrong with that. If the browser window was sent to the background but the app is still frontmost, the Visible parameter is true. If it is hidden behind another window or tab, Visible is false. This was supported behavior in at least Safari when the feature was implemented.
In terms of event order, there’s not much that can be done about that. IIRC Session.Open and WebPage.Open fire on the server before anything is delivered to the browser. The Activated event fires in response to an event fired by the browser once the initial app assets have been delivered to the browser.
That’s the design of Session.Activated and Session.Deactivated. The Activated event has no Visible parameter because the page can’t be activated without making it visible. I have found through testing that the web app does not get an activated event when the browser but not the tab is brought to the front. You also get a Deactivated event with the Visible parameter as false if the browser window is moved behind something, but the browser is still the active app. These events are effectively tracking the visibility state.
These events are behaving exactly as I would expect them to. I really don’t understand what Mike is trying to do or why, but I suspect there’s a better solution for the actual goal.
It is important to remember that Web and Desktop are different beasts, and building a web app to act like a desktop app is a difficult and often futile objective.
Statisics: detect when a user is actually logging into the system, vs. the browser automatically restoring a background tab. I need this in order to keep track of statistics such as “currently logged in users” and “user X last logged in N days ago”.
Efficiency: avoid wasting resources - by detecting when a user is not actually there, and serving up a placeholder webPage instead of a complicated one requiring a lot of data/database transactions.
Since Session.Activated fires after Session.Opening, you can’t really use any logic inside the Session.Opening event to determine which kind of user (“live” vs. “ghost”).
In the ‘hidden tab restoration’ scenario, neither .Activated nor .Deactivated fires at all, which means you have to guess the status.
I may be able to work around these issues by doing something like this:
me.liveUser=false // assume this is a background tab until proven otherwise
setup a Timer to call Session.TimerCallback later
[... do nothing else important ...]
if liveUser then
user.lastLoginTime = DateTime.Now
I’m not sure how robust this aproach will be, and it’s a lot of extra logic for something which could be simpler.
I have opinions on your complaints, but nothing that can solve what you are considering an issue. I do not consider Activated or Deactivated to be malfunctioning with all of the tests I have performed today. You might consider redesigning your application structure if an inactive tab is really consuming a noticeable amount of database time.
In an effort not to create a negative atmosphere that’s all I can add to this discussion.
@Tim_Parnell I’m appreciating your thoughts & ideas, please don’t worry on my behalf!
Some of this is just hypothetical musing. The CPU usage and bandwidth use of the webApp is pretty low, as I typically have under 100 users and Xojo web 2 is pretty frugal.
I think the problem is due to my design in which
users are given (if they agree) a long-lasting cookie upon login, and if they ever reload the page, they are logged back in automatically via the cookie
I use Session.UserTimedOut to kick off absent users - however, I do this by calling Session.Terminate. While this works to disconnect the user, it leaves the browser tab sitting on the same URL as the webApp.
then, sometime later, the user wakes up their device, the browser restores tabs, and (because of my cookie login logic) they are logged back in, even if they are not actually using the WebApp, the tab is invisible or hidden, etc.
Maybe I could fix this:
what if before calling Session.Terminate, i set Session.HashTag to “#TimedOut”
then, if the browser restores the tab, in Session.Opening I could check the hashTag, and if it is “timedOut” send them to a placeholder webPage which requires a click to log back in.
In addition, if Session.Activated fires, this would imply “actual user, tab is visible” and then I could trigger my auto-cookie-login logic.
I think this might solve most of the issues: keeping inactive users basically offline and out of my statistics, while not hassling actual users and forcing them to go through extra steps.
Thanks @Artur_Zaremba - that looks like a good solution using the WebSDK - the downside is that it requires that you add a control to each WebPage you want to track. I’m still looking for something that can be at a higher level (the WebSession) requiring less code.
I haven’t had a chance to work on this in a few days, but I will report back if I figure out any clever solutions.
Also, I’m not sure how the WebSession.UserTimedOut event works with a backgrounded Tab. If it’s a server-side timer, then I would expect it to work even if the browser has paused the WebPage. But if it’s client-side, then maybe it never fires? That may add some complexity…