# Richer install UI

> How Chrome turns the install prompt into a sheet with the manifest description and screenshots, the screenshot size, aspect-ratio, and form_factor rules it enforces, which browsers ignore the members, and how to check a manifest against the rules.

The richer install UI is Chrome's larger install dialog that shows the manifest `description` and `screenshots` alongside the name and icon, instead of the default dialog that shows the name and icon only. Chrome 94 on Android shows it as a bottom sheet when the manifest has a `description` and at least one screenshot; Chrome 108 on desktop shows it when at least one screenshot carries `form_factor: "wide"`; Samsung Internet 17 follows Chrome for Android; Safari and Firefox parse neither member for any install UI (BCD `html.manifest.screenshots`, `html.manifest.description`).

## How it works

The dialog is chosen at prompt time, whether the prompt comes from the browser's own surface or from `BeforeInstallPromptEvent.prompt()`. Chrome reads the manifest it already fetched for installability, filters `screenshots` by the current form factor, and falls back to the default dialog when the filter leaves nothing. Nothing in the page's JavaScript can request or detect which dialog appeared; `userChoice` resolves the same way for both.

Chrome enforces these rules on each screenshot before it counts:

- Width and height between 320 px and 3840 px.
- The longer side at most 2.3 times the shorter side.
- All screenshots shown together must share one aspect ratio; the first screenshot sets it and non-matching ones are dropped.
- On desktop, only screenshots with `form_factor: "wide"` are used; on Android, screenshots with `form_factor: "narrow"` or no `form_factor` are used.
- `sizes` and `type` are read when present; a screenshot that fails to load is skipped.

Chrome also caps how many screenshots it shows and may truncate a long `description` on desktop, so the first sentence has to carry the message. The members are declarative: the installed app does not read them at runtime, and changing them only changes the next install dialog (and, after Chrome's periodic manifest update, the app's store-style details page).

:::observed
In Chrome DevTools › Application › Manifest (English UI), a manifest whose screenshots all lack `form_factor: "wide"` shows the warning `Richer PWA Install UI won't be available on desktop. Please add at least one screenshot with the form_factor set to wide.` under the "Installability" heading, and a manifest with only wide screenshots shows the mobile counterpart asking for a screenshot whose `form_factor` is not `wide`; the desktop rule is the one described in Chrome's richer-install-UI-for-desktop announcement.
:::

## Examples

The manifest excerpt feeds both dialogs; the script checks the rules that DevTools reports only after the fact.

### One manifest that satisfies both the Android and the desktop dialog

The narrow screenshots share a 9:16 ratio and serve Android; the wide one serves desktop. Each has `sizes` so Chrome need not decode the image to apply the ratio rule.

```json
{
  "name": "Meal Planner",
  "description": "Plan a week of meals, build the shopping list, and cook offline.",
  "screenshots": [
    { "src": "/screenshots/week.png", "sizes": "1080x1920", "type": "image/png",
      "form_factor": "narrow", "label": "Weekly plan" },
    { "src": "/screenshots/list.png", "sizes": "1080x1920", "type": "image/png",
      "form_factor": "narrow", "label": "Shopping list" },
    { "src": "/screenshots/desktop.png", "sizes": "1920x1080", "type": "image/png",
      "form_factor": "wide", "label": "Weekly plan on a large screen" }
  ]
}
```

Dropping the `wide` entry keeps the Android sheet and silently returns desktop users to the default dialog; mixing 1080×1920 and 1080×2340 narrow screenshots keeps only the ones matching the first entry's ratio.

### Checking a manifest against the rules before deploying

There is no runtime API to detect the richer dialog, so the useful check is a pre-deploy script that reports the same conditions Chrome applies. Run it in Node against the built manifest; it needs no browser.

```js
import { readFile } from 'node:fs/promises';

const manifest = JSON.parse(await readFile('dist/manifest.webmanifest', 'utf8'));
const shots = manifest.screenshots ?? [];
const problems = [];

if (!manifest.description) problems.push('description missing: Android shows the default dialog');
if (!shots.some((s) => s.form_factor === 'wide')) problems.push('no wide screenshot: desktop shows the default dialog');
for (const s of shots) {
  const [w, h] = (s.sizes ?? '').split('x').map(Number);
  if (!w || !h) { problems.push(`${s.src}: add sizes so the ratio rule can be checked`); continue; }
  if (w < 320 || h < 320 || w > 3840 || h > 3840) problems.push(`${s.src}: ${w}x${h} outside 320-3840`);
  if (Math.max(w, h) / Math.min(w, h) > 2.3) problems.push(`${s.src}: aspect ratio above 2.3`);
}
console.log(problems.length ? problems.join('\n') : 'screenshots pass the richer install UI rules');
```

A manifest that passes this script can still fall back to the default dialog if an image returns a non-image response at prompt time, so the screenshot URLs belong in the same deploy as the manifest.

## See also

- [Richer install UI for desktop](https://developer.chrome.com/blog/richer-install-ui-desktop) (developer.chrome.com)
- [Web App Manifest Application Information: screenshots member](https://w3c.github.io/manifest-app-info/#screenshots-member) (w3c.github.io)
- [`screenshots` manifest member](/reference/manifest/screenshots/)
- [`description` manifest member](/reference/manifest/description/)
- [beforeinstallprompt event](/reference/installation/install-prompt/)
- [Install prompt UX](/reference/installation/install-prompt-ux/)