Require user gestures for push notifications

RESOLVED FIXED in Firefox 67

Status

()

enhancement
P2
normal
RESOLVED FIXED
6 months ago
13 days ago

People

(Reporter: Ehsan, Assigned: johannh)

Tracking

(Blocks 1 bug, {dev-doc-complete})

unspecified
mozilla68
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(firefox67 fixed, firefox68 fixed)

Details

Attachments

(5 attachments, 1 obsolete attachment)

Push notifications have become extremely annoying for users on the web these days. Websites requesting push notifications immediately upon loading has become a prevalent pattern. Safari 12.1 started to require user gestures for requesting push notifications, which mitigates this painful issue to some extent. I think we should follow by doing something similar.

I spoke with Cindy about doing this as part of the overall annoyance mitigation work. It seemed like this, along with the geolocation prompt, were great candidates for this.

As Martin said, this is something that we've been planning to do for quite some time. However, as always, the overall situation is a little more complex than the headline might suggest and this project definitely needs someone to own it and push it forward.

I'd like to provide a bit of background to this. The main complication is, of course, web compat. Currently, not even a single percent of websites on beta are requesting the desktop-notification permission with user gesture (https://mzl.la/2TzqOIc). If our measurements are correct, that's a breakage rate of 99%, which, as I understand, would be an unprecedented amount of breakage.

I would really like to do this, however, and push forward on restricting other highly used permission prompts as well. I added the telemetry years ago in preparation/anticipation of this change (and telemetry on HTTPS/third party checks as well).

