├── .github
└── workflows
│ └── pr-push.yml
├── .pr-preview.json
├── CONTRIBUTING.md
├── HOWTO.md
├── LICENSE.md
├── README.md
├── annex.md
├── example-page-info.png
├── example-permission-dialog.png
├── index.bs
├── logo-idle.png
├── logo-idle.svg
├── mdn-drafts
└── QUICK-REFERENCE.md
├── security-privacy-self-assessment.md
└── w3c.json
/.github/workflows/pr-push.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | pull_request: {}
4 | push:
5 | branches: [main]
6 |
7 | jobs:
8 | main:
9 | name: Build, Validate and Deploy
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 | - uses: w3c/spec-prod@v1
14 | with:
15 | GH_PAGES_BRANCH: gh-pages
16 | VALIDATE_MARKUP: false
17 |
--------------------------------------------------------------------------------
/.pr-preview.json:
--------------------------------------------------------------------------------
1 | {
2 | "src_file": "index.bs",
3 | "type": "bikeshed",
4 | "params": {
5 | "force": 1
6 | }
7 | }
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Web Platform Incubator Community Group
2 |
3 | This repository is being used for work in the W3C Web Platform Incubator Community Group, governed by the [W3C Community License
4 | Agreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To make substantive contributions,
5 | you must join the CG.
6 |
7 | If you are not the sole contributor to a contribution (pull request), please identify all
8 | contributors in the pull request comment.
9 |
10 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows:
11 |
12 | ```
13 | +@github_username
14 | ```
15 |
16 | If you added a contributor by mistake, you can remove them in a comment with:
17 |
18 | ```
19 | -@github_username
20 | ```
21 |
22 | If you are making a pull request on behalf of someone else but you had no part in designing the
23 | feature, you can remove yourself with the above syntax.
24 |
--------------------------------------------------------------------------------
/HOWTO.md:
--------------------------------------------------------------------------------
1 | # How to use the IdleDetector API
2 |
3 | The IdleDetector API is currently available in Chrome 84 and later behind a flag or by registering your domain for [the Origin Trial](https://developers.chrome.com/origintrials/#/view_trial/551690954352885761) (available until November 10th, 2020).
4 |
5 | 1) Download Chrome ([Android](https://play.google.com/store/apps/details?id=com.android.chrome), [Desktop](https://www.google.com/chrome/)).
6 | 2) Navigate to `chrome://flags` and enable `Experimental Web Platform features`.
7 | 3) Navigate to a test page, e.g. https://reillyeon.github.io/idle.html
8 | 4) Go idle (e.g. stop moving your mouse, typing on your keyboard or lock your screen)
9 |
10 | Here is an example of how to use the API:
11 |
12 | ```javascript
13 | async function main() {
14 | // feature detection.
15 | if (!window.IdleDetector) {
16 | console.log("IdleDetector is not available :(");
17 | return;
18 | }
19 |
20 | log("IdleDetector is available! Go idle!");
21 |
22 | try {
23 | await IdleDetector.requestPermission();
24 |
25 | let idleDetector = new IdleDetector();
26 | idleDetector.addEventListener('change', e => {
27 | console.log(`[${new Date().toLocaleString()}] idle change: ${idleDetector.userState}, ${idleDetector.screenState}`);
28 | });
29 | // There is a minimum limit here of 60 seconds.
30 | await idleDetector.start({threshold: 60000});
31 | } catch (e) {
32 | // deal with initialization errors.
33 | // permission denied, running outside of top-level frame, etc
34 | console.log(`Initialization error: ${e}.`);
35 | }
36 | };
37 | ```
38 |
39 | You should see something along the lines of:
40 |
41 | ```
42 | [4/4/2019, 2:59:54 PM] idle change: active, unlocked
43 | [4/4/2019, 3:00:54 PM] idle change: idle, unlocked
44 | [4/4/2019, 3:01:07 PM] idle change: active, unlocked
45 | [4/4/2019, 3:02:25 PM] idle change: idle, unlocked
46 | [4/4/2019, 3:02:41 PM] idle change: active, unlocked
47 | [4/4/2019, 3:03:56 PM] idle change: idle, unlocked
48 | [4/4/2019, 3:12:56 PM] idle change: idle, locked
49 | [4/4/2019, 3:17:38 PM] idle change: active, unlocked
50 | ```
51 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | All Reports in this Repository are licensed by Contributors
2 | under the
3 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document).
4 |
5 | Contributions to Specifications are made under the
6 | [W3C CLA](https://www.w3.org/community/about/agreements/cla/).
7 |
8 | Contributions to Test Suites are made under the
9 | [W3C 3-clause BSD License](https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html)
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # User Idle Detection
4 |
5 | [Read the draft specification](https://wicg.github.io/idle-detection).
6 |
7 | This proposed API allows developers to add an event listener for when the user
8 | becomes idle (e.g. they don’t interact with the keyboard, mouse or touchscreen,
9 | when a screensaver activates or when the screen is locked). Unlike solutions
10 | based on monitoring input events this capability extends beyond the site's
11 | content area (e.g. when users move to a different window or tab).
12 |
13 | Native applications and browser extensions (e.g. [Chrome
14 | apps](https://developer.chrome.com/apps/idle), [Android
15 | apps](https://stackoverflow.com/questions/8317331/detecting-when-screen-is-locked),
16 | [Firefox
17 | extensions](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/idle),
18 | [Edge
19 | extensions](https://github.com/MicrosoftDocs/edge-developer/blob/master/microsoft-edge/extensions/api-support/supported-apis.md#idle))
20 | use idle detection to notify other users that the user is unreachable (e.g. in
21 | chat applications), to show timely alerts (e.g. "welcome back" when a user
22 | returns to their task) or to pause media (e.g. to save bandwidth when the user
23 | is not present).
24 |
25 | The API should provide a means to _detect_ the user's idle status (active, idle,
26 | locked), and a power-efficient way to be _notified_ of changes to the status
27 | without polling from script.
28 |
29 | Feedback: [WICG Discourse
30 | Thread](https://discourse.wicg.io/t/idle-detection-api/2959) —
31 | [Issues](https://github.com/inexorabletash/idle-detection/issues)
32 |
33 | ## Use cases
34 |
35 | * Chat application: presenting a user's status to other users and delivering
36 | notifications to the device where the user is active.
37 | * Showing timely notifications - e.g. deferring displaying feedback until the
38 | user returns to an active state.
39 | * Updating an outdated service worker when there's no unsaved state by
40 | triggering reloading of the tab.
41 |
42 | ## Relationship with other APIs
43 |
44 | * As opposed to the
45 | [requestIdleCallback](https://www.w3.org/TR/requestidlecallback/), this is
46 | _not_ about asynchronously scheduling work when the **system** is idle.
47 | * As opposed to the [Page Visibility
48 | API](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API),
49 | this API enables detecting idleness even after a page is no longer visible
50 | (e.g. after the page is no longer visible, is the user still around? if i
51 | showed a notification, would it be perceived?).
52 |
53 | ## Polyfills
54 |
55 | Currently, web apps (e.g. Dropbox’s
56 | [idle.ts](https://github.com/dropbox/idle.ts)) are constrained to their own
57 | content area:
58 |
59 | 1. costly polling for input events or
60 | 1. listening to [visibility
61 | changes](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API)
62 |
63 | Script can't tell today when a user goes idle outside of its content area (e.g.
64 | whether a user is on a different tab or logged out of the computer altogether).
65 |
66 | ## Model
67 |
68 | The API assumes that there is some level of engagement between the user, user
69 | agent, and operating system of the device in use. This is represented in two
70 | dimensions:
71 |
72 | 1. The user idle state
73 | * **active**/**idle** - the user has / has not interacted with the user agent
74 | for some period of time
75 | 2. The screen idle state
76 | * **locked**/**unlocked** - the system has an active screen lock preventing
77 | interaction with the user agent
78 |
79 | Distinguishing "active" from "idle" requires heuristics that may differ across
80 | user, user agent, and operating system. It should also be a reasonably coarse
81 | threshold (See Privacy).
82 |
83 | The model intentionally does not formally distinguish between interaction with
84 | particular content (i.e. the web page in a tab using the API), the user agent as
85 | a whole, or the operating system; this definition is left to the user agent.
86 |
87 | > Example: The user is interacting with an operating system providing multiple
88 | > virtual desktops. The user may be actively interacting with one virtual
89 | > desktop, but unable to see the content of another virtual desktop. A user
90 | > agent presenting content on the second virtual desktop may report an "idle"
91 | > state rather than an "active" state.
92 |
93 | ## API Design
94 |
95 | The API design is largely inspired by the [Sensors
96 | API](https://w3c.github.io/sensors). You can find more about alternatives
97 | considered [here](annex.md).
98 |
99 | ### WebIDL
100 |
101 | ```js
102 | dictionary IdleOptions {
103 | [EnforceRange] unsigned long threshold;
104 | AbortSignal signal;
105 | };
106 |
107 | enum UserIdleState {
108 | "active",
109 | "idle"
110 | };
111 |
112 | enum ScreenIdleState {
113 | "locked",
114 | "unlocked"
115 | };
116 |
117 | [
118 | SecureContext,
119 | Exposed=(Window,DedicatedWorker)
120 | ] interface IdleDetector : EventTarget {
121 | constructor();
122 | readonly attribute UserIdleState? userState;
123 | readonly attribute ScreenIdleState? screenState;
124 | attribute EventHandler onchange;
125 | [Exposed=Window] static Promise requestPermission();
126 | Promise start(optional IdleOptions options = {});
127 | };
128 | ```
129 |
130 | ### Example
131 |
132 | Here is an example of how to use it (more detailed instructions
133 | [here](HOWTO.md)):
134 |
135 | ```js
136 | const main = async () => {
137 | // Feature detection.
138 | if (!('IdleDetector' in window)) {
139 | return console.log('IdleDetector is not available.');
140 | }
141 | // Request permission to use the feature.
142 | if ((await IdleDetector.requestPermission() !== 'granted') {
143 | return console.log('Idle detection permission not granted.');
144 | }
145 | try {
146 | const controller = new AbortController();
147 | const signal = controller.signal;
148 |
149 | const idleDetector = new IdleDetector();
150 | idleDetector.addEventListener('change', () => {
151 | console.log(`Idle change: ${idleDetector.userState}, ${idleDetector.screenState}.`);
152 | });
153 | await idleDetector.start({
154 | threshold: 60000,
155 | signal,
156 | });
157 | console.log('IdleDetector is active.');
158 |
159 | window.setTimeout(() => {
160 | controller.abort();
161 | console.log('IdleDetector is stopped.');
162 | }, 120000);
163 | } catch (err) {
164 | // Deal with initialization errors like permission denied,
165 | // running outside of top-level frame, etc.
166 | console.error(err.name, err.message);
167 | }
168 | };
169 |
170 | main();
171 | ```
172 |
173 | ## Platforms
174 |
175 | All platforms (Linux, Windows, macOS, Android, iOS and Chrome OS) support some
176 | form of idle detection.
177 |
178 | On desktop devices (Chrome OS, Linux, macOS and Windows), a screen saver (from a
179 | time when monitors were damaged if the same pixels were lit for an extended
180 | period of time) activates after a user-configurable period of inactivity. The
181 | operating system may optionally require the user to reauthenticate (i.e. lock
182 | the screen) after the screen saver has been activated for a period of time. Both
183 | of these events are observable by engines.
184 |
185 | On mobile devices (Android and iOS), the screen is dimmed after a few seconds of
186 | inactivity (to save battery, not pixels) but this isn't observable by engines
187 | (on Android). The screen is eventually turned off (to save further battery) if
188 | the user remains inactive for a configurable amount of time (typically 30
189 | seconds), and that is observable by engines. When the screen goes off, the
190 | screen is also typically locked (unlockable by Swipe, Pattern, PIN or Password),
191 | although it can be configured to be left off but unlocked.
192 |
193 | ## Permissions
194 |
195 | The ability to use this API will be controlled by the new [`"idle-detection"`
196 | permission].
197 |
198 | ## Security and Privacy
199 |
200 | See answers to the W3C TAG's [security & privacy self-review
201 | questionnaire](https://www.w3.org/TR/security-privacy-questionnaire/) in
202 | [security-privacy-self-assessment.md](security-privacy-self-assessment.md).
203 |
204 | The idle state is a global system property and so care must be taken to prevent
205 | this from being used as a cross-origin communication or identification channel.
206 | This is similar to other APIs which provide access to system events such as
207 | [Generic Sensors](https://w3c.github.io/sensors/) and
208 | [Geolocation](https://w3c.github.io/geolocation-api/).
209 |
210 | A short idle threshold could be used to identify user behavior in another tab.
211 | With a short enough threshold an idle state change could be used to measure
212 | typing cadence when the user is in another application and thus leak sensitive
213 | data such as passwords.
214 |
215 | Users with physical or cognitive impairments may require more time to interact
216 | with user agents and content. The API should not allow distinguishing such
217 | users, or limiting their ability to interact with content any more than existing
218 | observation of UI events.
219 |
220 | If an implementation restricts the detection threshold it should also restrict
221 | how quickly responses to `start()` are delivered or ensure that the response is
222 | cached or otherwise provide a guarantee that rapid polling does not bypass the
223 | restriction on data granularity.
224 |
225 | To mitigate the exposure of this global state the API should be restricted to
226 | top-level frames with a new `"idle-detection"` permission. This permission can
227 | be delegated to sub-frames via [Permissions Policy] or the [`sandbox`
228 | attribute]. The top-level frame requirement significantly reduces the number of
229 | cross-origin contexts which can observe the state event and thus identify the
230 | user through backend communication channels.
231 |
232 | Requiring a permission does not completely mitigate the cross-origin
233 | identification issue but further reduces the number of sites which are able to
234 | participate in such an attack.
235 |
236 | A new permission informs the user about the permission the page is requesting.
237 |
238 | > 
239 | >
240 | > Example icon and text for an `"idle-detection"` permission request.
241 |
242 | Rather than expanding the definition of an existing permission, it is clear to
243 | users which sites have access to additional capabilities.
244 |
245 | > 
246 | >
247 | > Example page information dialog box showing a site with both
248 | > `"notifications"` and `"idle-detection"` permissions granted.
249 |
250 | This capability changes the web privacy model by allowing the site to observe a
251 | limited amount of information about how the user interacts with their device
252 | outside the border of the site's content area. Sites using this permission
253 | should present the request in a context which explains the value to the user of
254 | being granted this capability.
255 |
256 | Implementations that provide a "privacy browsing" mode should not enable this
257 | capability in such a mode. This may be satisfied incidentally by not allowing
258 | notification permission to be granted. Care should be taken to avoid allowing
259 | sites to detect this mode by, for example, randomly delaying the automatic
260 | disapproval of the notification permission so that it appears to have been
261 | denied by the user.
262 |
263 | ## Alternative Permissions Models
264 |
265 | ### Event Timing Fuzzing
266 |
267 | The current idle state and the timing of transitions between states are global
268 | state which could be used to identify a user across origin boundaries. For
269 | example, two cooperating sites could compare the timestamps at which they
270 | observed clients transitioning from `"active"` to `"idle"`. Two clients which
271 | appear to consistently make transitions at the same time have a high likelyhood
272 | of being the same user.
273 |
274 | A mitigation with the potential to directly address this attack is to add a
275 | random delay between when the specified threshold is passed and when the
276 | `"change"` event is fired.
277 |
278 | This mitigation was considered and determined to be unacceptable because:
279 |
280 | * Delaying the event by even a small amount drastically reduces the usefulness
281 | of the API in chat applications which want to ensure that messages are
282 | delivered to the correct device.
283 | * Even with a large fuzzing factor (e.g. 30 seconds) data collected over a long
284 | period of time is still sufficient to identify the user.
285 |
286 | ### Combined with Notification Permission
287 |
288 | Rather than defining a new `"idle-detection"` permission, the definition of the
289 | existing `"notifications"` permission could be expanded to control access to
290 | this capability. The most compelling use cases for this capability involve
291 | messaging applications, so the [`"notifications"` permission] seems
292 | appropriate.
293 |
294 | The advantage of not defining a new permission type is that it helps to avoid
295 | "consent fatigue", in which users are presented with an endlessly increasing
296 | number of choices by operating systems, browsers, and web sites. Adding this
297 | capability to a related permission such as `"notifications"` can maintain a
298 | user's control while reducing the number of decisions that need to be made.
299 |
300 | The disadvantage of not defining a new permission is that it changes the meaning
301 | of permission decisions the user had made in the past. While notifications are
302 | related to signals of user presence the ability to monitor this state may not be
303 | something the user considers when granting this permission.
304 |
305 | There is a middle-ground in which the permission prompt text for the
306 | [`"notifications"` permission] is updated to explain this new capability but
307 | both capabilities are still controlled by a single permission. Implementations
308 | could internally track whether the user has seen the updated prompt and require
309 | a site re-request the [`"notifications"` permission] before it has access to the
310 | new capability.
311 |
312 | ## Prior Work
313 |
314 | * Chrome's [chrome.idle](https://developer.chrome.com/apps/idle) API for
315 | apps/extensions, which is a direct inspiration for this proposal.
316 | * Also exposed to Extensions in Firefox
317 | [MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/idle)
318 | * And
319 | [Edge](https://github.com/MicrosoftDocs/edge-developer/blob/master/microsoft-edge/extensions/api-support/supported-apis.md#idle)
320 | * That API has a global (per-execution-context) threshold and one source of
321 | events. This makes it difficult for two components on the same page to
322 | implement different thresholds.
323 | * Attempts to do this from JS running on the page:
324 | * [idle.ts](https://github.com/dropbox/idle.ts) from Dropbox
325 | * [Idle.js](http://shawnmclean.com/detecting-if-user-is-idle-away-or-back-by-using-idle-js/)
326 |
327 | [`"notifications"` permission]: https://w3c.github.io/permissions/#notifications
328 | [Permissions Policy]: https://w3c.github.io/webappsec-permissions-policy/
329 | [`sandbox` attribute]: https://html.spec.whatwg.org/multipage/iframe-embed-object.html#attr-iframe-sandbox
330 |
--------------------------------------------------------------------------------
/annex.md:
--------------------------------------------------------------------------------
1 | There are multiple alternatives to be considered here. Here are the ones that we ran into:
2 |
3 | * [IdleObserver](#IdleObserver)
4 | * [navigator.idle.query()](#navigatoridlequery) and variations ([chrome.idle](#chrome.idle.query), [browser.idle](#browser.idle.query))
5 |
6 | Here are some guidance on [Events vs Observers](https://w3ctag.github.io/design-principles/#events-vs-observers) we got from the TAG review.
7 |
8 | ### Alternatives Considered
9 |
10 | #### IdleDetector
11 |
12 | This formulation is inspired by [@kenchris's feedback](https://github.com/w3ctag/design-reviews/issues/336#issuecomment-470077151), the overall guidance on [Observers vs EventTargets](https://w3ctag.github.io/design-principles/#events-vs-observers), and the [Sensor API](https://w3c.github.io/sensors/#feature-detection), specifically, the [`Accelerometer`](https://w3c.github.io/sensors/#feature-detection) class.
13 |
14 | ```js
15 | async function main() {
16 | // feature detection.
17 | if (!window.IdleDetector) {
18 | console.log("IdleDetector is not available :(");
19 | return;
20 | }
21 |
22 | console.log("IdleDetector is available! Go idle!");
23 |
24 | try {
25 | let idleDetector = new IdleDetector({ threshold: 60 });
26 | idleDetector.addEventListener('change', ({user, screen}) => {
27 | console.log(`idle change: ${user}, ${screen}`);
28 | });
29 | await idleDetector.start();
30 | } catch (e) {
31 | // deal with initialization errors.
32 | // permission denied, running outside of top-level frame, etc
33 | }
34 | };
35 | ```
36 |
37 | And for a one-shot reading of the state:
38 |
39 | ```js
40 | const {user, screen} = await IdleDetector.read({ threshold: 2 * 60 });
41 | ```
42 |
43 | #### IdleObserver
44 |
45 | This formulation is inspired by the [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver), the [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) and the [PerformanceObserver](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver) APIs.
46 |
47 | ```js
48 | const observer = new IdleObserver({user, screen} => {
49 | // do stuff
50 | });
51 |
52 | // Define "idle" as two minutes of inactivity.
53 | observer.observe({threshold: 2*60});
54 | ```
55 |
56 | Open questions:
57 |
58 | * Should we allow observer.disconnect()?
59 | * Should we allow multiple new IdleObserver() to run concurrently?
60 |
61 |
62 | #### navigator.idle.query
63 |
64 | This formulation is closer to chrome's [`chrome.idle.query()`](https://developer.chrome.com/apps/idle) API and [`browser.idle,queryState()`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/idle/queryState):
65 |
66 | ```js
67 | const monitor = navigator.idle.query({threshold: 2 * 60});
68 |
69 | // Listen to state changes
70 | monitor.addEventListener('change', ({user, screen}) => {
71 | // do stuff
72 | });
73 | ```
74 |
75 | Or, if you only care about the current state:
76 |
77 | ```js
78 | navigator.idle.query({threshold: 2 * 60})
79 | .addEventListener({once: true}, ({user, screen}) => {
80 | // do stuff
81 | });
82 | ```
83 |
84 | Open questions:
85 |
86 | * do we have a preference between `navigator.idle.query()` or `navigator.idle.observe()`?
87 | * should we `navigator.idle.query()` return a `Promise` such that the current state is returned easily?
88 |
89 | #### Variations
90 |
91 | Here are some variations of the Observer pattern that we could try too:
92 |
93 | ```js
94 | navigator.idle.observe({threshold: 2*60}, (e) => console.log(e))
95 |
96 | let observer = navigator.idle.query({threshold: 2*60}, e => console.log(e))
97 | observe.observe()
98 |
99 | // More consistent with MutationObserver, less consistent with
100 | // the other static navigator.* APIs.
101 | let observer = new IdleObserver(e => console.log(e));
102 | observer.observe({threshold: 2*60});
103 | ```
104 |
--------------------------------------------------------------------------------
/example-page-info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WICG/idle-detection/183730b9a7a73e015866d5296c7e957aafe19463/example-page-info.png
--------------------------------------------------------------------------------
/example-permission-dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WICG/idle-detection/183730b9a7a73e015866d5296c7e957aafe19463/example-permission-dialog.png
--------------------------------------------------------------------------------
/index.bs:
--------------------------------------------------------------------------------
1 |
2 | Title: Idle Detection API
3 | Status: w3c/CG-DRAFT
4 | ED: https://wicg.github.io/idle-detection/
5 | Shortname: idle-detection
6 | Level: 1
7 | Editor: Reilly Grant 83788, Google LLC https://www.google.com, reillyg@google.com
8 | Abstract: This document defines a web platform API for observing system-wide user presence signals.
9 | Group: wicg
10 | Repository: https://github.com/WICG/idle-detection/
11 | Favicon: logo-idle.png
12 | Markup Shorthands: css no, markdown yes
13 | WPT Display: inline
14 | WPT Path Prefix: /idle-detection/
15 |
35 |
36 |
48 |
49 | # Introduction # {#introduction}
50 |
51 | *This section is non-normative.*
52 |
53 | Using existing capabilities a page is able to determine when it is currently
54 | visible to the user (using the {{Document/hidden}} property and
55 | {{Document/onvisibilitychange}} event). It is also possible to know when the
56 | user has recently interacted with the page by observing
57 | {{GlobalEventHandlers/onmousemove}}, {{GlobalEventHandlers/onkeypress}}, and
58 | other events triggered by user input. While sufficiently reflecting user
59 | engagement with a particular page these events give an incomplete picture of
60 | whether the user is still present at their device. For example, if
61 | {{Document/hidden}} is `true`, then the device screensaver may have activated,
62 | or the user could have switched to a different application. If it is `false` but
63 | there have been no recent input events, then the user could have left their
64 | computer to grab a cup of coffee, or they could be editing a document in another
65 | window side-by-side with the page.
66 |
67 | Making these distinctions is important for applications which have the option of
68 | delivering notifications across multiple devices, such as a desktop and
69 | smartphone. Users may find it frustrating when notifications are delivered to
70 | the wrong device or are disruptive. For example, if they switch from a tab
71 | containing a messaging application to one for a document they are editing, the
72 | messaging application, not being able to observe that the user is still
73 | interacting with their device, may assume that they have left to grab a coffee
74 | and start delivering notifications to their phone, causing it to buzz
75 | distractingly, instead of displaying notifications on their desktop or
76 | incrementing a badge count.
77 |
78 | ## Alternatives Considered ## {#alternatives-considered}
79 |
80 | An alternative design would protect this information by allowing a notification
81 | to be marked as "hide on active" or "hide on idle" and not allowing the page to
82 | observe whether or not the notification was actually shown. The problem with
83 | this approach is that the intelligent notification routing described previously
84 | requires observing these signals of user presence and making centralized
85 | decisions based on the state of all of the user's devices.
86 |
87 | For example, to route notifications to a user's mobile device when they get up
88 | to grab a coffee the messaging application could detect that it is no longer
89 | visible and start sending push messages to the mobile device while marking the
90 | desktop notifications as "hide on active". If the user were still at their desk
91 | but using a different application then they would start getting the distracting
92 | notifications from their mobile device this proposal is attempting to avoid
93 | whether or not the desktop is able to successfully suppress them. Successful
94 | suppression of duplicate and disruptive notification requires multi-device
95 | coordination.
96 |
97 | Allowing notifications to be hidden also breaks implementor mitigations for the
98 | [[PUSH-API]] being used to run silent background tasks.
99 |
100 | # Observing User Presence # {#api}
101 |
102 | ## Model ## {#api-model}
103 |
104 | This specification defines a model for user presence on two dimensions: idle
105 | state and screen lock.
106 |
107 | ### The {{UserIdleState}} enum ### {#api-useridlestate}
108 |
109 |
110 | enum UserIdleState {
111 | "active",
112 | "idle"
113 | };
114 |
115 |
116 | : {{"active"}}
117 |
118 | :: Indicates that the user has interacted with the device in the last
119 | {{IdleOptions/threshold}} milliseconds.
120 |
121 | : {{"idle"}}
122 |
123 | :: Indicates that the user has not interacted with the device in at least
124 | {{IdleOptions/threshold}} milliseconds.
125 |
126 | ### The {{ScreenIdleState}} enum ### {#api-screenidlestate}
127 |
128 |
129 | enum ScreenIdleState {
130 | "locked",
131 | "unlocked"
132 | };
133 |
134 |
135 | : {{"locked"}}
136 |
137 | :: Indicates that the device has engaged a screensaver or lock screen which
138 | prevents content from being seen or interacted with.
139 |
140 | : {{"unlocked"}}
141 |
142 | :: Indicates that the device is able to display content and be interacted with.
143 |
144 | ## Permissions ## {#api-permissions}
145 |
146 | The "idle-detection" permission is a [=default powerful feature=].
147 |
148 | ## Permissions policy ## {#api-permissions-policy}
149 |
150 | This specification defines a [=policy-controlled feature=] identified by the
151 | string `"idle-detection"`. Its [=default allowlist=] is `'self'`.
152 |
153 |
154 | The [=default allowlist=] of `'self'` allows usage of this feature on
155 | same-origin nested frames by default but prevents access by third-party content.
156 |
157 | Third-party usage can be selectively enabled by adding the
158 | `allow="idle-detection"` attribute to an {{iframe}} element:
159 |
160 |
161 | ```html
162 |
163 | ```
164 |
165 |
166 | Alternatively, this feature can be disabled completely in first-party contexts
167 | by specifying the permissions policy in an HTTP response header:
168 |
169 |
255 |
256 | ### {{IdleDetector/onchange}} attribute ### {#api-idledetector-onchange}
257 |
258 | onchange is an Event handler IDL
259 | attribute for the {{change}} event type.
260 |
261 | ### {{IdleDetector/requestPermission()}} method ### {#api-idledetector-requestpermission}
262 |
263 |
264 | The requestPermission() method steps are:
265 |
266 | 1. If [=this=]'s [=relevant global object=]'s [=associated Document=] is not
267 | [=fully active=], return [=a promise rejected with=] a
268 | "{{InvalidStateError}}" {{DOMException}}.
269 |
270 | idle-detection-detached-frame.https.html
271 |
272 | 1. If the [=relevant global object=] of [=this=] does not have [=transient
273 | activation=], return [=a promise rejected with=] a "{{NotAllowedError}}"
274 | {{DOMException}}.
275 | 1. Let |result| be [=a new promise=].
276 | 1. [=In parallel=]:
277 | 1. Let |permissionState| be the result of [=requesting permission to use=]
278 | "idle-detection".
279 | 1. [=Queue a global task=] on the [=relevant global object=] of [=this=]
280 | using the [=idle detection task source=] to [=resolve=] |result| with
281 | |permissionState|.
282 | 1. Return |result|.
283 |
284 |
289 |
290 | The start(|options|) method steps are:
291 |
292 | 1. Let |document| be [=this=]'s [=relevant global object=]'s [=associated
293 | Document=].
294 | 1. If |document| is not [=fully active=], return [=a promise rejected with=] a
295 | "{{InvalidStateError}}" {{DOMException}}.
296 |
297 | idle-detection-detached-frame.https.html
298 |
299 | 1. If |document| is not [=allowed to use=] "idle-detection",
300 | return [=a promise rejected with=] a "{{NotAllowedError}}" {{DOMException}}.
301 |
302 | idle-detection-allowed-by-permissions-policy-attribute-redirect-on-load.https.sub.html
303 | idle-detection-allowed-by-permissions-policy-attribute.https.sub.html
304 | idle-detection-allowed-by-permissions-policy.https.sub.html
305 | idle-detection-default-permissions-policy.https.sub.html
306 | idle-detection-disabled-by-permissions-policy.https.sub.html
307 |
308 | 1. If |this|.{{IdleDetector/[[state]]}} is not `"stopped"`,
309 | return [=a promise rejected with=] an "{{InvalidStateError}}" {{DOMException}}.
310 |
311 | interceptor.https.html
312 |
313 | 1. Set |this|.{{IdleDetector/[[state]]}} to `"starting"`.
314 | 1. If |options|[{{"threshold"}}] is less than 60,000, return [=a promise rejected with=]
315 | a {{TypeError}}.
316 |
317 | basics.tentative.https.window.js
318 |
319 | 1. Let |result| be [=a new promise=].
320 | 1. If |options|["{{signal}}"] is present, then perform the following sub-steps:
321 | 1. If |options|["{{signal}}"] is [=AbortSignal/aborted=], then
322 | [=reject=] |result| with |options|["{{signal}}"]'s [=AbortSignal/abort reason=]
323 | and return |result|.
324 | 1. [=AbortSignal/add|Add the following abort steps=] to
325 | |options|["{{signal}}"]:
326 | 1. Set |this|.{{IdleDetector/[[state]]}} to `"stopped"`.
327 | 1. [=Reject=] |result| with |options|["{{signal}}"]'s [=AbortSignal/abort reason=].
328 |
329 |
330 | interceptor.https.html
331 |
332 | 1. [=In parallel=]:
333 | 1. Let |permissionState| be the [=permission state=] of `"idle-detection"`.
334 | idle-permission.tentative.https.window.js
335 | 1. [=Queue a global task=] on the [=relevant global object=] of [=this=]
336 | using the [=idle detection task source=] to perform the following steps:
337 | 1. If |permissionState| is `"denied"`,
338 | 1. Set |this|.{{IdleDetector/[[state]]}} to `"stopped"`.
339 | 1. [=Reject=] |result| with a "{{NotAllowedError}}" {{DOMException}}.
340 | 1. Otherwise,
341 | 1. If |this|.{{IdleDetector/[[state]]}} is `"stopped"`, abort these
342 | steps.
343 | 1. Set |this|.{{IdleDetector/[[state]]}} to `"started"`.
344 | 1. Set |this|.{{IdleDetector/[[threshold]]}} to |options|["{{threshold}}"].
345 | 1. [=Resolve=] |result|.
346 | 1. Return |result|.
347 |
348 | Note: The steps above are performed [=in parallel=] to enable implementations
349 | to check the permission state asynchronously.
350 |
351 |
352 |
353 |
354 |
355 | The availability of this API can be detected by looking for the {{IdleDetector}}
356 | constructor in the {{Window}} object.
357 |
358 | ```js
359 | if (!('IdleDetector' in window)) {
360 | console.log('Idle detection is not available.');
361 | return;
362 | }
363 | ```
364 |
365 | Calling {{start()}} will fail if the "idle-detection" permission
366 | has not been [=permission/granted=].
367 |
368 | ```js
369 | if ((await IdleDetector.requestPermission()) !== 'granted') {
370 | console.log('Idle detection permission not granted.');
371 | return;
372 | }
373 | ```
374 |
375 | A set of options can be configured to control the threshold the [=user agent=]
376 | uses to decide when the user has become idle.
377 |
378 | ```js
379 | const controller = new AbortController();
380 | const signal = controller.signal;
381 |
382 | const options = {
383 | threshold: 60_000,
384 | signal,
385 | };
386 | ```
387 |
388 | The {{IdleDetector}} can now be created and started. An listener for the
389 | {{"change"}} event is added and will be fired if the {{userState}} or
390 | {{screenState}} attributes change.
391 |
392 | ```js
393 | try {
394 | const idleDetector = new IdleDetector();
395 | idleDetector.addEventListener('change', () => {
396 | console.log(`Idle change: ${idleDetector.userState}, ${idleDetector.screenState}.`);
397 | });
398 | await idleDetector.start(options);
399 | console.log('IdleDetector is active.');
400 | } catch (err) {
401 | // Deal with initialization errors like permission denied,
402 | // running outside of top-level frame, etc.
403 | console.error(err.name, err.message);
404 | }
405 | ```
406 |
407 | At a later time the page can cancel its interest in state change events by
408 | removing its event listeners or using the {{AbortSignal}} that was passed to
409 | {{start()}}.
410 |
411 | ```js
412 | controller.abort();
413 | console.log('IdleDetector is stopped.');
414 | ```
415 |
416 |
417 | ### Reacting to state changes ### {#state-changes}
418 |
419 |
420 |
421 | For each {{IdleDetector}} instance |detector| where |detector|.{{[[state]]}} is
422 | `"started"` the [=user agent=] MUST continuously monitor the following
423 | conditions:
424 |
425 | * If |detector|.{{[[userState]]}} is {{"active"}} and the user has not
426 | interacted with the device within the last |detector|.{{[[threshold]]}}
427 | milliseconds, it MUST [=queue a global task=] on the [=relevant global
428 | object=] of |detector| using the [=idle detection task source=] to run the
429 | following steps:
430 |
431 | 1. Set |detector|.{{[[userState]]}} to {{"idle"}}.
432 | 1. [=Fire an event=] named {{"change"}} at |detector|.
433 |
434 |
435 | * If |detector|.{{[[userState]]}} is {{"idle"}} and the user interacts with
436 | the device, it MUST [=queue a global task=] on the [=relevant global
437 | object=] of |detector| using the [=idle detection task source=] to run the
438 | following steps:
439 |
440 | 1. Set |detector|.{{[[userState]]}} to {{"active"}}.
441 | 1. [=Fire an event=] named {{"change"}} at |detector|.
442 |
443 | * If |detector|.{{[[screenState]]}} is {{"unlocked"}} and the screen is
444 | locked, it MUST [=queue a global task=] on the [=relevant global object=] of
445 | |detector| using the [=idle detection task source=] to run the following
446 | steps:
447 |
448 | 1. Set |detector|.{{[[screenState]]}} to {{"locked"}}.
449 | 1. [=Fire an event=] named {{"change"}} at |detector|.
450 |
451 | * If |detector|.{{[[screenState]]}} is {{"locked"}} and the screen is
452 | unlocked, it MUST [=queue a global task=] on the [=relevant global object=]
453 | of |detector| using the [=idle detection task source=] to run the following
454 | steps:
455 |
456 | 1. Set |detector|.{{[[screenState]]}} to {{"unlocked"}}.
457 | 1. [=Fire an event=] named {{"change"}} at |detector|.
458 |
459 |
460 |
461 |
462 | interceptor.https.html
463 | page-visibility.https.html
464 |
465 |
466 | # Security and privacy considerations # {#security-and-privacy}
467 |
468 | *This section is non-normative.*
469 |
470 | ## Cross-origin information leakage ## {#privacy-cross-origin-leakage}
471 |
472 | This interface exposes the state of global system properties and so care must be
473 | taken to prevent them from being used as cross-origin communication or
474 | identification channels. Similar concerns are present in specifications such as
475 | [[DEVICE-ORIENTATION]] and [[GEOLOCATION]], which mitigate them by requiring
476 | a visible or focused context. This prevents multiple origins from observing the
477 | global state at the same time. These mitigations are unfortunately inappropriate
478 | here because the intent of this specification is precisely to allow a limited
479 | form of tracking in blurred and hidden contexts. A malicious page could notify a
480 | tracking server whenever the user is detected as idle or active. If multiple
481 | pages the user was visiting notified the same server it could use the timing of
482 | the events to guess which sessions corresponded to a single user as they would
483 | arrive roughly simultaneously.
484 |
485 | To reduce the number of independent contexts with access to this interface this
486 | specification restricts it to top-level and same-origin contexts. Access can be
487 | delegated to a cross-origin context through [[PERMISSIONS-POLICY]].
488 |
489 | To further reduce the number of contexts this specification requires
490 | a page to obtain the "idle-detection" permission. User agents should inform
491 | the user of the capability that this permission grants and encourage them to
492 | only [=permission/grant=] it to trusted sites which have a legitimate purpose for this data.
493 |
494 | Implementations that provide a "private browsing" mode should not allow this
495 | capability in contexts where this mode is enabled. Implementations should be
496 | careful however to avoid the lack of this capability from being used as a signal
497 | that this mode is enabled. This can be accomplished by refusing to allow the
498 | "idle-detection" permission to be [=permission/granted=] but delaying the automatic
499 | dismissal of the permission request by a random interval so that it appears to
500 | have been a user action.
501 |
502 | ## Behavior tracking ## {#privacy-behavior-tracking}
503 |
504 | While this interface does not provide details of the user interaction which
505 | triggered an {{"idle"}} to {{"active"}} transition, with a sufficiently short
506 | threshold these events could be used to detect behavior such as typing. This
507 | specification therefore restricts the requested threshold to a minimum of at
508 | least 60 seconds.
509 |
510 | The permission requirement described previously also helps to mitigate the
511 | general concern that this interface can be used to build a profile of when and
512 | for how long the user typically interacts with their device.
513 |
514 | ## User coercion ## {#privacy-user-coercion}
515 |
516 | Sites may require the user to [=permission/grant=] them the "idle-detection" [=permission=]
517 | before unlocking some functionality. For example, a testing site could require
518 | this permission as part of an anti-cheating mechanism to detect the user
519 | consulting forbidden reference materials in another window. This type of
520 | "Contract of Adhesion" has been observed with other permissions such as
521 | notifications, FIDO attestation and DRM identifiers.
522 |
523 | A potential mitigation for this concern is to design that interface so that it
524 | is not possible for a site to determine whether the user has
525 | [=permission/granted=] or [=permission/denied=] the permission.
526 | An implementation could refuse to acknowledge that the user is
527 | idle, reducing a site to only the signals currently available. This mitigation
528 | could be detectable as it is unlikely that a user who has not interacted with a
529 | page for hours has nevertheless still been continuously interacting with
530 | something else. Implementations could instead insert fake idle transition events
531 | which correspond to plausible behavior given the other signals available to the
532 | page.
533 |
534 | This specification does not mandate this type of mitigation as it could create a
535 | poor user experience when sites take action based on this false data. For
536 | example, the message application mentioned previously would not deliver
537 | notifications to the user's mobile device because it believes the signals it has
538 | been given indicate that they are still at their desktop. As the site cannot
539 | detect that it is in this state it cannot directly recommend an action for the
540 | user to take to get themselves out of it.
541 |
542 | The harm done by such a site is limited as tracking is only possible while the
543 | user is visiting that page. Tracking across multiple origins requires permission
544 | to be requested on each participating site.
545 |
546 | # Accessibility considerations # {#accessibility}
547 |
548 | *This section is non-normative.*
549 |
550 | Users with physical or cognitive impairments may require more time to interact
551 | with user agents and content. Implementations should not allow distinguishing
552 | such users, or limiting their ability to interact with content any more than
553 | existing observation of UI events. For example, implementation should ensure
554 | that interactions from assistive technologies count towards considering the user
555 | active.
556 |
557 | The use of a permission also requires that user agents provide a user interface
558 | element to support requesting and managing that permission. Any such user
559 | interface elements must be designed with accessibility tools in mind. For
560 | example, a user interface describing the capability being requested should
561 | provide the same description to tools such as screen readers.
562 |
563 | # Internationalization considerations # {#internationalization}
564 |
565 | *This section is non-normative.*
566 |
567 | The interface described by this specification has limited internationalization
568 | considerations, however the use of a permission does require that user agents
569 | provide a user interface element to support requesting and managing that
570 | permission. Any content displayed by the user agent in this context should be
571 | translated into the user's native language.
572 |
573 | # Acknowledgements # {#acknowledgements}
574 |
575 | *This section is non-normative.*
576 |
577 | Many thanks to
578 | Kenneth Christiansen,
579 | Samuel Goto,
580 | Ayu Ishii and
581 | Thomas Steiner
582 | for their help in crafting this proposal.
583 |
--------------------------------------------------------------------------------
/logo-idle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WICG/idle-detection/183730b9a7a73e015866d5296c7e957aafe19463/logo-idle.png
--------------------------------------------------------------------------------
/logo-idle.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/mdn-drafts/QUICK-REFERENCE.md:
--------------------------------------------------------------------------------
1 | ---
2 | recipe: api-interface
3 | title: 'IdleDetector'
4 | mdn_url: /en-US/docs/Web/API/IdleDetector
5 | specifications: https://wicg.github.io/idle-detection/#api-idledetector
6 | browser_compatibility: api.IdleDetector
7 | ---
8 |
9 | **This is a rough draft of content that will eventually live on MDN. When this
10 | feature ships, the content below will live on MDN under
11 | [developer.mozilla.org/en-US/docs/Web/API](https://developer.mozilla.org/en-US/docs/Web/API).**
12 |
13 | ## Description
14 |
15 | The `IdleDetector` interface of the Idle Detection API provides events
16 | indicating when the user is no longer interacting with their device or the
17 | screen has locked.
18 |
19 | This interface requires a secure context.
20 |
21 | ## Constructor
22 |
23 | Creates a new `IdleDetector` object.
24 |
25 | ## Properties
26 |
27 | **`IdleDetector.userState`**
28 |
29 | Returns either `"active"` to indicate that the user has interacted with the
30 | device within the threshold provided to `start()` or `"idle"` if they have not.
31 | This attribute returns `null` before `start()` is called.
32 |
33 | **`IdleDetector.screenState`**
34 |
35 | Returns either `"locked"` if the device's screen is locked or `"unlocked"` if it
36 | is not. This attribute returns `null` before `start()` is called.
37 |
38 | ## Events
39 |
40 | **`IdleDetector.onchange`**
41 |
42 | Called when the value of `userState` or `screenState` has changed. This method
43 | receives an `Event` object.
44 |
45 | ## Methods
46 |
47 | **`IdleDetector.requestPermission()`**
48 |
49 | Returns a `Promise` that resolves when the user has chosen whether or not to
50 | grant the origin access to their idle state. Resolves with `"granted"` on
51 | acceptance and `"denied"` on refusal.
52 |
53 | **`IdleDetector.start()`**
54 |
55 | Returns a `Promise` that resolves when the detector has started listening for
56 | changes in the user's idle state. `userState` and `screenState` are populated
57 | with their initial values. Takes an optional options object with the
58 | `threshold` in milliseconds where inactivity should be reported and `signal`
59 | for an `AbortSignal` to abort the idle detector.
60 |
61 | ## Examples
62 |
63 | The following example shows creating a detector and logging changes to the
64 | user's idle state. A button is used to get the necessary user activation before
65 | requesting permission.
66 |
67 | ```js
68 | const controller = new AbortController();
69 | const signal = controller.signal;
70 |
71 | startButton.addEventListener('click', async () => {
72 | if (await IdleDetector.requestPermission() != "granted") {
73 | console.error("Idle detection permission denied.");
74 | return;
75 | }
76 |
77 | try {
78 | const idleDetector = new IdleDetector();
79 | idleDetector.addEventListener('change', () => {
80 | const userState = idleDetector.userState;
81 | const screenState = idleDetector.screenState;
82 | console.log(`Idle change: ${userState}, ${screenState}.`);
83 | });
84 |
85 | await idleDetector.start({
86 | threshold: 60_000,
87 | signal,
88 | });
89 | console.log('IdleDetector is active.');
90 | } catch (err) {
91 | // Deal with initialization errors like permission denied,
92 | // running outside of top-level frame, etc.
93 | console.error(err.name, err.message);
94 | }
95 | });
96 |
97 | stopButton.addEventListener('click', () => {
98 | controller.abort();
99 | console.log('IdleDetector is stopped.');
100 | });
101 | ```
102 |
--------------------------------------------------------------------------------
/security-privacy-self-assessment.md:
--------------------------------------------------------------------------------
1 | https://www.w3.org/TR/security-privacy-questionnaire/
2 |
3 | ### 3.1 Does this specification deal with personally-identifiable information?
4 |
5 | No.
6 |
7 | ### 3.2 Does this specification deal with high-value data?
8 |
9 | No.
10 |
11 | ### 3.3 Does this specification introduce new state for an origin that persists across browsing sessions?
12 |
13 | No.
14 |
15 | ### 3.4 Does this specification expose persistent, cross-origin state to the web?
16 |
17 | As not all device types may support a "lock" state, detecting such a state provides some additional distinguishing information about the user's device (i.e. potentially one bit of entropy for fingerprinting), but as this correlates with the native platform this is generally inferrable from information exposed by the user agent header already.
18 |
19 | ### 3.5 Does this specification expose any other data to an origin that it doesn’t currently have access to?
20 |
21 | Yes - the status of a "screen lock" or equivalent is not detectable by script today - other than e.g. [Wake Lock](https://w3c.github.io/wake-lock/) to detect the absence.
22 |
23 | Detection of "idle" vs. "active" can be done by script today by watching for UI events, but this is restricted to events within windows/frames controlled by the origin.
24 |
25 | The "idle" state can be described as "time since last user interface event" and is global state which, with this API, can be observed cross-origin. In one hypothetical attack, with sub-second detection it would be possible to infer keystrokes and thus guess passwords being entered in other windows. For this reason, idle time detection must be appropriately coarse. In another attack scenario different origins could collaborate to corrolate idle state change events on the back-end, allowing identification of a user session across origins. For this reason, this capability must be limited to a small set of trustworthy origins by limiting it to top-level frames with notification permission.
26 |
27 | ### 3.6 Does this specification enable new script execution/loading mechanisms?
28 |
29 | No.
30 |
31 | ### 3.7 Does this specification allow an origin access to a user’s location?
32 |
33 | No.
34 |
35 | ### 3.8 Does this specification allow an origin access to sensors on a user’s device?
36 |
37 | Not directly. A device may use sensors to control lock state (e.g. proximity sensor to lock, fingerprint sensor to unlock) but the sensor data itself is not exposed.
38 |
39 | ### 3.9 Does this specification allow an origin access to aspects of a user’s local computing environment?
40 |
41 | See the answer to 3.5 above. The user's idle state is an aspect of their local computing environment which extends beyond the boundaries of a single site.
42 |
43 | ### 3.10 Does this specification allow an origin access to other devices?
44 |
45 | No.
46 |
47 | ### 3.11 Does this specification allow an origin some measure of control over a user agent’s native UI?
48 |
49 | No.
50 |
51 | ### 3.12 Does this specification expose temporary identifiers to the web?
52 |
53 | No.
54 |
55 | ### 3.13 Does this specification distinguish between behavior in first-party and third-party contexts?
56 |
57 | This capability is not allowed in third-party contexts.
58 |
59 | ### 3.14 How should this specification work in the context of a user agent’s "incognito" mode?
60 |
61 | This capability should be disabled in "incognito" modes to avoid exposing the same global state to two content inside and outside of "incognito" mode simultaneously.
62 |
63 | ### 3.15 Does this specification persist data to a user’s local device?
64 |
65 | No.
66 |
67 | ### 3.16 Does this specification have a "Security Considerations" and "Privacy Considerations" section?
68 |
69 | _Not yet!_
70 |
71 | **TODO: Make sure this is included when the spec is written.**
72 |
73 | ### 3.17 Does this specification allow downgrading default security characteristics?
74 |
75 | No.
76 |
--------------------------------------------------------------------------------
/w3c.json:
--------------------------------------------------------------------------------
1 | {
2 | "group": [80485]
3 | , "contacts": ["cwilso"]
4 | , "repo-type": "cg-report"
5 | }
6 |
--------------------------------------------------------------------------------