How to provide your own in-app install experience

Many browsers let you enable and promote the installation of your Progressive Web App (PWA) directly within its user interface. Installation (sometimes formerly referred to as Add to Home Screen) lets users install your PWA on their mobile or desktop device. Installing a PWA adds it to a user's launcher so it can run like any other installed app.

In addition to thebrowser-provided install experience, you can provide your own custom install flow directly within your app.

Install App button provided in the Spotify PWA
The "Install App" button provided in the Spotify PWA.

When considering whether to promote installation, consider how users typically use your PWA. For example, if there's a set of users who use your PWA multiple times in a week, these users might benefit from the added convenience of launching your app from a phone home screen or from the Start menu in a desktop operating system. Some productivity and entertainment applications also benefit from the extra screen space created by removing the browser toolbars from the window in installedstandaloneorminimal-uimodes.

Prerequisites

Before getting started, make sure your PWA meets the installability requirements,which typically include having aweb app manifest.

Promote installation

To show that your Progressive Web App is installable, and to provide a custom in-app install flow:

  1. Listen for thebeforeinstallpromptevent.
  2. Save thebeforeinstallpromptevent so it can trigger the install flow later.
  3. Alert the user that your PWA is installable, and provide a button or other element to start the in-app installation flow.

Listen for thebeforeinstallpromptevent

If your Progressive Web App meets the requiredinstallation criteria, the browser fires abeforeinstallpromptevent. Save a reference to the event, and update your user interface to indicate that the user can install your PWA.

// Initialize deferredPrompt for use later to show browser install prompt.
let deferredPrompt;

window.addEventListener('beforeinstallprompt', (e) => {
// Prevent the mini-infobar from appearing on mobile
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
// Update UI notify the user they can install the PWA
showInstallPromotion();
// Optionally, send analytics event that PWA install promo was shown.
console.log(`'beforeinstallprompt' event was fired.`);
});

In-app installation flow

To provide in-app installation, provide a button or other interface element that a user can click or tap to install your app. When the element is clicked or tapped, callprompt()on the savedbeforeinstallpromptevent (stored in the deferredPromptvariable). It shows the user a modal install dialog, asking them to confirm that they want to install your PWA.

buttonInstall.addEventListener('click', async () => {
// Hide the app provided install promotion
hideInstallPromotion();
// Show the install prompt
deferredPrompt.prompt();
// Wait for the user to respond to the prompt
const { outcome } = await deferredPrompt.userChoice;
// Optionally, send analytics event with outcome of user choice
console.log(`User response to the install prompt: ${outcome}`);
// We've used the prompt and can't use it again, throw it away
deferredPrompt = null;
});

TheuserChoiceproperty is a promise that resolves with the user's choice. You can only callprompt()on the deferred event once. If the user dismisses it, you'll need to wait until thebeforeinstallpromptevent fires again, typically immediately after theuserChoiceproperty has resolved.

Detect when the PWA was successfully installed

You can use theuserChoiceproperty to determine whether the user installed your app from within your user interface. But, if the user installs your PWA from the address bar or another browser component,userChoicewon't help. Instead, you should listen for theappinstalledevent, which fires whenever your PWA is installed, no matter what mechanism is used to install it.

window.addEventListener('appinstalled', () => {
// Hide the app-provided install promotion
hideInstallPromotion();
// Clear the deferredPrompt so it can be garbage collected
deferredPrompt = null;
// Optionally, send analytics event to indicate successful install
console.log('PWA was installed');
});

Detect how the PWA was launched

The CSSdisplay-modemedia query indicates how the PWA was launched, either in a browser tab, or as an installed PWA. This makes it possible to apply different styles depending on how the app was launched. For example, you can configure it to always hide the install button and provide a back button when launched as an installed PWA.

Track how the PWA was launched

To track how users launch your PWA, usematchMedia()to test the display-modemedia query. Safari on iOS doesn't support this yet, so you must instead checknavigator.standalone,which returns a boolean indicating whether the browser is running in standalone mode.

function getPWADisplayMode() {
const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
if (document.referrer.startsWith('android-app://')) {
return 'twa';
} else if (navigator.standalone || isStandalone) {
return 'standalone';
}
return 'browser';
}

Track when the display mode changes

To track if the user changes betweenstandalone,andbrowser tab,listen for changes to thedisplay-modemedia query.

window.matchMedia('(display-mode: standalone)').addEventListener('change', (evt) => {
let displayMode = 'browser';
if (evt.matches) {
displayMode = 'standalone';
}
// Log display mode change to analytics
console.log('DISPLAY_MODE_CHANGED', displayMode);
});

Update UI based on the current display mode

To apply a different background color for a PWA when launched as an installed PWA, use conditional CSS:

@media all and (display-mode: standalone) {
body {
background-color: yellow;
}
}

Update your app's icon and name

What if you need to update your app name, or provide new icons? Check outHow Chrome handles updates to the web app manifest to see when and how are those changes are reflected in Chrome.