Skip to content

Installing Progressive Web Apps

Installing a Progressive Web App registers a website with the operating system as an application. The site gets its own launcher icon, its own window without browser UI, an entry in the OS app list, and on some platforms access to features that plain tabs don't get. The browser still runs the app. That distinction explains most of the surprises developers hit: storage is shared with the browser or isolated from it depending on the platform, "uninstall" may or may not delete data, and your code often can't tell that it was installed at all. This section covers what installation creates on each platform, how users and your UI trigger it, and how you detect and measure it.

Key takeaways

  • An installed PWA is an OS-level launcher entry plus a browser-hosted app window. Chromium creates real OS artifacts: Start menu entries on Windows, app bundles on macOS, .desktop files on Linux, and signed WebAPKs on Android. Safari creates Home Screen web apps on iOS and Dock web apps on macOS.
  • Storage behavior differs by platform. Chromium apps on desktop and Android share storage with the browser profile. Each iOS Home Screen web app has its own isolated storage. Safari on macOS copies only cookies into a new Dock app.
  • Only Chromium-based browsers let your page trigger the install dialog, through beforeinstallprompt. Safari and Firefox are user-initiated only, so your UI must fall back to instructions there.
  • Since iOS 26, every site added to the Home Screen opens as a web app by default, and desktop Chrome lets users install almost any page from its menu (Install page as app). Installation no longer depends on your manifest, but promotion and the quality of the result still do.
  • Install detection comes from several partial signals: appinstalled, the display-mode media feature, navigator.standalone on iOS, getInstalledRelatedApps(), and a marker in start_url. None of them works everywhere.
  • navigator.install() and the <install> element, which let a page install itself or another origin's app, are still experimental in September 2026.

What installation creates, technically

"Install" means different things on different platforms. What they have in common is that the browser writes something into the operating system's app registry that launches your start_url in an app window. The table shows what that is on each platform.

Platform Installing browser What the OS gets Where users find and remove it
Windows Chrome, Edge (Chromium) Start menu shortcut in a per-browser Apps folder, optional taskbar and desktop shortcuts, an entry in Settings > Apps > Installed apps Start menu, Installed apps, chrome://apps, edge://apps, the app window's menu
Windows Firefox 143+ A site pinned to the taskbar that opens in a simplified Firefox window Taskbar
macOS Chrome, Edge An app shim bundle; Chrome puts it in ~/Applications/Chrome Apps.localized/ Launchpad, Spotlight, Finder, chrome://apps
macOS Safari 17+ A web app added to the Dock, opened in its own window even without a manifest Dock, Launchpad, Spotlight
Linux Chrome, Edge A freedesktop .desktop file named <browser>-<app id>-<profile>.desktop in the user's applications directory Desktop environment's app launcher
ChromeOS Chrome A launcher and shelf app managed by the system Launcher, Settings > Apps
Android Chrome with Google Play services, Samsung Internet on Samsung devices A WebAPK: a real Android package signed by a minting server App drawer, Settings > Apps
Android Firefox, Edge, others A pinned home screen shortcut badged with the browser logo Home screen
iOS, iPadOS Safari and, since 16.4, browsers with Apple's web-browser entitlement A Home Screen web app Home Screen, App Library

The details of each flow are in Installation by Platform. The rest of this section covers the parts every installed app has in common.

The launcher entry and the app's identity

Every install creates a launcher entry named after your manifest's name or short_name and using an icon from icons (or apple-touch-icon on iOS). The browser also records an identity for the app, and on Chromium that identity is the manifest id, or start_url when there's no id. The identity decides whether a later manifest counts as an update to the same app or as a different app. It also shows up in APIs that need to refer to an installed app, such as getInstalledRelatedApps() on desktop and the experimental navigator.install(). Set id explicitly before your first user installs. App Identity & Updates covers how the ID is computed and what changes trigger an update.

The standalone window

Launching the entry opens start_url in a window whose chrome depends on display and display_override: no browser UI in standalone, a small back and reload toolbar in minimal-ui, or custom title bar content with Window Controls Overlay. Navigations inside the manifest scope stay in the window. Out-of-scope navigations show an origin bar on desktop, or open in a Custom Tab on Android. The display-mode media feature reports which mode applies, which is how CSS and JavaScript adapt to the app context. Display Modes documents how each engine resolves the mode.

Storage: shared with the browser or isolated

Where your data lives after installation surprises many teams:

  • Chromium on desktop. The app runs in the browser profile it was installed from. Cookies, IndexedDB, Cache Storage and service worker registrations are the same ones the site uses in a tab of that profile. A user signed in in the browser is signed in in the app.
  • Chrome on Android (WebAPK). The WebAPK is a thin launcher package. Pages run in Chrome and use Chrome's storage for the origin, so tab and app share state.
  • Safari on iOS and iPadOS. Each Home Screen web app has its own storage container, isolated from Safari and from other copies of the same site added to the Home Screen. Since iOS 17.2, Safari's cookies are copied into the new web app when it is created, so users generally stay signed in through cookie-based sessions; localStorage, IndexedDB and caches are not copied. Adding the same site twice creates two independent apps.
  • Safari on macOS. When the user adds a site to the Dock, Safari copies the site's cookies into the new web app so the user stays signed in. According to WebKit's Safari 17 announcement, "Safari does not copy over any other kind of local storage."

