Skip to content

Concept in Installation

Install banners and beforeinstallprompt

Published Updated

Limited availabilityNot supported in Firefox (Desktop), Firefox (Android), Safari (macOS), Safari (iOS)WICG draft

The beforeinstallprompt event supplies Chromium pages with a one-use object that can open the browser’s install prompt from an application-provided banner or button. A page can defer that prompt, but it should keep its own install control hidden until the event proves that this path is available.

BCD api.BeforeInstallPromptEvent records Chrome support from 44 and Samsung Internet Android support from 5.0; Edge is recorded as "mirror". The compatibility data presents the site targets. BCD records no support in Firefox or Safari. Its api.BeforeInstallPromptEvent.prompt entry records Chrome 44 through 75 as a partial implementation whose promise resolves without a value; the result object is recorded from Chrome 76. The event is non-standard and absent in Firefox and Safari, so an install banner needs an explicit no-event path.

Listen on window, call preventDefault(), save the event, and reveal the install control. Call prompt() inside the install control’s click handler. MDN states that prompt() requires a user-action handler and can be called once on each BeforeInstallPromptEvent. Clear the saved event after the prompt flow settles. Read userChoice when the code must cover Chrome 44 through 75 because those versions do not return a result object from prompt().

State Banner action Evidence available to the page
No event has fired Keep the programmatic install button hidden The page does not have a prompt object
beforeinstallprompt fires Save the event and reveal the button The browser determined that the app can use this install flow
prompt() settles Hide the button and discard the event userChoice supplies "accepted" or "dismissed"; prompt() itself returns that result object from Chrome 76
appinstalled fires Hide install promotion and clear stored state The browser reports that the app was installed
The event API is absent Offer browser-specific help without calling prompt() BCD records no BeforeInstallPromptEvent in Firefox or Safari

preventDefault() controls the event’s default install promotion on supporting browsers. Chrome’s mini-infobar update says Chrome 76 began honoring that call to suppress the mini-infobar. The page’s banner does not install the app by itself; it gives the user a control that later calls the browser-owned prompt() method.

MDN defines an "accepted" outcome as the user installing the application. Listen for appinstalled too, so promotion is removed when installation completes through browser UI outside the saved event flow. The MDN install guide also clears the stored event after calling prompt() because that event cannot be reused.

Treat the event object and the banner as one piece of state. Navigation discards the JavaScript object, so a later document waits for its own event. A dismissed prompt also ends that object’s useful life. The MDN event example hides the button and resets the saved reference after prompt() returns; the appinstalled example performs the same cleanup when installation finishes through another browser surface. These transitions prevent a visible control from pointing at a missing or consumed event.

The browser remains responsible for confirmation. The page can choose when to reveal its own promotion and when to call prompt(), while userChoice reports the user’s decision in browser UI across the recorded Chrome support range. Keep application analytics downstream of that result, and do not replace browser confirmation with a page-styled success state. When the outcome is "dismissed", remove the banner for that event and let a future beforeinstallprompt event create fresh state.

BCD records version_added: false for Firefox and Safari. A feature test can select explanatory copy, but it cannot manufacture a browser prompt. Keep the fallback short, and let the browser’s own menu or install surface remain available.

Goal Chromium event path No-event path
Show an in-page install action Reveal it after beforeinstallprompt Keep it hidden
Start browser confirmation Call the saved event’s prompt() from a click Explain where the browser exposes installation
Remove stale promotion Handle appinstalled and clear the event after use Recheck installed display mode when the page loads
Handle dismissal Hide the action and wait for another event No prompt outcome exists to inspect

The banner starts hidden in the markup. JavaScript reveals it only after the browser hands the page a valid event object.

Test for the event handler property before waiting for beforeinstallprompt. The supported branch keeps the install button hidden until the event fires; the fallback branch reveals browser-install instructions instead. BCD records no BeforeInstallPromptEvent support in Firefox or Safari.

<button data-event-install type="button" hidden>Install</button>
<p data-event-fallback hidden>Use your browser's install command if it provides one.</p>
<script>
var installButton = document.querySelector('[data-event-install]');
var installFallback = document.querySelector('[data-event-fallback]');
if ('onbeforeinstallprompt' in window) {
window.addEventListener('beforeinstallprompt', function (event) {
event.preventDefault();
installButton.hidden = false;
});
} else {
installButton.hidden = true;
installFallback.hidden = false;
}
</script>

