#336: User Idle Detection

Visit on Github.

Opened Jan 22, 2019

こんにちはTAG!

I'm requesting a TAG review of:

Further details (optional):

We'd prefer the TAG provide feedback as (please select one):

  • open issues in our Github repo for each point of feedback
  • open a single issue in our Github repo for the entire review
  • leave review feedback as a comment in this issue and @-notify [github usernames]

Discussions

Discussed Feb 1, 2019 (See Github)

Sangwhan: still pending external feedback. At f2f we requested clarification whether it's only accessible from top level frame and have not heard back.

Dan: pinging?

Peter: we have pinging

Lukasz: wondering whether there is a risk of ... not limited to web browsers .. is it limited to the browser or ... operating systems. OS have lock screens.

Sangwhan: it does - if you grant this permission to multiple origins then you can use it for cross origin tracking - if the user goes idle on multiple origins at the samne time you could use it for tracking

Lukasz: usage patterns - conjunction with other APIs e.g. sensors

Alex: this is expressed as a permission - where browsers can decide what policy to apply - fuzziness is available. if the origins are currently running are collaborating with eachother in the same browser process they could build a wormhold scripting relationship in some browsers. e.g. iframe -> relationship -> different window (e.g. through serviceworker). Question here about what else is being exposed and how it's exposed to users is important.

Kanneth: would it idle immediately if the screen turns off?

Sangwhan: OS dependentent?

Lukasz: or use the keyboard or mouse for 1ms - is it idle.

Alex: it's user agent defined.

Lukasz: so different for each UA.

Alex: potentially different for each UA and for each OS - in some it's most approriate to use screen lock as a signal of idleness.

Lukasz: a link betwen browser and OS

Kenneth: browser knows that if there are 5 sites open looking for idle it doesn't have to tell them at the same time.

Alex: we should look at this and make sure that idleness is only being delivered to top level documents, only in secure contexts and documents withough visibility are not having the event delivered.

Kenneth: but if I have an app running int he background i may want people to know I am idle...

Alex: what is the visibility state of tab?

Kenneth: often not visible - not opened -

Alex: there's a question for the services if visibility is strong enough correlation with idleness

Sangwhan: I think it's 2 different flags.

Dan: ... tabs ... I' have notifications in another tab but should people there see me as idle

Kenneth: lot of people want to know if you're available. if you're in a meeting - that's a kind of idling - it's more like "im busy" - whether you're going ot answer an IM or not.

Peter: an "active idle" like a do not disturb or "distracted"

Lukasz: how should this work in private browsing modes and should user be able to disable it. Let's say slack asks for permission to use "idle"...

Alex: question we're being asked - if web platform exposes this, does it expose what develoeprs would need and does it fit with the rest of the platform.

Peter: looks like this is modeled on mution observer / interaction observer. is that right? .. you can pass in a theshold

Lukasz: what's the granularity of updates....

Alice: mutution observers vs. events trade-off: we suggest observers vs events. How would someone know when to use which.

Alex: observers tend ot be about the rate you're going to fire things. it's a good way to do complex configuration. Multiple parties to take a different view of the event stream. for lf stuff an observer is probably not great - event tends to be cleaner and easier. visibility state event vs intersection observers.

Peter: bunch of feedback - can someone(s) summarize?

Alex: i can summarize pieces I recall

Kenneth: I can do some

Carriage of Web Resource in ISOBMFF

Sangwhan: we need to set up a call with David.

Triage of unassigned issues

https://github.com/w3ctag/design-reviews/issues/341 - feature policy evolution - sangwhan

https://github.com/w3ctag/design-reviews/issues/342 - first party sets - david & dan

https://github.com/w3ctag/design-reviews/issues/343 - Verifiable Credentials Data Model 1.0 - hadley

https://github.com/w3ctag/design-reviews/issues/344 - Web Publications - dan

https://github.com/w3ctag/design-reviews/issues/345 - Audio books - david