We had some conversations about this in Orlando, and we came up with a few suggestions:

  • When blocking permission requests, we should give users a subtle UI hint that we've done so, and provide them with an option to revert their decision.

  • To that extent, we were planning to work out some amendment to the Permissions API that e.g. provides an event to let websites know when it is allowed to prompt users for permission again.

  • Thirdly (and maybe most crucially), we have really good Telemetry on a) permission request rate and b) user interaction on doorhangers (https://mzl.la/2Bi57VI). I'm confident that our goal in this work comes down to increasing the percentage of users who reply "Allow" to a prompt (which means it appeared in the right context) while keeping the total number of prompts high (thus allowing a large group of developers to use the API in a good manner). Both are easily measurable.
    To this extent, we could develop a shield study that flips prefs to enable a number of restrictions on permission prompts (such as user gesture, storageAccessAPI permission, etc.) and measure which strikes the best (or maybe an appropriate) balance.

Again, this all would take quite a bit of time and someone to drive it. I was trying to get some resourcing on this, and some additional help might allow us to move even faster.

With that said, if someone can come to the decision that we should "just do it" as Safari has done, I'm happy to be part of that. Given the potential breakage this decision could be quite impactful to Firefox as a project and the Mozilla Corporation strategy, so I believe it may be something for the FTLM (https://wiki.mozilla.org/Modules/Firefox_Technical_Leadership)

Thoughts?

(In reply to Johann Hofmann [:johannh] from comment #2)

As Martin said, this is something that we've been planning to do for quite some time. However, as always, the overall situation is a little more complex than the headline might suggest and this project definitely needs someone to own it and push it forward.

I'd like to provide a bit of background to this. The main complication is, of course, web compat. Currently, not even a single percent of websites on beta are requesting the desktop-notification permission with user gesture (https://mzl.la/2TzqOIc). If our measurements are correct

Hmm, they aren't, but probably not in a way that matters here:

StorageAccessPermissionRequest always passes in false: https://searchfox.org/mozilla-central/rev/152993fa346c8fd9296e4cd6622234a664f53341/dom/base/StorageAccessPermissionRequest.cpp#24

MIDIPermissionRequest always passes in true: https://searchfox.org/mozilla-central/rev/152993fa346c8fd9296e4cd6622234a664f53341/dom/midi/MIDIPermissionRequest.cpp#31

We should probably make ContentPermissionRequestBase() not accept a boolean argument for this and call EventStateManager::IsHandlingUserInput() itself to prevent future mistakes of this type. (It is not clear from Gecko what this boolean ends up being used for...)

, that's a breakage rate of 99%, which, as I understand, would be an unprecedented amount of breakage.

This data looks pretty sad for our users more so than for web developers, since that shows that users receive most of our permission prompts probably without having interacted with the page. :-(

Do we have data on which percentage of notification prompts users say "Allow" to by any chance?

I would really like to do this, however, and push forward on restricting other highly used permission prompts as well. I added the telemetry years ago in preparation/anticipation of this change (and telemetry on HTTPS/third party checks as well).

We had some conversations about this in Orlando, and we came up with a few suggestions:

  • When blocking permission requests, we should give users a subtle UI hint that we've done so, and provide them with an option to revert their decision.

  • To that extent, we were planning to work out some amendment to the Permissions API that e.g. provides an event to let websites know when it is allowed to prompt users for permission again.

  • Thirdly (and maybe most crucially), we have really good Telemetry on a) permission request rate and b) user interaction on doorhangers (https://mzl.la/2TzqOIc).

Wrong link (same as the previous one...)?

I'm confident that our goal in this work comes down to increasing the percentage of users who reply "Allow" to a prompt (which means it appeared in the right context) while keeping the total number of prompts high (thus allowing a large group of developers to use the API in a good manner). Both are easily measurable.
To this extent, we could develop a shield study that flips prefs to enable a number of restrictions on permission prompts (such as user gesture, storageAccessAPI permission, etc.) and measure which strikes the best (or maybe an appropriate) balance.

Again, this all would take quite a bit of time and someone to drive it. I was trying to get some resourcing on this, and some additional help might allow us to move even faster.

Overall sounds good.

But I'm curious, why do you think our overall goal should be to increase the percentage of users who reply "Allow" to a prompt? That might convert the project from an annoyance mitigation project (remove the possibility of websites showing permission prompts in scenarios where users will definitely say "Deny" or will ignore the prompt) into a monumentally difficult project with vastly different goals. For example, consider randomjunknews.example/you-clicked-on-this-link-by-accident.html. If while searching for something I come across that page, it can currently show me a notification prompt on load. If we made these prompts require a user gesture it might register a click handler on the body or some such, and if I clicked accidentally somewhere on the page while rushing to hit Back, it can quickly show me the same notification. In both cases my interest as a user is aligned against the interests of the web developer in that I probably never want to receive any messages from the site. Why should we pick a success metric that may be misaligned with the interests of our users?

With that said, if someone can come to the decision that we should "just do it" as Safari has done, I'm happy to be part of that. Given the potential breakage this decision could be quite impactful to Firefox as a project and the Mozilla Corporation strategy, so I believe it may be something for the FTLM (https://wiki.mozilla.org/Modules/Firefox_Technical_Leadership)

In the past when moving the geolocation API to secure contexts we've been willing to break ~20% of active call sites https://groups.google.com/d/msg/mozilla.dev.platform/BvcsTpAqIsQ/PjXqf3u3BgAJ. Part of the argument for doing so at the time was that sites that would be broken in Firefox as a result were broken in Chrome and Safari already.

Going forward, I guess over 99% of sites which use notification prompts will be broken in Safari. Although I think the case of the geolocation API is quite different than the notification API, since in the former case chances are that the site may be using the user's location to do something with on the page, but in the latter case users will probably see the result of the breakage later if they continue to use the website and actually want to receive notifications from it. If we have some data on the percentage of users who currently respond "Allow" to these prompts it may be possible to say with more confidence whether they would consider the resulting behaviour as breakage per se.

It would also be interesting to see what Chrome's stance on this issue is.

Thanks for the reply, I'll reply in more detail later, just wanted acknowledge the wrong link about popup acceptance stats:

The correct link should be https://mzl.la/2Bi57VI (TMO has this bug where it doesn't update the short url when you switch histograms). I'll edit my above comment.

"1" here is "Accept", while "2" is "Deny"

You can see the immense difference in these stats between web-notifications and webRTC-shareDevices.

(In reply to Johann Hofmann [:johannh] from comment #4)

Thanks for the reply, I'll reply in more detail later, just wanted acknowledge the wrong link about popup acceptance stats:

The correct link should be https://mzl.la/2Bi57VI (TMO has this bug where it doesn't update the short url when you switch histograms). I'll edit my above comment.

"1" here is "Accept", while "2" is "Deny"

You can see the immense difference in these stats between web-notifications and webRTC-shareDevices.

Wow! This indeed matches my anecdotal experience in how many of these prompts I say "Allow" to myself...

See Also: → 1525054
See Also: → 1525057

why do you think our overall goal should be to increase the percentage of users who reply "Allow" to a prompt?

I think that the recognition here is that 1% accept rate is indicative of abuse. A higher value (though not 100%, certainly) would indicate that perhaps notifications were being requested responsibly. For instance, I hold Slack up as an exemplar in this narrow way, they provide context in an unobtrusive way that I bet gets them pretty good acceptance rates once the prompt is shown.

For the rest, I suspect that this is scattershot in the same way that spam is. Ask enough times and you get some acceptances. And it is probably the case that any acceptance is more valuable than none, because the cost to the site is very low. Note that the value is increased with push, especially if you consider the ability to track over time </cynic>.

Probably needs mentioning in the docs.

Keywords: dev-doc-needed

+100 to this… when we did our doorhanger re-design to make them not dismiss by clicking outside I fought UX for months to do this and finally gave up… Hopefully it's clear to more people now that it was a mistake to make doorhangers more intrusive.

Back then I suggested a middle-ground for web compat. which is to still show the doorhanger icon, just not open the panel by default (dismissed:true in the PopupNotifications API), when there was no user interaction. I realize that most users aren't going to see the icon in the address bar but it's better than not having any way to enable a permission for a site for the users who do find it. If we find all the icons there are distracting we could eventually phase it out… hopefully some sites would have adjusted to providing a button to request permission by then. This would still be a great improvement over what we have today.

(In reply to Matthew N. [:MattN] (PM me if requests are blocking you) from comment #8)

+100 to this… when we did our doorhanger re-design to make them not dismiss by clicking outside I fought UX for months to do this and finally gave up… Hopefully it's clear to more people now that it was a mistake to make doorhangers more intrusive.

Back then I suggested a middle-ground for web compat. which is to still show the doorhanger icon, just not open the panel by default (dismissed:true in the PopupNotifications API), when there was no user interaction. I realize that most users aren't going to see the icon in the address bar but it's better than not having any way to enable a permission for a site for the users who do find it. If we find all the icons there are distracting we could eventually phase it out… hopefully some sites would have adjusted to providing a button to request permission by then. This would still be a great improvement over what we have today.

We've thought about doing this for a while, but the big problem is that the request APIs will give no indication that the user got the "degraded" experience and only saw the little icon in the identity block. The Promise will simply be left dangling forever. I'd say outright rejecting and then allowing websites to notice and recover sounds like a better plan, but that's also much more complicated.

With that said I think we always agreed that back then we made the doorhangers way too annoying, it's a long story.

Oh, true, on APIs where we are rejecting then that's not as bad though it assumes the website actually has UI that allows a user interaction to prompt. My solution works with existing sites that may not even have a button to click and assumes the onload prompt will work.

Of course there is also the middle ground where our doorhanger can grant permission for the future and not worry about any promise for the initial request. That actually makes a lot of sense for push notifications where the result isn't something that appears on the webpage you're viewing (unlike geolocation). i.e. we could still have a dismised doorhanger to grant the permanent permission in storage even if we deny the site's request (e.g. reject a request promise).

(In reply to Matthew N. [:MattN] (PM me if requests are blocking you) from comment #11)

Oh, true, on APIs where we are rejecting then that's not as bad though it assumes the website actually has UI that allows a user interaction to prompt. My solution works with existing sites that may not even have a button to click and assumes the onload prompt will work.

Of course there is also the middle ground where our doorhanger can grant permission for the future and not worry about any promise for the initial request. That actually makes a lot of sense for push notifications where the result isn't something that appears on the webpage you're viewing (unlike geolocation). i.e. we could still have a dismised doorhanger to grant the permanent permission in storage even if we deny the site's request (e.g. reject a request promise).

I think that's where I'd like to get to, plus amending the Permissions API to include a simple EventTarget that emits an event when the user made up their mind about a permission. Implementing that would probably not block the other interventions, though...

(In reply to Johann Hofmann [:johannh] from comment #12)

(In reply to Matthew N. [:MattN] (PM me if requests are blocking you) from comment #11)

Oh, true, on APIs where we are rejecting then that's not as bad though it assumes the website actually has UI that allows a user interaction to prompt. My solution works with existing sites that may not even have a button to click and assumes the onload prompt will work.

One bad anti-pattern I've seen on some sites is dimming the entire viewport using an overlay with an arrow pointing to where the doorhanger prompt would be (presumably in an LTR UI!) waiting for the user to grant the permission before removing the overlay and allowing the content on the page to even be viewed. So sometimes the website has the opposite UI: UI for ensuring that the user can't interact with the page before they answer the right way to our impossible-to-dismiss prompt.

Of course there is also the middle ground where our doorhanger can grant permission for the future and not worry about any promise for the initial request. That actually makes a lot of sense for push notifications where the result isn't something that appears on the webpage you're viewing (unlike geolocation). i.e. we could still have a dismised doorhanger to grant the permanent permission in storage even if we deny the site's request (e.g. reject a request promise).

Are you thinking of this middle ground with our current door hanger design which forces the user into making a decision (through making it impossible to dismiss the doorhanger by clicking it outside)?

I think that's where I'd like to get to, plus amending the Permissions API to include a simple EventTarget that emits an event when the user made up their mind about a permission. Implementing that would probably not block the other interventions, though...

Out of curiosity why not send that event no the Notification object itself? It is an EventTarget already. If you send it to the Permissions object you'd need to pick which object you want to send it to (e.g. do you send it to the Permissions object exposed to the Window context or the Worker context or both?)

(In reply to :Ehsan Akhgari from comment #13)

(In reply to Johann Hofmann [:johannh] from comment #12)

(In reply to Matthew N. [:MattN] (PM me if requests are blocking you) from comment #11)

Of course there is also the middle ground where our doorhanger can grant permission for the future and not worry about any promise for the initial request. That actually makes a lot of sense for push notifications where the result isn't something that appears on the webpage you're viewing (unlike geolocation). i.e. we could still have a dismised doorhanger to grant the permanent permission in storage even if we deny the site's request (e.g. reject a request promise).

Are you thinking of this middle ground with our current door hanger design which forces the user into making a decision (through making it impossible to dismiss the doorhanger by clicking it outside)?

Yes, since my proposal doesn't involve showing the doorhanger panel without user interaction. I'll explain better: What I meant was that we could deny by default if there is no user interaction (website gets the deny response) and still show the doorhanger icon with no panel ("dismissed by default" via dismissed:true). If the user wants to allow notifications they can click on the doorhanger anchor icon which opens the panel and then grant the permanent permission (allow or deny). If they allow it then websites listening for the "change" event of the permission could immediately register for push, otherwise, on the next page load that that site tries to request push they will be subscribed. It's not perfect if the site doesn't try to subscribe again (I'll admit I haven't brushed up on the notification APIs) as the subscription would never happen but it's better than not providing any UI in this case.

This could help for cases where there was a user interaction (therefore the user may be expecting a prompt) but perhaps the website uses async methods to request permission after the user interaction (bug 1496656) or the site uses postMessage after a user interaction to do the request (bug 1447178).

Anyways, just some ideas to reduce the web compat. (though admittedly not in a large way). I'm just trying to help give ideas so this general idea can move forward.

To add to comment 14, I think that we want to show desktop-notification-blocked.svg (or equivalent). :jib mentioned that we use the icon to indicate active use, but this is a case where we have chosen to block access.

Q: What happens if we block, then get another request that is after a user interaction? My sense is that we have a temporarily blocked situation and we continue to respect that. That is, abuse results in punishment.

(In reply to Matthew N. [:MattN] (PM me if requests are blocking you) from comment #14)

(In reply to :Ehsan Akhgari from comment #13)

(In reply to Johann Hofmann [:johannh] from comment #12)

(In reply to Matthew N. [:MattN] (PM me if requests are blocking you) from comment #11)

Of course there is also the middle ground where our doorhanger can grant permission for the future and not worry about any promise for the initial request. That actually makes a lot of sense for push notifications where the result isn't something that appears on the webpage you're viewing (unlike geolocation). i.e. we could still have a dismised doorhanger to grant the permanent permission in storage even if we deny the site's request (e.g. reject a request promise).

Are you thinking of this middle ground with our current door hanger design which forces the user into making a decision (through making it impossible to dismiss the doorhanger by clicking it outside)?

Yes, since my proposal doesn't involve showing the doorhanger panel without user interaction. I'll explain better: What I meant was that we could deny by default if there is no user interaction (website gets the deny response) and still show the doorhanger icon with no panel ("dismissed by default" via dismissed:true). If the user wants to allow notifications they can click on the doorhanger anchor icon which opens the panel and then grant the permanent permission (allow or deny). If they allow it then websites listening for the "change" event of the permission could immediately register for push, otherwise, on the next page load that that site tries to request push they will be subscribed. It's not perfect if the site doesn't try to subscribe again (I'll admit I haven't brushed up on the notification APIs) as the subscription would never happen but it's better than not providing any UI in this case.

Ah I see. This has some of the properties of the idea I suggested in bug 1375683 comment 12, so I like it.

I suspect (but have no data to prove) that as we have kept adding more icons next to the padlock when random things happen, users will sooner or later start to ignore that area as they become unable to understand what those icons mean (I am personally near that point myself these days!) so I think your idea may end up helping the "harass users less" cause more than "give webdevs more allow responses" cause. That is a fine outcome by me personally, since I think the model we want to encourage is for webdevs to start requesting notification access in context, and part of that is of course when having had user interaction.

This could help for cases where there was a user interaction (therefore the user may be expecting a prompt) but perhaps the website uses async methods to request permission after the user interaction (bug 1496656) or the site uses postMessage after a user interaction to do the request (bug 1447178).

Ah this reminds me... We probably want to pass ePropagateUserInteraction as the third argument to Promise::Create() here: https://searchfox.org/mozilla-central/rev/cb7faaf6b4ad2528390186f1ce64618dea71031e/dom/notification/Notification.cpp#1547 to ensure the Promise returned from requestPermission() will also maintain the user activation flag through its resolve/reject handler.

(In reply to Martin Thomson [:mt:] from comment #15)

Q: What happens if we block, then get another request that is after a user interaction? My sense is that we have a temporarily blocked situation and we continue to respect that. That is, abuse results in punishment.

Yes, I believe that is what we get through the TemporaryPermissions handling by default.

Active discussion seems to warrant a P2 here.

Priority: -- → P2
Assignee: nobody → jhofmann
Status: NEW → ASSIGNED
Blocks: 1534456

Do you mind sending an intent to implement to dev-platform please? Thanks!

Attachment #9051237 - Attachment description: Bug 1524619 - Require user gestures for push notifications. r=Ehsan,MattN → Bug 1524619 - Part 1 - Add support for requiring user gestures for push notifications. r=Ehsan,MattN
Attachment #9051238 - Attachment description: Bug 1524619 - Support requiring user gestures for push notifications on Fennec. r=snorp → Bug 1524619 - Part 3 - Support requiring user gestures for push notifications on Fennec. r=snorp

This is done to support requiring user interaction when calling PushManager.subscribe().
Because PushManager must usually be accessed with async APIs, this makes for a better
developer experience and should reduce breakage.

Argh, phabricator/hg made a total mess of this, landing manually.

Attachment #9052387 - Attachment is obsolete: true
https://hg.mozilla.org/integration/mozilla-inbound/rev/3926b4caa17b2de3cff8754d97a689c0aa15bc4d
Bug 1524619 - Part 1 - Add support for requiring user gestures for push notifications. r=Ehsan,MattN

https://hg.mozilla.org/integration/mozilla-inbound/rev/f0c0208fb146fb3fefaf2312baa42ff300d82cb6
Bug 1524619 - Part 2 - Add tests for notification permission prompts with user interaction. r=Ehsan,lina

https://hg.mozilla.org/integration/mozilla-inbound/rev/7980ec2cfbd7aca4c9b2259c72343f4ee6d736d6
Bug 1524619 - Part 3 - Support requiring user gestures for push notifications on Fennec. r=snorp

https://hg.mozilla.org/integration/mozilla-inbound/rev/a20b1b76ad7895a042af9c00702dfaddd9f09445
Bug 1524619 - Part 4 - Set user interaction flag in push notification permission requests. r=lina

https://hg.mozilla.org/integration/mozilla-inbound/rev/87c1a38234f515024a7930f6c7b24908a5e9776b
Bug 1524619 - Part 5 - Propagate user interaction through APIs that return ServiceWorkerRegistrations. r=Ehsan

Comment on attachment 9051237 [details]
Bug 1524619 - Part 1 - Add support for requiring user gestures for push notifications. r=Ehsan,MattN

Beta/Release Uplift Approval Request

  • User impact if declined: Needed for uplifting bug 1536454
  • Is this code covered by automated tests?: Yes
  • Has the fix been verified in Nightly?: No
  • Needs manual test from QE?: No
  • If yes, steps to reproduce:
  • List of other uplifts needed: None
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): Well tested, long baked on Nightly, preffed off by default
  • String changes made/needed: None
Attachment #9051237 - Flags: approval-mozilla-beta?
Attachment #9051238 - Flags: approval-mozilla-beta?
Attachment #9051870 - Flags: approval-mozilla-beta?
Attachment #9051871 - Flags: approval-mozilla-beta?
Attachment #9051872 - Flags: approval-mozilla-beta?

Comment on attachment 9051237 [details]
Bug 1524619 - Part 1 - Add support for requiring user gestures for push notifications. r=Ehsan,MattN

Uplift approved in 67 beta 14 for the same reasons as bug 1536454, thanks.

Attachment #9051237 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Attachment #9051238 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Attachment #9051870 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Attachment #9051871 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Attachment #9051872 - Flags: approval-mozilla-beta? → approval-mozilla-beta+

In the future when changes get requested for uplift which contain string changes, request feedback from :flod to get them approved. Part 1 changes dom.properties. See the "mozilla-beta" at https://wiki.mozilla.org/Tree_Rules#mozilla-beta

Ah, my bad, sorry, I know about this but didn't consider that there's a string for the console warning. FWIW, this will not ever be exposed, so it doesn't matter if it's translated or not.

Apologies!

Documentation updates:

  • Added a section to the article "Web Push API Notifications best practices" with information on browser mitigation of abuse; this change is mentioned there.
  • Added the same information to the "Using the Notifications API" page
  • Mentioned on Firefox 68 for developers

(In reply to Eric Shepherd [:sheppy] from comment #36)

Documentation updates:

  • Added a section to the article "Web Push API Notifications best practices" with information on browser mitigation of abuse; this change is mentioned there.
  • Added the same information to the "Using the Notifications API" page
  • Mentioned on Firefox 68 for developers

This bug only added support for requiring a user gesture for requesting push notifications, and didn't enable it by default. So the documentation here was a mistake. In fact we probably shouldn't have marked this as dev-doc-needed in the first place.

Eric, any chance you could please revert these recent edits? I couldn't figure out how to revert revisions on the wiki software on MDN... Thanks!

Sorry I didn't catch this in time.

Flags: needinfo?(eshepherd)

Yeah sorry for not following up to this earlier, this kinda went under the radar during the all hands for me...

So, ideally this would actually have been dev-doc-needed BUT would have had some form of really explicit note to the docs team that this is behind a preference. In a perfect world, I'd have caught this myself anyway, but it would be best to have had it pointed out clearly. We do document these things, but on a special "Experimental features" page, which I've now in fact done:

https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Experimental_features

I've also reverted the other changes. Dan Callahan beat me to removing this From Firefox 68 for developers..

Flags: needinfo?(eshepherd)
You need to log in before you can comment on or make changes to this bug.