Skip to content

The Install Prompt

When a browser decides your PWA is installable (valid manifest + registered service worker + HTTPS), it fires the beforeinstallprompt event on window. By default the browser would show its own install badge or prompt immediately — but you can intercept that event, hide the default UI, and show your own install button at the right moment.

let deferredPrompt = null;
window.addEventListener('beforeinstallprompt', (event) => {
// Prevent the browser from showing its mini-infobar
event.preventDefault();
// Save the event so we can trigger it later
deferredPrompt = event;
// Show your own install button
document.getElementById('install-btn').hidden = false;
});

Step 2 — trigger the prompt from a user gesture

Section titled “Step 2 — trigger the prompt from a user gesture”

You must call deferredPrompt.prompt() from inside a user-initiated handler (a click). Calling it outside a user gesture will throw.

document.getElementById('install-btn').addEventListener('click', async () => {
if (!deferredPrompt) return;
// Show the browser's install dialog
deferredPrompt.prompt();
// Wait for the user's choice
const { outcome } = await deferredPrompt.userChoice;
console.log('User choice:', outcome); // 'accepted' or 'dismissed'
deferredPrompt = null;
document.getElementById('install-btn').hidden = true;
});

The appinstalled event fires after the user confirms the install:

window.addEventListener('appinstalled', () => {
console.log('PWA installed successfully');
deferredPrompt = null;
});

Safari on iOS does not fire beforeinstallprompt. There is no programmatic way to trigger the install dialog. Your only option is to show an instructional banner that guides the user manually:

  1. Tap the Share button in Safari.
  2. Scroll down and tap Add to Home Screen.

Detect iOS to show the right guidance:

const isIos = /iphone|ipad|ipod/i.test(navigator.userAgent);
const isInStandaloneMode = window.matchMedia('(display-mode: standalone)').matches;
if (isIos && !isInStandaloneMode) {
document.getElementById('ios-hint').hidden = false;
}

The playground below wires up a complete install-button flow. Because StackBlitz runs inside an iframe, the beforeinstallprompt event will not fire — but you can inspect the full code and run it on a real domain to test.

Runs a real service worker + manifest in your browser.
What must you call on the beforeinstallprompt event to suppress the browser default install UI?
From where must you call deferredPrompt.prompt()?
Which event fires after the user successfully installs the PWA?
How must iOS users install a PWA when beforeinstallprompt is not available?