# iOS Add to Home Screen

> How a site reaches the iOS Home Screen through the Share sheet, what decides web app versus bookmark on iOS 16.4 and 26, and how a page detects standalone mode.

On iOS and iPadOS the only install route is the user's own gesture: Share, then "Add to Home Screen". Safari has offered it since iPhone OS 1; third-party browsers gained it in iOS 16.4; no version fires `beforeinstallprompt` or exposes an install API (BCD `api.BeforeInstallPromptEvent`), so the page supplies icons, a name, and a manifest, and the person holding the device decides, on iOS 26 with an explicit "Open as Web App" switch, how the icon launches.

## How it works

The gesture is fixed: tap **Share**, tap **Add to Home Screen**, optionally edit the name, tap **Add**. From iOS 16.4 a third-party browser can offer the same item when it holds the `com.apple.developer.web-browser` entitlement, places a `WKWebView` showing an HTTP or HTTPS document in the Share sheet's `activityItems`, and the device is not a Shared iPad (WebKit, "Web Push for Web Apps on iOS and iPadOS").

What the icon does when tapped changed between 16.4 and 26:

| iOS version | Opens as a web app (own App Switcher entry, no Safari UI) when | Otherwise |
|---|---|---|
| 16.4 to 18 | The manifest's `display` is `standalone` or `fullscreen`, or the legacy `apple-mobile-web-app-capable` meta tag is `yes`; the browser that added it does not matter | Saved as a Home Screen bookmark that opens in the default browser |
| 26 | By default for every added site; the user can turn off "Open as Web App" in the add sheet even for a site configured as a web app | Bookmark, only when the user turned the switch off |

WebKit's framing for 26 is that Safari has no installability requirements: no manifest, no service worker, no HTTPS check beyond the page itself loading. The manifest still matters for what the web app looks like: `icons` have been read since iOS 15.4, `name` and `short_name` seed the editable title, `id` (16.4+) is combined with the user's chosen name so that two installs of the same site ("Shiny (work)" and "Shiny (personal)") stay distinguishable and Focus filters can treat them separately. Multiple installs of one site are supported and intentional.

Markup supplies the rest, in this order of precedence:

- Icon: `<link rel="apple-touch-icon" sizes="180x180" href="…">` wins over manifest `icons` when both exist; Apple's archived guide documents selecting the icon closest to the device size, then the smallest larger one, then the largest available. With no icon at all, iOS 16.4 and later draw a monogram from the first letter of the site name on a colour taken from the site.
- Name: `<meta name="apple-mobile-web-app-title" content="…">`, else `<title>`, editable by the user before adding.
- Launch image: a screenshot of the last launch by default; `<link rel="apple-touch-startup-image" href="…">` overrides it, which matters offline.
- Status bar: `<meta name="apple-mobile-web-app-status-bar-style" content="black">` applies only in standalone mode; Apple's archived guide states it "has no effect unless you first specify standalone mode".

Once on the Home Screen, the web app gets capabilities a Safari tab does not: Web Push (16.4+, after a user gesture; Declarative Web Push in 18.4 subscribes through `window.pushManager` without a service worker), the Badging API (16.4+, drawn once notifications are allowed), Screen Wake Lock, Screen Orientation, and User Activation (all listed by WebKit for 16.4). WebKit has not required a service worker for the Home Screen entry in any iOS version (WebKit, Safari 26.0 post). Storage stays best-effort: Safari deletes script-written data for an origin with no interaction in seven days of browser use when cross-site tracking prevention is on, and `navigator.storage.persist()` is answered from interaction history without a prompt (MDN, storage quotas and eviction).

## Observed behaviour

The behaviour below is what a reader can reproduce on a device; the page cannot observe the install itself, only the display context afterwards.

:::observed
On an iPhone running iOS 26 (English UI), the Safari Share sheet lists "Add to Home Screen"; the next screen shows the editable name and an "Open as Web App" switch that is on by default, and turning it off saves a bookmark instead (WebKit, "WebKit features in Safari 26.0"). Inside the launched web app, `navigator.standalone` is `true` and `matchMedia('(display-mode: standalone)').matches` is `true`; in a Safari tab on the same device `navigator.standalone` is `false`, and in Chrome on Android the property is `undefined`.
:::

Because no install event exists, the only useful branch is on the display context, taken with the standard media feature and the legacy property as a fallback for older iOS:

```js
const standalone =
  matchMedia('(display-mode: standalone)').matches ||
  navigator.standalone === true;              // Safari-only legacy property

if (standalone) {
  hideInstallHint();                          // launched from the Home Screen
} else if (/iPhone|iPad/.test(navigator.userAgent)) {
  showShareMenuInstructions();                // "Tap Share, then Add to Home Screen"
}
```

Showing the hint on a second or later visit rather than the first trades reach for relevance; rendering it inside a launched web app is noise the branch above prevents. The user-agent test chooses the instruction text only; capability is read from `display-mode`.

## See also

- [WebKit features in Safari 26.0](https://webkit.org/blog/17333/webkit-features-in-safari-26-0/) (webkit.org)
- [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)
- [Configuring Web Applications](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html) (developer.apple.com)
- [PWAs on iOS and Safari](/reference/platforms/ios-safari/)
- [iOS Safari push](/reference/notifications/ios-safari-push/)
- [Badging API](/reference/installation/badging/)
- [`id` manifest member](/reference/manifest/id/)
- [Installability criteria](/reference/installation/installability-criteria/)