This has practical consequences for install flows. On iOS, anything you store before installation, such as a draft, a cart or an onboarding state, isn't available in the installed app. On Chromium, your service worker and caches are already in place when the app launches for the first time. Storage Quotas & Persistence and iOS & iPadOS cover the details.

WebAPKs on Android

When Chrome on Android installs a promotable PWA on a device with Google Play services, it requests a WebAPK from Google's minting service. The WebAPK is a real, signed Android package generated from your manifest. It appears in the app drawer and in Settings > Apps, registers intent filters so links inside your scope open in the app, and can expose app shortcuts and a share target. Chrome checks the manifest for changes and requests an updated WebAPK when relevant members change. When minting isn't available, Chrome creates a plain home screen shortcut instead, which gets none of these integrations. You can inspect installed WebAPKs at about://webapks. The differences between WebAPKs, shortcuts and Trusted Web Activities are covered in Android.

Minting takes time. According to web.dev's Learn PWA detection chapter, on Android with WebAPK the appinstalled event fires when the user accepts the dialog, "not after the WebAPK is minted and installed". The launcher icon may appear a few seconds later.

Uninstalling and what happens to data

Users uninstall PWAs the way they uninstall other apps on the platform: Settings > Apps on Windows and Android, dragging to the Trash or using the launcher on macOS, or long-pressing the icon on iOS. Chromium browsers also offer uninstall from the app window's menu and from chrome://apps or edge://apps. On Windows, Chromium registers each app with the OS uninstall list, so it also appears in Installed apps. Chromium's source only implements that registration on Windows.

Uninstalling doesn't necessarily delete site data:

  • Chrome's desktop uninstall dialog has an opt-in checkbox, "Also delete browsing data (origin) which will sign you out of domain." Unchecked, the site's storage survives in the browser profile.
  • Removing a WebAPK on Android removes the launcher package. The origin's data lives in Chrome and stays there unless the user clears it.
  • Deleting an iOS Home Screen web app deletes its isolated storage container along with it.

No uninstall event reaches your code. If you need to know about uninstalls, infer them server side: push subscriptions that start returning 404 or 410 from the push service, or installed-app sessions that stop arriving. Detecting Installed Apps shows how to record installed sessions.

Install flows by platform

The table summarizes how installation starts on each platform and which developer-facing events you get. The full step-by-step flows, menu labels and platform quirks are in Installation by Platform.

Platform and browser User-initiated path Browser promotion beforeinstallprompt appinstalled
Chrome desktop Address bar install icon; More > Cast, save, and share > Install page as app Install icon in the address bar ✅ ✅
Edge desktop App available icon; Settings and more > Apps > Install this site as an app App available icon ✅ ✅
Chrome for Android More > Add to home screen > Install (labels vary by version) Install message and bottom sheet, rate-limited by Chrome's own heuristics ✅ ✅ (on accept)
Samsung Internet Install icon in the URL bar; menu Add page to URL bar icon ✅ (5.0+) ✅ (7.0+)
Firefox for Android Menu Add app to Home screen or Install (varies by version) None ❌ ❌
Firefox on Windows (143+) Pin the site to the taskbar None ❌ ❌
Safari on iOS and iPadOS Share > Add to Home Screen, with Open as Web App on by default since iOS 26 None ❌ ❌
Safari on macOS (17+) File > Add to Dock or Share > Add to Dock None ❌ ❌

Support data as of September 2026. Check MDN's beforeinstallprompt compatibility data and caniuse for live data.

Two platform changes from 2024 to 2025 reshaped this table. Chrome added Install page as app on desktop in 2024, which installs almost any page whether or not it passes the installability criteria, and Safari 26 made Open as Web App the default for every Home Screen addition. As a result, the criteria now decide whether a browser promotes your app and how good the installed result is, not whether users can install it.

Promoting installation

Because browsers promote installation sparingly and Safari never does, most successful PWAs ask for the install themselves. The common patterns:

  • A persistent, low-key entry point: an Install app item in the header, account menu or settings page. It's always there for users who look for it.
  • A contextual promotion: a card in a feed, or a prompt shown after a meaningful action such as completing an order, saving a second document or enabling notifications. It appears when the value of installing is obvious.
  • An install landing page that explains what the app does offline or with notifications, linked from emails or onboarding.
  • Platform-specific instructions for Safari and Firefox, which don't fire beforeinstallprompt: a short illustrated guide to Share > Add to Home Screen or File > Add to Dock.

