# Declarative Web Push subscription scope on iOS

> On iOS 18.6.2, window.pushManager.getSubscription() returned null while a subpath-scoped worker held a subscription; the manager also existed in a Safari tab.

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="declarative-web-push-subscription-scope" locale="en" />

From iOS 18.4 a page can subscribe to push through `window.pushManager` (Declarative Web Push) as
well as through a service worker registration. On an iPhone 16 Pro running iOS 18.6.2 (22G100), `window.pushManager` existed in a Safari tab.
In Home Screen apps it did not return the subpath-scoped worker's subscription (2026-10-20).

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

On iOS, when a Home Screen web app's service worker is scoped to a subpath and subscribes through its
registration, does `window.pushManager.getSubscription()` return that subscription? Does one
permission grant cover both managers? And is `window.pushManager` exposed in a plain Safari tab?

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

## Two subscription managers

Two Home Screen apps were used, each with a worker scoped below the site root: the Device Lab harness
"PWA Lab" (scope `/lab/device-tests/`) and the OpenPWA demo (scope `/demo/`). In each app the
subscription was made through `registration.pushManager.subscribe()` with `userVisibleOnly: true` and
an application server key. We recorded these values, keeping only the endpoint's host:

- For `registration.pushManager.getSubscription()`, we recorded the endpoint host and path length.
  We also recorded `expirationTime` and `options.userVisibleOnly` and checked whether the `applicationServerKey` matched;
- `window.pushManager.getSubscription()`;
- `permissionState({userVisibleOnly: true})` on both managers before the grant and again afterward.

In a Safari tab we checked exposure only. We read `'pushManager' in window` and the types of its
`subscribe` and `permissionState` members, along with `getSubscription`. We also checked
`'PushManager' in window` and `'Notification' in window`. `window.pushManager.subscribe()` was not called in any context, and no
root-scoped worker was tested.

## How to run

Steps 4 and 5 need Web Inspector. On the iPhone, turn Settings → Apps → Safari → Advanced → Web Inspector
on. On a Mac, select Safari → Develop → the iPhone → the app's page.

1. In Safari on the iPhone, open `https://openpwa.net/lab/device-tests/` and read the Results panel
   (T5, T9, T10). It prints `'pushManager' in window` and the types of `window.pushManager.subscribe`
   and `permissionState`. It also prints `'PushManager' in window` and `'Notification' in window`.
2. Add the page to the Home Screen (Share, **Add to Home Screen**, **Add**) and launch **PWA Lab**.
3. Tap **1. Request permission**, allow it, then tap **Subscribe to push**. The result line names the
   endpoint host.
4. In the Web Inspector console, evaluate
   `(await navigator.serviceWorker.getRegistration()).pushManager.getSubscription()` and
   `await window.pushManager.getSubscription()`. Record the endpoint host only, not the full
   endpoint or keys.
5. Evaluate `await window.pushManager.permissionState({userVisibleOnly: true})` and the same call on
   the registration's `pushManager`.

<LabHarnessLinks behaviour="declarative-web-push-subscription-scope" locale="en" />

## Results

On iOS 18.6.2 (22G100), in the PWA Lab app the registration's subscription had an endpoint on
`web.push.apple.com`, a path length of 172, `expirationTime` null, `userVisibleOnly` true and the
harness's key, while `window.pushManager.getSubscription()` returned null (Instrumented read, A;
notebook N33). The demo app also returned endpoint host `web.push.apple.com` with
`expirationTime` null. Its `window.pushManager.getSubscription()` returned null too (A; N41). One permission
grant set both managers' `permissionState` to granted, in PWA Lab and in the freshly installed Perm Test
app (A; N32, N54).

In a plain Safari tab `'pushManager' in window` was true. Both `subscribe` and `permissionState` were functions,
as was `getSubscription`, while `'PushManager' in window` and `'Notification' in window` were
false (A; N03, N10). We did not try `window.pushManager.subscribe()` in a tab; these reads establish only that the object exists.

<LabResults behaviour="declarative-web-push-subscription-scope" locale="en" />

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

## Root scope and Home Screen requirements

WebKit's [Meet Declarative Web Push](https://webkit.org/blog/16535/meet-declarative-web-push/) post
(webkit.org) says that a registered service worker "scoped to the root level of your website domain"
shares the window's push subscription. The subpath result **agrees** with that rule for the case it
leaves out: with a worker below the root, the window manager did not return the worker's
subscription. The rule's positive case, a root-scoped worker, was not tested here, so this run
neither confirms nor contradicts it. The shared permission is not stated in the post.

WebKit's Safari 18.4 post makes Declarative Web Push available "on iOS and iPadOS 18.4 for web apps
added to the Home Screen"
([WebKit Features in Safari 18.4](https://webkit.org/blog/16574/webkit-features-in-safari-18-4/),
webkit.org), and BCD records `api.Window.pushManager` from Safari for iOS 18.4, marked experimental
([Window.json](https://raw.githubusercontent.com/mdn/browser-compat-data/main/api/Window.json),
github.com). Neither says whether the object exists in an ordinary tab. The tab result therefore
**adds a condition**. On 18.6.2 the object is exposed in a tab that has no `Notification` and no
`PushManager`, so `'pushManager' in window` does not show that push can be used there. The Push API
defines `window.pushManager` through a `PushManagerAttribute` mixin that `Window` includes in secure
contexts ([Push API](https://w3c.github.io/push-api/), w3.org); it does not describe the Home Screen
condition that WebKit's post states.

As far as the study's prior-art check found, the tab exposure had not been published before. The
subpath subscription result is consistent with WebKit's description and adds a measured case.

## Data

The values are in the study's
[data package](/research/2026-10-ios18-home-screen-web-apps/data/) (CC BY 4.0): the tab side in
`raw/2026-10-20-ios18.6.2-tab-lab.json` (N03) and `raw/2026-10-20-ios18.6.2-step03-tab-demo-push.json`
(N10); PWA Lab in `raw/2026-10-20-ios18.6.2-step19-app-lab-perm.json` (N32) and
`raw/2026-10-20-ios18.6.2-step20-app-lab-sub.json` (N33); the demo in
`raw/2026-10-20-ios18.6.2-step25b-app-demo-push.json` (N41); Perm Test in
`raw/2026-10-20-ios18.6.2-25c-post-app-perm.json` (N54). No raw file holds a full endpoint. The
machine-readable run is in [/lab/results.json](/lab/results.json) under the id
`declarative-web-push-subscription-scope/2026-10-20-ios-18.6.2-22g100`.

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

## Related reference entries

The result backs the Declarative Web Push paragraphs of
[Web Push on iOS and iPadOS](/reference/notifications/ios-safari-push/) and
[Web Push and PushManager.subscribe()](/reference/notifications/web-push/), and the condition on the
Declarative Web Push row of the Web Push compatibility data.

<LabBacks behaviour="declarative-web-push-subscription-scope" locale="en" />

## Limits

- One device, one build, one operator, one run day: an iPhone 16 Pro on iOS 18.6.2 (22G100).
- Both workers were scoped to a subpath. A root-scoped worker, the case WebKit's rule covers, was not
  tested.
- `window.pushManager.subscribe()` was not called, in either a tab or an app. The run therefore does not establish whether
  a window subscription is visible to the worker or whether a tab can subscribe.
- No push message was delivered; the harness has no push server.
- The demo app's prompt rests on the operator's report; its permission state and subscription are
  instrumented reads.
- iPadOS and macOS Safari were not tested, nor were other iOS builds. The same device is due to be rerun after
  its upgrade to iOS 27.

<LabProvenance locale="en" />