Android is where progressive web apps are first-class. Chrome installs them as real apps, Google Play will list them, and the browser actively offers installation. This guide covers the mechanics so you can control them rather than hope.
When Chrome considers a site installable
The criteria have relaxed over the years; as of current Chrome on Android:
- Served over HTTPS.
- A manifest with
nameorshort_name,start_url, adisplayofstandalone,fullscreenorminimal-ui, and icons including 192×192 and 512×512 PNGs. - Historically a registered service worker with a fetch handler and offline capability were also required. Chrome has progressively dropped these as hard conditions — a site can now be installable without working offline — but you want the service worker anyway for speed and offline behaviour, and some other browsers still check for it.
Chrome also applies an engagement heuristic before showing its own prompt: the user must have interacted with the site for a short period. A first-time visitor who bounces in two seconds won't see it. Your own install button (below) is not subject to this delay once the event has fired.
What "installed" produces: the WebAPK
When a user installs from Chrome on a device with Google Play services, Chrome asks a Google server to mint a tiny signed Android package — a WebAPK — containing your manifest data and icon, and installs it. That is why an installed PWA on Android appears in Settings → Apps, can be uninstalled like any app, gets its own task-switcher card, and handles links to your scope directly. Chrome checks the manifest for changes about once a day and re-mints the WebAPK if the name or icon changed. On devices without Play services (and in some other browsers) installation falls back to a home-screen shortcut with the same standalone behaviour.
Controlling the prompt: beforeinstallprompt
Chrome fires this event on the page when the site becomes installable. Catch it, stash it, and show your own button:
let deferredPrompt = null;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault(); // stop the default mini prompt
deferredPrompt = e;
document.getElementById('installBtn').hidden = false;
});
document.getElementById('installBtn').addEventListener('click', async () => {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice; // 'accepted' | 'dismissed'
deferredPrompt = null;
document.getElementById('installBtn').hidden = true;
});
window.addEventListener('appinstalled', () => {
// analytics: installation completed
});Show the button where it makes sense — on the install page, after a successful order, at the end of an article — not on first paint of the homepage. Users who dismiss the prompt won't be re-prompted by Chrome for a while; your button remains available.
The richer install dialog
Since Chrome 108, if your manifest has a description and at least one screenshots entry with form_factor: "narrow", the install prompt becomes a bottom sheet with a screenshot carousel and your description — much closer to a store listing. Sites that add this generally see more completed installs because the prompt finally explains what is being installed. The screenshot tool exports compliant images; the manifest guide has the field details.
Detecting the installed state
const installed = window.matchMedia('(display-mode: standalone)').matches
|| navigator.standalone === true; // iOSUse it to hide the install call-to-action inside the app and to tag analytics.
Other Android browsers
- Samsung Internet — installs to the home screen and its own app list; supports
beforeinstallprompt; no WebAPK. - Edge — Chromium-based; behaves like Chrome including WebAPKs.
- Firefox for Android — add-to-home-screen shortcut; service workers and push supported; no
beforeinstallprompt. - In-app browsers (Facebook, Instagram, TikTok) — cannot install. Detect and offer "Open in Chrome".
Debugging installability
On desktop Chrome, open your site, DevTools → Application → Manifest: the Installability section lists every failing criterion in plain words ("Manifest does not contain a suitable icon"). On the phone, chrome://inspect from a connected desktop shows the same. Nine times out of ten the cause is an icon size, a wrong start_url, or the manifest failing to load because of a path or CORS error.
From installed PWA to Google Play
Everything above is about installing from the browser. If you also want a Play Store listing — for discovery, or because your audience expects one — the same manifest and service worker power a Trusted Web Activity. Get the browser install right first; the Play listing inherits it.