Customize PWA Installs with BeforeInstallPromptEvent

Progressive Web Apps (PWAs) provide native-like experiences on the web, but default browser installation banners can feel intrusive or appear before a user understands the app’s value. The BeforeInstallPromptEvent interface gives developers programmatic control over when and how the installation prompt is displayed. By intercepting this event, JavaScript can suppress the default browser banner, save the event reference, and trigger a tailored installation flow through custom user interface elements at the most effective moment.

How BeforeInstallPromptEvent Works

When a browser detects that a web application meets all PWA criteria—such as having a valid Web App Manifest, a registered Service Worker, and being served over HTTPS—it fires the beforeinstallprompt event on the global window object before showing its standard installation UI.

Developers can leverage this event in four distinct steps:

1. Intercepting the Default Prompt

By adding an event listener for beforeinstallprompt and calling event.preventDefault(), you prevent the browser from displaying its default mini-infobar or automated prompt to the user.

let deferredPrompt;

window.addEventListener('beforeinstallprompt', (e) => {
  // Prevent the default browser install banner
  e.preventDefault();
  // Stash the event so it can be triggered later
  deferredPrompt = e;
  // Update UI to notify the user they can install the PWA
  showInstallPromotion();
});

2. Displaying Custom In-App Promotion

Once the event is captured and stored, your application can reveal custom UI elements that fit natively into your design. Common patterns include an “Install App” button in the navigation bar, a banner within the settings menu, or a prompt after a user completes a meaningful action (such as placing an order or bookmarking an item).

3. Triggering the Browser Install Dialog

The saved BeforeInstallPromptEvent object contains a .prompt() method. When the user interacts with your custom install button, JavaScript invokes this method to finally show the native confirmation dialog.

installButton.addEventListener('click', async () => {
  if (!deferredPrompt) {
    return;
  }
  // Show the native install prompt
  deferredPrompt.prompt();
  
  // Wait for the user to respond to the prompt
  const { outcome } = await deferredPrompt.userChoice;
  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;
  hideInstallPromotion();
});

4. Handling the User’s Choice

The userChoice property on the BeforeInstallPromptEvent returns a Promise that resolves to an object containing the user’s decision (accepted or dismissed). This allows the application to track conversion metrics, hide promotional components, or provide contextual onboarding immediately following acceptance.

Key Considerations and Limitations