Installation · Concept
Installability criteria
Published
Installability criteria are the conditions a browser checks before it offers an install surface (an address-bar icon, a menu item, or the beforeinstallprompt event) for a page. Chromium browsers (Chrome, Edge, Samsung Internet) gate on a secure origin plus a manifest with a name, a start URL, a non-browser display mode, and icons; Safari on iOS 26 and Firefox 143 on Windows have no manifest requirement at all and install any page from their own menus (BCD html.manifest, Chrome “Changes to the installability criteria”, WebKit Safari 26.0 release post, Firefox 143 release notes).
How it works
Section titled “How it works”Chromium evaluates the page each time it loads and records the result in DevTools under Application › Manifest › “Installability”. The checks, in the order Chrome’s install-criteria article lists them:
- The page is served from a secure context:
https:, orhttp://localhostandhttp://127.0.0.1during development. - The document links a manifest (
<link rel="manifest">) that parses and containsnameorshort_name,start_url, adisplayofstandalone,fullscreen, orminimal-ui(or adisplay_overridethat resolves to one), andiconsincluding a 192 px and a 512 px entry; for the install dialog Chrome requires at least one icon of 144 px or larger in PNG, SVG, or WebP withsizesset andpurposeincludingany. start_urlis withinscopeand returns a document (a redirect to another origin fails the check).- The app is not already installed in this browser profile.
A registered service worker with a fetch handler was part of the list until Chrome 108 on Android and Chrome 112 on desktop removed it for installation from the browser menu; Chrome supplies a default offline page for installed apps without one. The same Chrome post notes that the heuristic behind beforeinstallprompt still looked for a fetch handler, so a page can pass the menu check and never receive the event. Chrome additionally delays the event (and the Android mini-infobar) until its engagement heuristics are met, which is why the DevTools panel can report “installable” while no event fires.
Other browsers apply different lists:
| Browser | What it requires before offering install | Install surface |
|---|---|---|
| Edge 79+ (desktop) | Same manifest and HTTPS checks as Chrome, same Chromium release floors | Address-bar icon, Apps menu, beforeinstallprompt |
| Samsung Internet 9.0+ | Its own variant of the Chromium list; the compat dataset records beforeinstallprompt from 9.0 |
Address-bar install button, beforeinstallprompt |
| Safari, iOS and iPadOS 26 | None: every site added from the Share sheet opens as a web app unless the user turns off “Open as Web App” | Share sheet › “Add to Home Screen” |
| Safari, iOS and iPadOS 16.4 to 18 | Manifest display: standalone or fullscreen (or the legacy apple-mobile-web-app-capable meta tag) for web-app mode; otherwise a bookmark |
Share sheet › “Add to Home Screen” |
| Safari 17+, macOS 14+ | None; File › “Add to Dock” works for any page, manifest values are used when present | File menu |
| Firefox 143+, Windows | None; the address-bar icon pins any site as a taskbar web app | Address-bar icon |
| Firefox for Android | A manifest; installs as a home-screen shortcut, no event | Three-dot menu › “Install” |
The trade-off for authors is that the Chromium list is the only one that can be failed, so a manifest that satisfies Chrome also satisfies every other browser’s install path; the reverse is not true, and a page that only tests on iOS can ship without the icons Chrome’s dialog needs.
Examples
Section titled “Examples”The first example is a page-side check that mirrors the Chromium list; the second shows a manifest that passes it.
Checking the page against the Chromium list and acting on the result
Section titled “Checking the page against the Chromium list and acting on the result”The page cannot run Chrome’s installability algorithm, but it can verify the inputs it controls and decide what install UI to offer per browser. The fallback branch covers browsers that install without any of these inputs.
async function installabilityReport() { const problems = []; if (!isSecureContext) problems.push('not a secure context: no browser will offer install');
const link = document.querySelector('link[rel="manifest"]'); if (!link) { problems.push('no <link rel="manifest">'); } else { const manifest = await fetch(link.href).then((r) => r.json()).catch(() => null); if (!manifest) problems.push('manifest does not parse'); else { if (!manifest.name && !manifest.short_name) problems.push('manifest needs name or short_name'); if (!manifest.start_url) problems.push('manifest needs start_url'); if (!['standalone', 'fullscreen', 'minimal-ui'].includes(manifest.display)) problems.push('display must not be browser'); const sizes = (manifest.icons ?? []).flatMap((i) => (i.sizes ?? '').split(' ')); if (!sizes.includes('192x192') || !sizes.includes('512x512')) problems.push('icons need 192x192 and 512x512'); } } if (!('serviceWorker' in navigator)) problems.push('no service worker support: offline page unavailable'); return problems;}
const problems = await installabilityReport();if (problems.length && 'onbeforeinstallprompt' in window) { console.warn('Chromium will not fire beforeinstallprompt:', problems); // fix the manifest} else if (!('onbeforeinstallprompt' in window)) { showMenuInstructions(); // Safari and Firefox install from their menus regardless of the list}The service worker line is informational: since Chrome 112 its absence no longer blocks installation, but it does mean the installed app shows Chrome’s default offline page instead of the site’s own.
A manifest that satisfies every browser’s install path
Section titled “A manifest that satisfies every browser’s install path”The manifest below meets the Chromium list; Safari and Firefox read name, icons, and display from it but do not require them.
{ "name": "Field Notes", "short_name": "Notes", "id": "/notes/", "start_url": "/notes/?source=pwa", "scope": "/notes/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#1f3a5f", "icons": [ { "src": "/notes/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { "src": "/notes/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { "src": "/notes/icons/maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } ]}Keeping the any and maskable purposes on separate icon entries matters for the Chrome dialog, which needs an icon whose purpose includes any; a single entry with "purpose": "any maskable" passes the check but renders the same bitmap in both contexts.
See also
Section titled “See also”- Changes to the installability criteria (developer.chrome.com)
- What does it take to be installable? (web.dev)
- WebKit features in Safari 26.0 (webkit.org)
- beforeinstallprompt event
- iOS Add to Home Screen
- Desktop installation
iconsmanifest member- Firefox
Specifications
| Specification | Status |
|---|---|
| None. | |