Comment by @slightlyoff Feb 5, 2019 (See Github)

Discussed briefly today at the TOK F2F. We weren't able to quickly spot a restriction on access to this API from the top-level frame (and, perhaps, delegation via Feature Policy or sandbox attribute). Is that planned?

Comment by @lknik Feb 26, 2019 (See Github)

Looks like it may have a potential to profile users, and perhaps potential to misuses with conjunction with other APIs. Has this been been deployed already by any chance (chrome canary?)?

Comment by @cynthia Feb 26, 2019 (See Github)

Status here: https://www.chromestatus.com/feature/4590256452009984

Comment by @cynthia Feb 26, 2019 (See Github)

@samuelgoto, @inexorabletash do you folks have any feedback on the top-level frame restriction noted above?

Comment by @kenchris Feb 26, 2019 (See Github)
  • Should this be event based instead of observer based? Check our design principles https://w3ctag.github.io/design-principles/#events-vs-observers
  • Should events be delivered to tabs in the background - I think they should, as my Hangouts and Slack tabs are seldom in foreground and people still want to know whether I am idle or not
  • Are events restricted to top-frame and https? - they should be
  • To reduce multiple sites identifying me as the same person due to the time I idle, it might be possible to introduce some fuzziness between reporting to the various observers
  • For IM, users usually want to know if a user is available to know whether they can expect a response or not - but often people in meetings/busy cannot respond - maybe we need a API for sites to report business and these should be tied together
  • how important is the configuration? I can easily start a timer myself for say 5 minutes idling before I update my UI, and the event is only send infrequently

@lknik any more feedback

Comment by @samuelgoto Feb 26, 2019 (See Github)

@samuelgoto, @inexorabletash do you folks have any feedback on the top-level frame restriction noted above?

It sounds like a reasonable restriction to me. @inexorabletash any concerns?

Comment by @inexorabletash Feb 26, 2019 (See Github)

sgtm!

Comment by @samuelgoto Feb 26, 2019 (See Github)

Has this been been deployed already by any chance (chrome canary?)?

The feature is still under development and an early version can be accessed in canaries through runtime flags (so no, not available by default).

Comment by @samuelgoto Feb 26, 2019 (See Github)

sgtm!

Ok, I'll update the explainer to make this easier to find and report back on this thread here.

@slightlyoff any other feedback that you think is worth paying attention to?

Comment by @samuelgoto Feb 28, 2019 (See Github)

Ok, I'll update the explainer to make this easier to find and report back on this thread here.

Done.

Discussed Mar 1, 2019 (See Github)

alice: I took myself off because it seemed like there were enough people on it. Was a good discussion on there already.

sangwhan: My main concern has been addressed... Ken added a bunch of feedback, I haven't read that yet.

sounds of reading

sangwhan: This is about events vs. observers. That hasn't been resolved yet. This is still waiting on external feedback.

torgo: Should we bump this a week or two to wait for feedback? Ken may also not be able to make next week's call, so let's bump two weeks.

Discussed Mar 1, 2019 (See Github)

Kenneth: We gave a lot of feedback - events or observers - they are implementing the idea we raised. They still have some design questions. Not sure if we should close for now... wait for them to close back.

Sangwhan: i think we should remove the milestone and put it to pending extenral feedback.

Dan: suggest we put it to the f2f.

Sangwhan: i couldn't figure out whether it was supposed to be an observer or an event.

Further discussion on design principles to happen here

Comment by @samuelgoto Mar 4, 2019 (See Github)

Great feedback @kenchris ! Let me try to address that!

Should this be event based instead of observer based? Check our design principles https://w3ctag.github.io/design-principles/#events-vs-observers

Great question and thanks for pointing out that doc!! Super helpful!!! The following seems to be the general guidance:

In general, start your design process using an EventTarget and only move to Observers if and when events can’t be made to work well.

In the specific case of idle detection, I run into the following:

