Quick answer: Chrome only offers installation when the page is served over HTTPS, links a valid web app manifest (name, icons of 192 and 512 px, start_url, display of standalone, fullscreen or minimal-ui) and is not already installed. beforeinstallprompt does not fire inside iframes (itch.io, game portals) or in Safari and Firefox. DevTools > Application > Manifest lists what is missing.
You added a manifest so players can install your browser game, and the install button never appears. Chrome is strict and quiet about installability; fortunately it also tells you exactly what is wrong if you know where to look.
Check DevTools first
Open the game in Chrome, then DevTools > Application > Manifest. The Installability section lists every failed requirement. Fix those before anything else.
Manifest requirements
{
"name": "My Game",
"short_name": "MyGame",
"start_url": "/index.html",
"display": "fullscreen",
"background_color": "#000000",
"icons": [
{ "src": "icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "icon-512.png", "sizes": "512x512", "type": "image/png" }
]
}
Link it with <link rel="manifest" href="manifest.json">. Common mistakes: icon files that 404, sizes that do not match the real image, start_url outside the manifest's scope, and serving the manifest with the wrong content type.
HTTPS
Installation requires a secure context. localhost counts, so local testing works; a LAN IP over plain HTTP does not.
Service worker
Older Chrome versions required a service worker with a fetch handler. Current Chrome no longer needs one to be installable, but you still want one for offline play and caching large game data. Godot's web export has a Progressive Web App option that generates the manifest and service worker for you; Construct 3 has a similar export option.
Handling beforeinstallprompt
The event fires once per page load, and calling prompt() must happen in response to a user gesture:
let deferredPrompt = null;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault(); // keep it for later
deferredPrompt = e;
installButton.hidden = false;
});
installButton.addEventListener('click', async () => {
if (!deferredPrompt) return;
deferredPrompt.prompt();
await deferredPrompt.userChoice;
deferredPrompt = null; // it can only be used once
installButton.hidden = true;
});
Register the listener early (before your game engine loads), or the event may fire before you are listening.
Why it still does not fire
- The game runs in an iframe. On itch.io, Newgrounds, CrazyGames and similar hosts the game is embedded from another origin; install prompts are not offered for iframes. Host a standalone page for the installable version.
- It is already installed. Uninstall it from
chrome://appsor the app's own menu to test again. - The user dismissed it. Chrome may suppress the prompt for a while afterwards.
- Other browsers. Safari and Firefox do not support
beforeinstallprompt. On iOS, players install through Share > Add to Home Screen; show them instructions instead of a button.
Testing tip
Chrome's install icon in the address bar appears whenever the page is installable, independent of your button. If the icon appears but your button does not, your event handling is the problem; if neither appears, it is the manifest or hosting.