# Notification permission in iOS Home Screen apps

> On iOS 18.6.2, a tap-initiated Notification.requestPermission() in a never-prompted Home Screen app stayed pending 2068 ms until answered.

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="notification-permission-prompt" locale="en" />

A Home Screen web app on iOS asks for notification permission with
`Notification.requestPermission()`. In the recorded request on 2026-10-20, an iPhone 16 Pro running iOS 18.6.2 (22G100)
showed the system prompt and kept the promise pending for 2068 ms until the user answered.

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

In an iOS Home Screen web app that has not yet requested notification permission, does
`Notification.requestPermission()` called from a tap show the system prompt, and does the promise
stay pending until the user answers it?

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

## Fresh permission state and request timing

The main test app is "Perm Test", a separate harness app at `/lab/device-tests/t7/perm/` with its own
manifest, scope and service worker, installed for this step and not asked for permission before it.
Its page prints three permission values and keeps a log of every request:

- `Notification.permission`;
- `registration.pushManager.permissionState({userVisibleOnly: true})` on the app's registration;
- `window.pushManager.permissionState({userVisibleOnly: true})`, the Declarative Web Push manager;
- for each request: the wall-clock start and end (`Date.now()`), the elapsed time measured with
  `performance.now()`, and the resolved value.

The values were read over USB before the tap (notebook N53) and after the answer (N54), and the
operator recorded the screen during the request (N59). Two other contexts give supporting values: the
"PWA Lab" app, where the operator's screenshot shows the prompt (N58), and a plain Safari tab, where
the interfaces were checked for presence (N03, N10). The demo app's prompt (N41) rests on the
operator's report and is not used here.

## How to run

The test needs an app that has not asked for permission yet. Whether deleting and re-adding an app
resets its permission was not tested, so use a fresh install.

1. Start a screen recording from Control Centre.
2. In Safari, open `https://openpwa.net/lab/device-tests/t7/perm/`, tap Share, then
   **Add to Home Screen**, then **Add**. Launch **Perm Test** from its yellow P7 icon.
3. Tap **1. Read state (no request)**. A never-prompted app shows `default` and `prompt` twice.
4. Tap **2. Request permission**. Note whether a system prompt appears and its exact text, then
   answer it.
5. Stop the recording. Read "Last request (start / end / elapsed / result)" on the page and tap
   **1. Read state (no request)** again.
6. Compare the elapsed time with the prompt in the recording. A result with no prompt on screen
   would mean the request was decided without asking.

<LabHarnessLinks behaviour="notification-permission-prompt" locale="en" />

## Results

On iOS 18.6.2 (22G100) the never-prompted Perm Test app read `default` with both `permissionState`
values `prompt` before the tap (Instrumented read, A; N53). The request started at 09:27:59.551 UTC,
settled at 09:28:01.620 UTC and took **2068 ms**, resolving `"granted"`; all three values then read
granted (A; N54). The recording shows the system prompt from about 70.6 s to 72.5 s of the original file
(about 69.6 s to 71.5 s in the published file, which drops the first 1.0 s), aligned with the
page's start and end times within the recording's 1 s timestamp resolution (Screenshot or recording,
S; N59). In a zh-CN interface it read "“Perm Test”想给你发送通知", with the body
"通知可能包括提醒、声音和图标标记。可在“设置”中配置相关功能。" and the buttons "不允许" and "允许". Within that resolution the
prompt was on screen during the interval the page recorded, so the request stayed pending until the
prompt was answered.

The PWA Lab app shows the same prompt with its own name in a screenshot taken at 08:17:36 UTC (S;
N58), and its permission read `default` at first launch and `granted` after the tap (A; N18, N32).
In both apps one grant set the registration's and `window.pushManager`'s `permissionState` to
granted (A; N32, N54). Settings → 通知 then listed PWA Lab and the OpenPWA demo app with banners,
sounds and badges (S; N61). In a Safari tab `Notification` and `PushManager` were absent, so no
request is possible there (A; N03, N10).

<LabResults behaviour="notification-permission-prompt" locale="en" />

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

## Permission requirements and promise resolution

WebKit's iOS 16.4 post requires the permission request in a Home Screen web app to follow a user
gesture
([Web Push for Web Apps on iOS and iPadOS](https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/),
webkit.org). The Notifications API Standard defines `requestPermission()` as returning a promise
that resolves with the permission once it is decided
([Notifications API](https://notifications.spec.whatwg.org/), whatwg.org). BCD records
`api.Notification` on Safari for iOS from 16.4 as partial, with notes that the interface exists only
in web apps saved to the Home Screen
([Notification.json](https://raw.githubusercontent.com/mdn/browser-compat-data/main/api/Notification.json),
github.com). The measurement agrees with all three. It records the prompt
text in one UI language, the pending interval, and the fact that one grant set both push managers'
`permissionState`, which none of the three sources states (the `permissionState()` method itself is
defined in the [Push API](https://w3c.github.io/push-api/), w3.org). It is not a new finding.

The coordinator's relay that a prompt was shown at step 19 paraphrased the planned step and is void
as evidence (N32-b). The operator later reported that no prompt appeared at step 19, but their
own screenshot contradicts that report (N32-a, N58). Do not cite either account. Nothing
in this run shows iOS granting permission without a prompt.

## Data

The values are in the study's
[data package](/research/2026-10-ios18-home-screen-web-apps/data/) (CC BY 4.0):
`raw/2026-10-20-ios18.6.2-25c-pre-app-perm.json` (N53) and
`raw/2026-10-20-ios18.6.2-25c-post-app-perm.json` (N54), each with a `.meta.json` sidecar, and
`raw/2026-10-20-ios18.6.2-step19-app-lab-perm.json` (N32) for PWA Lab. The recording is
`recording/2026-10-20_iphone16pro_ios18.6.2_T7_25c_trimmed.mp4`, with key frames before, during
(`…_frame_t071.5s_prompt.png`) and after the prompt; the PWA Lab prompt is
`screenshots/2026-10-20_iphone16pro_ios18.6.2_T7_2.png`. The machine-readable run is in
[/lab/results.json](/lab/results.json) under the id
`notification-permission-prompt/2026-10-20-ios-18.6.2-22g100`.

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

## Related reference entries

The result backs the permission paragraph of
[Web Push on iOS and iPadOS](/reference/notifications/ios-safari-push/), the iOS notes of
[Notification.requestPermission()](/reference/notifications/permissions/) and the Safari for iOS
row of the notification permission compatibility data.

<LabBacks behaviour="notification-permission-prompt" locale="en" />

## Limits

- One device, one build, one operator, one run day: an iPhone 16 Pro on iOS 18.6.2 (22G100), with a
  zh-CN interface.
- One recorded request in a never-prompted app. The 2068 ms is one human response time, not a
  platform constant.
- Only **Allow** was tapped. A denial, a dismissed prompt, a second request after a decision, and a
  request made without a user gesture were not tested.
- The recording's start time has 1 s resolution; the interval comes from `performance.now()` in the
  page.
- iPadOS and other iOS builds were not tested. The same device is due to be rerun after its upgrade
  to iOS 27.

<LabProvenance locale="en" />