Instances observe specific targets, using the observe() and unobserve() methods. The callback provided in the constructor is invoked when something interesting happens to those targets.

In that, in the EventTarget formulation, navigator.idle.query({threshold: 60}) takes a configuration object with a threshold. Does that cross a line to tip us towards observers? Or would are there more precedent for configurations to be passed as the creation of EventTargets?

Should events be delivered to tabs in the background - I think they should, as my Hangouts and Slack tabs are seldom in foreground and people still want to know whether I am idle or not

Yes, events are delivered to tabs in the background. That's more or less the point of the API, because when your tab is in the foreground, idle detection can be polyfillable (with detecting gestures and the Page Visibility API).

Are events restricted to top-frame and https? - they should be

Yes.

To reduce multiple sites identifying me as the same person due to the time I idle, it might be possible to > introduce some fuzziness between reporting to the various observers

Ah, good point. That came up on a security/privacy review. Let me digest this a bit more and circle back.

For IM, users usually want to know if a user is available to know whether they can expect a response or not - but often people in meetings/busy cannot respond - maybe we need a API for sites to report business and these should be tied together

Hummmm ... can you walk me through how this would work?

how important is the configuration? I can easily start a timer myself for say 5 minutes idling before I update my UI, and the event is only send infrequently

The only configuration available is a threshold you pass, in seconds, as the criteria for idleness. Without a threshold, you'd have to poll. Does that make sense?

Comment by @domenic Mar 5, 2019 (See Github)

Or would are there more precedent for configurations to be passed as the creation of EventTargets?

There is precedent. Perhaps the most relevant is the generic sensors API: https://w3c.github.io/sensors/

Which also brings up a good point that it seems you could model this with a constructor instead of a navigator.idle() method which returns a non-constructible object.

I might suggest following the generic sensor API as much as possible in naming and usage style. Although probably not by actually subclassing the Sensor class; it seems like you want a subset of that functionality.

Comment by @kenchris Mar 6, 2019 (See Github)

Maybe something like (Maybe making threshold not optional to avoid polling?)

