This is the short path that actually makes a static site installable. The generators used below run locally in the browser on Colorful Toolhub's Mobile PWA workbench. You still deploy the files yourself.
Chromium installs a site when it is served over HTTPS, the page points at a valid manifest, a service worker controls the page, and 192px and 512px icons are present. iOS does not use the manifest icons for the home screen. You still need apple-touch-icon.
Manifest
Use the PWA Manifest Generator.
-
short_namestays around 12 characters. Home screens truncate longer names. -
start_urlis a stable path inside the site, optionally with one fixed query such as/?source=pwa. Do not put changing analytics parameters here. -
scopemust coverstart_url. A site deployed at/app/cannot use scope/. -
display: "standalone"is the usual choice.browserdoes not leave the browser UI.fullscreenhides the status bar. -
background_coloris the splash background.theme_coloris the browser chrome. They can differ. - Provide PNG icons at 192 and 512. SVG alone is still unreliable on some Android installers.
shortcuts are optional. Each shortcut URL has to sit inside scope.
Save the file as /manifest.json and add this to every HTML document:
<link rel="manifest" href="/manifest.json">
A root-relative href that does not match the deployed path fails silently. The installer requests that exact URL.
Maskable icons
Android masks icons as a circle, a rounded square, or a teardrop. The safe zone is roughly the center 80%. Keep the mark inside that circle.
Adjust it in the Maskable Icon Editor, and preview circle, rounded-rect, and teardrop. Prefer two manifest entries over a single purpose: "any maskable" image:
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
{ "src": "/icon-maskable-192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }
Do the same for 512. One image marked any maskable is often padded, so the non-masked icon looks small.
iOS still wants touch icons and splash screens. The Launch Icon and Splash Generator exports those PNGs and the link tags. Without them, Safari screenshots the current page and flashes a blank splash.
Service worker
Installability only needs a controlling worker. Caching strategy decides whether the next deploy is reachable.
- Fingerprinted JS, CSS, and fonts: cache-first. A new filename is a new resource.
- HTML: network-first, then cache. Cache-first HTML keeps pointing at deleted hashed assets and the site goes blank.
- API responses: stale-while-revalidate, or do not cache them.
- One offline fallback document for failed navigations.
The Service Worker Generator emits sw.js plus a registration snippet for those strategies. Register after load. The default scope is the script's directory, so /sw.js can control the origin and /assets/sw.js cannot.
Do not call skipWaiting() and clients.claim() on the first install of every version. The old page and the new cache will mix. Let the new worker wait, tell the page, and skip waiting only after a refresh.
Check
In Chrome DevTools, Application:
- Manifest shows no errors,
start_urlis insidescope, icons preview. - The service worker is activated and controls the current window.
- Offline reload still serves the HTML fallback you wrote, not the browser's offline dinosaur.
The install icon, or a firing beforeinstallprompt, is the real signal. Lighthouse no longer scores PWA as a single category, so an old PWA score is not the definition of done.
Top comments (0)