Skip to content

Progressive Web App (PWA)

A progressive web app is an ordinary web application that a browser will offer to install to the device, after which it launches in its own window rather than a browser tab. React applications qualify like any other: nothing in the framework is involved, only what the page serves.

Chromium-based browsers — Chrome, Edge, Samsung Internet — apply the following criteria before offering installation:

  1. The application is served over HTTPS. localhost and 127.0.0.1 also qualify, so local development works without a certificate.
  2. Every page links a web app manifest: <link rel="manifest" href="manifest.json" />.
  3. The manifest contains name or short_name, an icons array including a 192px and a 512px icon, start_url, and display or display_override.
  4. prefer_related_applications is absent, or present and false. Setting it to true tells the browser to promote a native app instead.
  5. The application is not already installed.

Chrome additionally applies engagement heuristics before showing the prompt unprompted — how often the site is visited and how long is spent on it — and backs off for a period after a user dismisses the prompt. These are not part of the criteria and are not documented as stable behaviour; an application that meets the criteria can always trigger the prompt itself by handling the beforeinstallprompt event.

Criteria differ by browser. Safari on iOS and macOS installs through the share sheet’s “Add to Home Screen” or “Add to Dock” rather than a prompt, and Firefox’s support varies by platform.

A service worker is not an install requirement. MDN is explicit: “While not a requirement for a PWA to be installable, many PWAs use service workers to provide an offline experience.”

The reason to register one is capability rather than installability. A service worker is a script that sits between the application and the network, and it is what makes a cache strategy, offline operation, background sync and push notifications possible. An installed application without one simply fails the same way a browser tab does when the network is unavailable — which, for something presented to the user as an app, is usually the wrong behaviour.