Behaviour · Measured 2026-10-20, iPhone 16 Pro, iOS 18.6.2 (22G100) · A, Instrumented read · Differs from BCD
The notificationclick event reached both service worker handlers on 6 of 6 taps in a Home Screen
web app on an iPhone 16 Pro running iOS 18.6.2 (22G100), tested on 2026-10-20.
Browser-compat-data (BCD) lists the event as unsupported on Safari for iOS.
In a Home Screen web app on iOS, does a service worker’s notificationclick handler run when the
user taps a notification that the worker showed, through both
addEventListener('notificationclick', …) and the self.onnotificationclick property, and can the
handler bring the app’s window to the front?
The test app is the Device Lab harness (v1) added to the Home Screen from Safari as “PWA Lab”. Its
service worker (lab-sw-v2, scope /lab/device-tests/) installs two handlers: one with
addEventListener and one assigned to self.onnotificationclick. Each handler writes a timestamped record
to IndexedDB. Its via field names the handler path. Neither calls
event.preventDefault(). Only the listener navigates: it calls
clients.matchAll({type: "window", includeUncontrolled: true}), calls focus() on a lab window if
one is found, and otherwise calls clients.openWindow(); the outcome is stored with the record.
Button 2a calls registration.showNotification() from the page at once. Button 2b posts a
message to the worker, which waits 5 s and then calls self.registration.showNotification() (see
lab.js and sw.js). Tap 4 used button 2a; the other five used 2b. No push message was sent: the harness has no push
server. Notification permission had been granted in the app beforehand (notebook N32).
We tested five tap conditions in the Home Screen app:
- a banner tapped on the Home Screen;
- a banner tapped while the app was in front;
- a notification tapped in Notification Centre;
- a banner tapped after the app was swiped away and relaunched;
- a banner tapped after the app was swiped away in the app switcher, to try to reach the
clients.openWindow() path.
Each record holds a createdAt time, set when the page built the notification options (for 2b,
before the 5 s wait), and an at time, set when the handler started building its record (before
navigation and the IndexedDB write). The listener record also holds how many windows
clients.matchAll() returned and the navigation outcome. An AI agent session read the accumulated
records from the app page over USB through the WebKit remote inspector four times, after taps 3, 4,
5 and 6 (N35, N36, N38, N40); each read also showed whether any notificationclose record existed.
The steps need an iPhone and about ten minutes; Web Inspector is optional, because the harness page
prints its own event log.
- In Safari on the iPhone, open
https://openpwa.net/lab/device-tests/, tap Share, then
Add to Home Screen, then Add.
- Launch PWA Lab from its icon. In “T7 and T8: notifications”, tap 1. Request permission
and answer Allow on the system prompt.
- Tap 2b. Show in 5 s (then go Home) and go to the Home Screen at once. When the banner
appears, tap it.
- In the app, read the event log. A tap that reaches both paths adds one record marked
addEventListener and one marked onnotificationclick property, and the listener record names
its navigation outcome.
- Tap 2a. Show notification now, stay in the app, pull down Notification Centre and tap the
notification there.
- Close the app in the app switcher, launch it again from its icon and repeat step 3.
- For the no-window path, tap 2b, swipe the app away in the app switcher at once, then tap the
banner. An outcome of “opened new window” means
clients.openWindow() ran; “focused existing
window” means a page was still alive.
- Tap Copy results as JSON to keep the records. The JSON holds the read time (
collectedAt) and the user agent but no device model or OS build, so write those down from Settings > General > About.
- T8 notificationclick: exposure, handlers and a notification tap (5 min)
Harness v1: Open the test
On iOS 18.6.2 (22G100) both handler paths ran on 6 of 6 taps, which produced twelve records, two per
tap (Instrumented read, A; notebook N35, N36, N38, N40). On every tap clients.matchAll() returned
one window and focus() on it succeeded. No notificationclose record was produced. A banner was
also shown while the app was in front (Screenshot or recording, S; N63).
| Tap |
Condition |
createdAt |
Listener at |
Property at |
Notebook |
| 1 |
banner, Home Screen |
08:22:57.000 |
08:23:07.007 |
08:23:07.008 |
N35 |
| 2 |
banner over the app in front |
08:23:21.253 |
08:23:30.533 |
08:23:30.534 |
N35, N63 |
| 3 |
banner over the Home Screen |
08:24:38.479 |
08:24:46.071 |
08:24:46.072 |
N35, N63 |
| 4 |
Notification Centre |
08:26:28.601 |
08:26:49.588 |
08:26:49.588 |
N36 |
| 5 |
after swipe-away and relaunch |
08:28:40.822 |
08:28:50.048 |
08:28:50.061 |
N38 |
| 6 |
app swiped away before the tap |
08:43:03.022 |
08:43:09.236 |
08:43:09.245 |
N40 |
Times are UTC on 2026-10-20. The interval from createdAt to at includes the operator’s reaction
and, for the 2b taps (all but tap 4), the 5 s wait, so it is not a dispatch latency. Every tap had a live window: in tap 6 the document
loaded at the previous relaunch was still alive about 6 s after the swipe-away and was focused
(N40). The clients.openWindow() path was therefore not reached, and this method records it as
could-not-run.
2026-10-20, iOS 18.6.2
In the PWA Lab Home Screen app notificationclick fired through both addEventListener and self.onnotificationclick on 6 of 6 taps (banner, Notification Centre, after a relaunch, after a swipe-away), and focus() on the existing window succeeded each time. The clients.openWindow() path was not reached.
- Date
- 2026-10-20
- Device
- iPhone 16 Pro
- OS and build
- iOS 18.6.2 (22G100), release
- Context
- Home Screen app
- Result
- Differs from the expectation
- Key values
taps: 6addEventListenerRecords: 6onnotificationclickPropertyRecords: 6focusedExistingWindow: 6notificationcloseRecords: 0openWindowPath: not reached
- Confidence
- A, Instrumented read
- Tests
- T8
- Notebook entries
- N35, N36, N38, N40
- Study
- Read the study · Data package
- Harness
- Harness v1
Harness v1 files used (3), served SHA-256
/lab/device-tests/ 42c90845419f5ed3ad15d941bea04f649f4c5d350b1847292292fadd55871486/lab/device-tests/manifest.webmanifest cab4e60719fd1f9c84d04aada2ad6cd937f50615ce646c3ed20f14f0ca09832b/lab/device-tests/sw.js 0e7e6f34cb814d808edba644d664bac0f4337cc59a88dbb509d25a8e11fffc30
BCD records api.ServiceWorkerGlobalScope.notificationclick_event for safari_ios as
version_added: false (ServiceWorkerGlobalScope.json,
github.com, read 2026-10-20). The measurement differs from that cell. In
mdn/browser-compat-data#22959
(github.com), opened 2024-04-29 and open on 2026-10-20, a BCD contributor explains that the
collector evaluates "onnotificationclick" in self in a service worker and that the check fails on
Safari for iOS 16, 17 and 18. The collector’s worker is controlled by a Safari tab. In that context
the property is absent on 18.6.2, and a tab has no Notification interface, so it cannot show a
notification to click (see
worker event handler exposure). The cell
is correct for the context it was measured in and generalises it to all of Safari on iOS. The same
BCD file already qualifies push_event with the note “Notifications are supported in web apps saved
to the home screen”. In the same issue a participant reports that the event fires on iOS 18 in an
installed app; this run confirms that report with a dated measurement and is not a new finding.
WebKit bug 268797, “notificationclick events in serviceworkers not firing”, was opened 2024-02-05
against iOS 17 and has status NEW, last changed 2026-10-12
(Bug 268797, bugs.webkit.org). Its reports
cover several app states. Comment 35 (iOS 18.7) ties the lost click to a push notification tapped
when no page of the app is alive; comment 40 (iOS 26.6.2) describes a different pattern. This run sent no push message and had a window alive on every tap, so it neither
confirms nor contradicts the bug.
The Notifications API Standard defines notificationclick as a service worker event
(Notifications API, whatwg.org), and the Service Workers
specification defines clients.openWindow()
(Service Workers, w3.org). MDN’s
notificationclick event
page (developer.mozilla.org) shows the same matchAll() then focus() or openWindow() pattern the
harness uses.
The redacted evidence is in the study’s
data package (CC BY 4.0). The event records
are in raw/2026-10-20-ios18.6.2-step22-app-lab-events.json (taps 1 to 3, N35),
raw/2026-10-20-ios18.6.2-step23-app-lab-events.json (tap 4, N36),
raw/2026-10-20-ios18.6.2-step24-app-lab-events.json (tap 5, N38) and
raw/2026-10-20-ios18.6.2-step24b-app-lab-events.json (tap 6, N40), each with a .meta.json
sidecar giving the UTC read time and tool hashes. The banners are in
screenshots/2026-10-20_iphone16pro_ios18.6.2_T8_1a.png and …_T8_1b_redacted.png. The
machine-readable run is in /lab/results.json under the id
notificationclick-in-home-screen-apps/2026-10-20-ios-18.6.2-22g100.
The result backs the notification-click section of
Web Push on iOS and iPadOS and a measured condition on the
Safari for iOS cell of the notificationclick entry.
Reference entries
Related issues and bugs
- One device, one build, one operator, one run day: an iPhone 16 Pro on iOS 18.6.2 (22G100), not
wiped, with other Home Screen apps and one Safari Web Extension installed.
- Only local notifications from
registration.showNotification() were tapped. No push message was
delivered, so the push conditions reported in WebKit bug 268797 were not created.
- A window was alive on every tap. The
clients.openWindow() path, with no window alive, was not
reached. A test of that path is listed on the roadmap.
- One worker script with a subpath scope, no notification actions, no
event.preventDefault(), and
no notificationclose test.
- iPadOS, other iPhone models and other iOS builds were not tested.
Device steps performed by an OpenPWA operator on an iPhone 16 Pro. AI agent sessions read page state over USB, kept the notebook and drafted this text; automated gates and an AI fact-check checked it. No person reviews each entry.