# notificationclick in iOS Home Screen web apps

> On iOS 18.6.2, notificationclick fired in a Home Screen web app through addEventListener and onnotificationclick on 6 of 6 taps.

import LabEvidenceLine from '@components/lab/LabEvidenceLine.astro';
import LabHarnessLinks from '@components/lab/LabHarnessLinks.astro';
import LabResults from '@components/lab/LabResults.astro';
import LabBacks from '@components/lab/LabBacks.astro';
import LabProvenance from '@components/lab/LabProvenance.astro';

<LabEvidenceLine behaviour="notificationclick-in-home-screen-apps" locale="en" />

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.

<span id="question"></span>

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?

<span id="what-we-measured"></span>

## Handlers and tap conditions

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](https://openpwa.net/lab/device-tests/lab.js) and [sw.js](https://openpwa.net/lab/device-tests/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.

## How to run

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.

<LabHarnessLinks behaviour="notificationclick-in-home-screen-apps" locale="en" />

## Results

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.

<LabResults behaviour="notificationclick-in-home-screen-apps" locale="en" />

<span id="what-the-documentation-says"></span>

## BCD and WebKit click-event reports

BCD records `api.ServiceWorkerGlobalScope.notificationclick_event` for `safari_ios` as
`version_added: false` ([ServiceWorkerGlobalScope.json](https://raw.githubusercontent.com/mdn/browser-compat-data/main/api/ServiceWorkerGlobalScope.json),
github.com, read 2026-10-20). The measurement differs from that cell. In
[mdn/browser-compat-data#22959](https://github.com/mdn/browser-compat-data/issues/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](/lab/behaviour/worker-event-handler-exposure-tab-vs-app/)). 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](https://bugs.webkit.org/show_bug.cgi?id=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](https://notifications.spec.whatwg.org/), whatwg.org), and the Service Workers
specification defines `clients.openWindow()`
([Service Workers](https://w3c.github.io/ServiceWorker/#clients-openwindow), w3.org). MDN's
[notificationclick event](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/notificationclick_event)
page (developer.mozilla.org) shows the same `matchAll()` then `focus()` or `openWindow()` pattern the
harness uses.

## Data

The redacted evidence is in the study's
[data package](/research/2026-10-ios18-home-screen-web-apps/data/) (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](/lab/results.json) under the id
`notificationclick-in-home-screen-apps/2026-10-20-ios-18.6.2-22g100`.

<span id="what-it-backs"></span>

## Related reference entries

The result backs the notification-click section of
[Web Push on iOS and iPadOS](/reference/notifications/ios-safari-push/) and a measured condition on the
Safari for iOS cell of the `notificationclick` entry.

<LabBacks behaviour="notificationclick-in-home-screen-apps" locale="en" />

## Limits

- 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](/lab/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.

<LabProvenance locale="en" />