On Chromium, every pattern ends in the same call: save the beforeinstallprompt event, then call its prompt() method from a click handler. Install Prompts & Custom UI documents the event, complete code for each pattern, the iOS instructions UI, the experimental Web Install API, and UX rules that keep promotion from becoming spam. The manifest can make the browser's own dialog more persuasive. Rich Install UI covers the screenshots and description members behind Chromium's store-like dialog.

flowchart TD
    A["Page loads"] --> B{"beforeinstallprompt fired?"}
    B -- "yes (Chromium)" --> C["preventDefault(), save event, show install button"]
    C --> D["User clicks button"]
    D --> E["event.prompt()"]
    E --> F{"outcome"}
    F -- accepted --> G["appinstalled: hide promotion, record install"]
    F -- dismissed --> H["Hide button; wait for next beforeinstallprompt"]
    B -- "no" --> I{"Already running installed?"}
    I -- yes --> J["No promotion"]
    I -- no --> K{"iOS / macOS Safari / Firefox?"}
    K -- yes --> L["Show platform instructions on demand"]
    K -- no --> M["No install UI"]

Detecting and measuring installs

You can't query "is this app installed?" everywhere, so install analytics combines several signals, each covering part of the picture:

Signal What it tells you Where it works
beforeinstallprompt fired The page is promotable and not installed in this profile Chromium
prompt() result (outcome) Whether the user accepted or dismissed your prompt Chromium
appinstalled An install succeeded, from your button or from browser UI Chromium
display-mode media feature The current document runs in an app window All engines, with differences
navigator.standalone === true The document runs as a Home Screen web app (iOS, iPadOS) or a Dock web app (macOS) Safari on iOS and iPadOS; Safari 17+ on macOS. Check it before display-mode on iOS, and combine it with navigator.maxTouchPoints > 0 to tell iOS from macOS
start_url marker, such as ?source=pwa The session started from the app icon All platforms
document.referrer starting with android-app:// The first page load came from an Android app, such as a TWA Chrome on Android
navigator.getInstalledRelatedApps() Your PWA or native app is installed, queried from a tab Chromium on Android (84+) and desktop (140+)

These signals give you an install funnel: promotable → promotion shown → prompt accepted → installed → launched as app → retained. Detecting Installed Apps has complete detection code, and Install Prompts & Custom UI shows how to instrument each step. For sending these events to an analytics backend, including sessions that start offline, see Analytics for PWAs.

Measure launches and retention, not just installs. An install that's never opened adds little value, and on iOS you can only observe the launch, not the install itself.

Beyond browser installation: stores and wrappers

Browser installation isn't the only way to put a PWA on a device. You can package the same web app for app stores:

  • Google Play through a Trusted Web Activity, an Android app that renders your origin in Chrome without browser UI, verified with Digital Asset Links.
  • Microsoft Store, which lists PWAs directly as packaged apps.
  • Apple's App Store, which requires a native wrapper and is subject to App Review's rules on minimum functionality.

Store distribution changes discovery, updates and payments, and it adds signals you can detect, such as related_applications entries of platform play or windows. Publishing to App Stores compares the stores and the tooling, including PWABuilder.

The experimental Web Install API

beforeinstallprompt can only install the page the user is on, and only when Chromium decides it's promotable. Microsoft and Google are incubating two entry points that remove both limits: navigator.install(), a promise-based method, and a declarative <install> element. Both can install the current app or an app from another origin identified by its manifest URL, and both require the target manifest to have an id (or the caller to supply the computed ID). They ran as origin trials in Chrome and Edge (navigator.install() from Chrome 143 to 150, <install> from 148 to 153), and Chrome Platform Status lists intents to ship both on desktop in Chrome 156, scheduled for stable release on October 20, 2026. Android isn't part of that intent. WebKit opposes site-initiated installation, and Mozilla hasn't taken a position. Install Prompts & Custom UI covers the current API shape and how to feature-detect it safely.

Pages in this section

  • Install Prompts & Custom UI


    beforeinstallprompt in depth, complete install button and promotion patterns, iOS instructions, appinstalled, the Web Install API and install funnel analytics.

    Install Prompts & Custom UI

  • Detecting Installed Apps


    display-mode, navigator.standalone, getInstalledRelatedApps(), launch attribution with start_url, TWA referrers and server-side install tracking.

    Detecting Installed Apps

  • Installation by Platform


    Step-by-step install flows and behavior on Windows, macOS, Linux, ChromeOS, Android, iOS and iPadOS for every major browser.

    Installation by Platform

  • Publishing to App Stores


    Shipping a PWA through Google Play, the Microsoft Store and Apple's App Store: packaging, policies and tooling.

    Publishing to App Stores

  • Trusted Web Activity


    Wrapping a PWA in an Android app with Digital Asset Links, Bubblewrap, Play Billing and launch customization.

    Trusted Web Activity

Further reading

On this site

External references