Answer to the core questions
1. Tag replacement on Safari iOS – Safari follows the standard and replaces an existing visible notification with the same tag. Only one banner appears in the lock screen or Notification Center, and its body/title update to the newest payload.
2. Effect of requireInteraction on a tagged notification – The notification remains until the user taps it or the page calls close(). If the user dismisses it (by swiping or tapping “X” on the expanded view), the replacement rule still applies: a new notification with the same tag will replace the dismissed one, resetting the interaction requirement.
3. Permission timing guidance – Request Notification.requestPermission() only after a user gesture that explicitly indicates intent to receive alerts (e.g., clicking a “Subscribe” button). Pre‑emptive requests (e.g., on page load) are often denied or ignored, especially on Safari iOS where the prompt is tied to the gesture.
Why the behavior is consistent across browsers
The Notifications API spec mandates tag replacement for visible notifications. Chrome, Firefox, Edge, and Safari (iOS) all implement this rule. The only nuance is the visual delay Safari iOS can introduce when the Notification Center is not actively open.
Practical suppression pattern
Maintain an in‑memory map of alertId → tag. Before showing a new alert:
- Generate a tag (e.g.,
"order‑1234‑status") based on the alert’s semantic group.
- Call
new Notification(title, { body, icon, tag, requireInteraction }). If a notification with that tag already exists, the browser replaces it.
- Optionally, after display, call
registration.getNotifications({ tag }) to confirm only one instance remains.
Permission‑state considerations
- Granted – Show notifications immediately.
- Denied – Show an in‑page fallback and offer a link to browser settings.
- Default – Show a prompt only after a user gesture; if the user declines, remember the choice and avoid repeated prompts.
What to test on a real device
- Push two tagged notifications with different
requireInteraction values and verify that the second replaces the first.
- Dismiss the first in Safari iOS and confirm that a new tagged notification still replaces it.
- Trigger
Notification.requestPermission() on page load vs. after a button click and record the resulting state.
Missing diagnostic detail
To fine‑tune the requireInteraction policy, could you share whether the alerts you need to suppress are high‑severity (e.g., security) or low‑severity (e.g., marketing)? This will influence whether you keep requireInteraction true for all alerts or only for a subset.