The click handler in the next example supplies the supported branch’s prompt behavior.

Deferring the prompt behind an install banner

Section titled “Deferring the prompt behind an install banner”

This complete HTML example preserves the browser event until a click, reads the broadly supported userChoice promise instead of dereferencing the return value from prompt(), and clears the banner when appinstalled fires.

<aside data-install-banner hidden>
<p>Install this app for quicker access.</p>
<button type="button">Install</button>
</aside>
<p><output data-install-status aria-live="polite"></output></p>
<script>
(function () {
var installEvent = null;
var banner = document.querySelector('[data-install-banner]');
var status = document.querySelector('[data-install-status]');
var installButton = banner && banner.querySelector('button');
if (!banner || !status || !installButton) return;
window.addEventListener('beforeinstallprompt', function (event) {
event.preventDefault();
installEvent = event;
installButton.disabled = false;
banner.hidden = false;
});
installButton.addEventListener('click', function () {
if (!installEvent) return;
var pendingEvent = installEvent;
installEvent = null;
installButton.disabled = true;
pendingEvent.prompt().then(function () {
return pendingEvent.userChoice;
}).then(function (choice) {
status.textContent = 'Install prompt result: ' + choice.outcome;
banner.hidden = true;
}, function (error) {
status.textContent = 'The install prompt could not open: ' + error.name;
banner.hidden = true;
});
});
window.addEventListener('appinstalled', function () {
installEvent = null;
banner.hidden = true;
status.textContent = 'The app was installed.';
});
}());
</script>

The button never appears merely because the property exists. It appears when the event fires, which keeps the UI aligned with the browser’s decision for that visit.

The failure path chooses instructions instead of waiting for an event that BCD does not record in Firefox or Safari. Installed display mode hides the message after the app opens in a standalone window.

<p data-install-help hidden>
Use your browser's install command if it provides one.
</p>
<p data-installed-state hidden>This app is already open as an installed app.</p>
<script>
var help = document.querySelector('[data-install-help]');
var installedState = document.querySelector('[data-installed-state]');
var installed = window.matchMedia('(display-mode: standalone)').matches;
if (help && installedState) {
installedState.hidden = !installed;
help.hidden = installed || 'onbeforeinstallprompt' in window;
}
</script>

The fallback does not call prompt() because no BeforeInstallPromptEvent exists on this branch. Adapt its copy to the browser UI you have tested. The install prompt compatibility data supplies the engine-level support split, while the iOS install API lab note records measured iOS behavior separately.

This correction aligns the description of an "accepted" outcome with the cited sources. MDN’s prompt() reference defines "accepted" as the user installing the application, and web.dev’s in-app install guidance says userChoice reports whether the user installed through the in-app interface. The original publishedAt date remains unchanged.

Specifications

SpecificationStatus
Install Prompt (beforeinstallprompt)WICG draft
  • Legend
  • Yes
  • Partial
  • Flag
  • No
  • Unknown
Browser / PlatformSupportVersionsConfidenceSourceNotes
Chrome (Desktop)#Yes44highsource—
Chrome (Android)#Yes44highsource1
Edge (Desktop)#Yes79highsource2
Firefox (Desktop)#No—highsource3
Firefox (Android)#No—highsource45
Safari (macOS)#No—highsource6
Safari (iOS)#No—highsource78
Samsung Internet#Yes5.0highsource—
WebView (Android)#Yes44highsource9
  1. Derived by browser-compat-data mirroring from Chrome.
  2. Derived by browser-compat-data mirroring from Chrome.
  3. No Firefox support is recorded in browser-compat-data.
  4. No Firefox for Android support is recorded in browser-compat-data.
  5. Derived by browser-compat-data mirroring from Firefox.
  6. No Safari support is recorded in browser-compat-data.
  7. No Safari on iOS support is recorded in browser-compat-data.
  8. Derived by browser-compat-data mirroring from Safari.
  9. Derived by browser-compat-data mirroring from Chrome Android.

Source data: /compatibility/install-prompt.json · Global usage: 75 % (StatCounter 2026-09, CC BY-SA 4.0)

Source: spec · MDN · Last verified 2026-10-20 · Confidence: high (computed from sources)