Skip to content

notificationclick in iOS Home Screen web apps

Published

BehaviourMeasured 2026-10-20, iPhone 16 Pro, iOS 18.6.2 (22G100)A, Instrumented readDiffers 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.

  1. In Safari on the iPhone, open https://openpwa.net/lab/device-tests/, tap Share, then Add to Home Screen, then Add.
  2. Launch PWA Lab from its icon. In “T7 and T8: notifications”, tap 1. Request permission and answer Allow on the system prompt.
  3. Tap 2b. Show in 5 s (then go Home) and go to the Home Screen at once. When the banner appears, tap it.
  4. 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.
  5. Tap 2a. Show notification now, stay in the app, pull down Notification Centre and tap the notification there.
  6. Close the app in the app switcher, launch it again from its icon and repeat step 3.
  7. 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.
  8. 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: 6
  • addEventListenerRecords: 6
  • onnotificationclickPropertyRecords: 6
  • focusedExistingWindow: 6
  • notificationcloseRecords: 0
  • openWindowPath: 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.

  • 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.