[SecureContext, Exposed=Window, Constructor(IdleDetectorOptions options)
interface IdleDetector : EventTarget {
  readonly attribute IdleState state;
  readonly attribute DOMHighResTimeStamp? timestamp;
  void start();
  void stop();
  attribute EventHandler onreading;
};

dictionary IdleDetectorOptions {
  double threshold;
};

enum IdleState {
  "active",
  "idle",
  "locked" 
}

From your explainer it sounds like "locked" means that screen was turned off, and not a locked screen like WakeLock - those need to be aligned.

If you really need a one-shot you can add one like the geolocation sensor: https://www.w3.org/TR/geolocation-sensor/#idl-index

[SecureContext, Exposed=Window, Constructor(IdleDetectorOptions options)
interface IdleDetector : EventTarget {
  static Promise<IdleReading> read(optional ReadOptions readOptions);
  readonly attribute DOMHighResTimeStamp? timestamp;
  readonly attribute IdleState state;
  void start();
  void stop();
  attribute EventHandler onreading;
};

dictionary IdleDetectorOptions {
  double threshold;
};

dictionary ReadOptions : IdleDetectorOptions {
  AbortSignal? signal;
};

enum IdleState {
  "active",
  "idle",
  "locked" 
}

ictionary IdleReading {
  DOMHighResTimeStamp? timestamp;
  readonly attribute IdleState state;
}

Examples:

const reading = await IdleDetector.read({ threshold: 2 * 60 });

const detector = new IdleDetector({ threshold: 2 * 60 });
detector.onreading = () => {
  console.log(detector.timestamp, detector.state);
}
detector.start();
Comment by @tomayac Mar 6, 2019 (See Github)

From @samuelgoto's Explainer:

locked - the system has an active screen lock preventing interaction with the user agent

As @kenchris said above, this should indeed be aligned with Wake Lock terms. A type "screen" Wake Lock might still mean the user is idle (or rather: in DND mode, e.g., when presenting or watching a movie). If we think of idle detection use cases, a chat app should probably report "idle" if a screen lock is active (even if it's not the right word) in that case.

Comment by @samuelgoto Mar 7, 2019 (See Github)

Ha, I love IdleDetector @kenchris and thanks for pointing out the sensors API for precedence/inspiration @domenic !

Looking at the Accelerometer for inspiration, here is what it looks like:

let accelerometer = new Accelerometer({ frequency: 10 });
accelerometer.addEventListener('error', event => {
    // Handle runtime errors.
});
accelerometer.addEventListener('reading', () => reloadOnShake(accelerometer));
accelerometer.start();

@kenchris curious: is there a specific reason why you chose a onreading callback EventHandler as opposed to using the addEventListener() method of the subclassing of EventTarget? For example, would something along these lines be more consistent with the Accelerometer design:

let idleDetector = new IdleDetector({ threshold: 60 });
idleDetector.addEventListener('reading', () => reloadOnShake(idleDetector));
idleDetector.start();

Couple of other things that came up: feature detection and permissions/errors/feature policies.

// feature detection
if (window.IdleDetector) {
  /// idle detection available
}

And we thought that making start() return a Promise would allow us to return all sorts of initialization errors. E.g.:

try {
  let idleDetector = new IdleDetector({ threshold: 60 });
  idleDetector.addEventListener('reading', () => reloadOnShake(idleDetector));
  await idleDetector.start();
} catch (e) {
  // deal with permission errors, feature policy errors, etc
}

WDYT?

Putting aside this, I also really like the design for one-shot queries with a static async method. This works really well to me:

const reading = await IdleDetector.read({ threshold: 2 * 60 });
Comment by @samuelgoto Mar 7, 2019 (See Github)

@tomayac wrt

If we think of idle detection use cases, a chat app should probably report "idle" if a screen lock is active (even if it's not the right word) in that case.

I think that's the original intent/model and the implementation.

The state is reported in two orthogonal/different dimensions, the user state (idle/active) and the screen state (locked/unlocked).

We debated a bit whether it would be useful to decouple in different APIs the user state from the screen state, and arrived at bundling but weekly held.

Does that make sense and address your point?

Comment by @kenchris Mar 11, 2019 (See Github)

@kenchris curious: is there a specific reason why you chose a onreading callback EventHandler as opposed to using the addEventListener() method of the subclassing of EventTarget?

Both are supported :-) in addition to the onreading property there is a "reading" event. That is how EventTarget usually works.

Comment by @kenchris Mar 11, 2019 (See Github)

And we thought that making start() return a Promise would allow us to return all sorts of initialization errors. E.g.:

That was considered for Sensors as well. I don't remember the discussion but the conclusion was that it was better not to (there is already the error event, as errors can happen at any time). @tobie @anssiko do you remember?

I believe it is better to not return a promise, just for the sake of consistency across the platform

Comment by @tobie Mar 11, 2019 (See Github)

Yes. We dropped those promises as mentioned here: https://github.com/w3c/sensors/issues/104#issuecomment-248316955.

At best, you had to duplicate your event handlers and then filter out error messages between the promise and the event handler.

At worst it pushed developers to rely only on rejected promises as an error handling strategy and miss a number of error classes.

Comment by @kenchris Mar 11, 2019 (See Github)

Related: https://github.com/w3c/sensors/issues/93

Comment by @anssiko Mar 11, 2019 (See Github)

(For more historical context, this was discussed at famous Lisbon F2F https://www.w3.org/2016/09/20-dap-minutes.html, but I think the issue pointed out by @tobie is the best summary. You know F2F minutes.)

Comment by @torgo Mar 19, 2019 (See Github)

Pink @kenchris - can we discuss next week?

Comment by @kenchris Mar 20, 2019 (See Github)

@torgo sure thing!

Comment by @samuelgoto Mar 20, 2019 (See Github)

I got a CL in that covers a lot of ground and aligns with what was discussed here.

I'll follow up with some more API design questions that came up while we were coding this up momentarily.

Comment by @jwheare Apr 10, 2019 (See Github)

Would a name like “presence detector” be more appropriate to a) avoid confusion with requestIdleCallback and b) communicate that you can detect an active state as well as an idle one?

Comment by @cynthia May 21, 2019 (See Github)

Just to clarify, progress "stalled" has no negative implications, we're still in-progress (or "stalled") with a new (hopefully more efficient) work mode and the dual state means that "we have provided all the technical feedback we could, we know you have acknowledged the feedback and are happy to look at the next iteration when you have something ready".

As for the last comment from @jwheare - we don't have strong opinions about the naming. @kenchris noted that it can be confused with proximity.

Comment by @cynthia Sep 10, 2019 (See Github)

Thanks a lot for all the patience, we don't have much more feedback on this so we'll close this as part of our new process. If there are significant changes in the design, please ask us to re-open.

Thanks again for bringing this to our attention.

Comment by @reillyeon Oct 28, 2020 (See Github)

I would like to ask the TAG to reopen this review as there is now a specification available: https://wicg.github.io/idle-detection

The API design is mostly unchanged from what has been discussed here previously. What has been added is a new 'idle-detection' permission which is required to call start() on an IdleDetector instance.

Discussed Nov 1, 2020 (See Github)

Hadley: relationship with generic sensor API?

Ken: this is very low frequency unlike generic sensor API.

Ken: We were OK with this last time we looked - now there is specificaiton.

Dan: is it part of DAS? Seems related to DAS.

Hadley: checking new charter.. it's not there.

Dan: So what is the trajectory for this work? Where does it go after WICG?

Dan: asking

Dan: so basically we need to take a deeper dive into this spec now that there is a spec.

Ken: I gave feedback in the first review - they seem to have implemented it.

Sangwhan: it's not as scary as you might think - but a question of usefulness. I can think of one use case -

Ken: they want it for the chat apps. That's a pretty compelling one.

Sangwhan: it's not the end of the world without it.

Yves: they want indication of are people looking at ads or not. It could be used for that as well.

Sangwhan: you could use intersection observer for that...

Yves: if you are on your mobile and there is a popup app and you drop your phone waiting for it to start then you will be "idle" so I think it would be used for that.

Dan: I think that's a privacy issue.

Sangwhan: as for the spec at hand I haven't looked at it yet - the updated one.

Dan: I can review for privacy

[bumped 2 weeks]

Comment by @torgo Nov 10, 2020 (See Github)

Hi @reillyeon - one question on this: what is the trajectory for this spec after WICG? Is this intended to be a part of the DAS work? We couldn't find it on the charter. Has there been any thinking on where this ends up? Sorry if that's documented somewhere above and I've missed it.

Comment by @reillyeon Nov 10, 2020 (See Github)

I do not have a particular destination working group in mind for this incubation.

Discussed Jan 1, 2021 (See Github)

Ken: Only big difference is they adopted my API suggestions and added an idle detection permission.

Sangwhan: We discussed this earlier...

Dan: So they respoded to all your feedback...

Ken: Yes, looks like they took it all on and made all the changes we asked for.

Dan: Last comment from Reilly was in response to my question about venue/destination. Intended venue beyond WICG. "We don't have a particular destination in mind" as of Nov. 10.

... Could leave a closing comment saying we're happy you've addressed our feedback, and suggest a venue...

Ken: Seems like WebApps.

Sangwhan: I can leave that feedback.

Dan: Propose close, we can officially close it in plenary.

Comment by @cynthia Jan 12, 2021 (See Github)

Sorry this took so long. We discussed this in our F2F today, and the proposed changes look great to us! From the back of our head, this feels like it would belong in Webapps, but as long as it ends up somewhere we are happy.

Thanks for bringing this to our attention.