# related_applications and prefer_related_applications

> related_applications lists a PWA's native or web counterparts by platform, url, and id; prefer_related_applications makes Chrome on Android offer one instead.

`related_applications` is an array of objects, each naming a `platform` and a store `url` or
`id`, that points at the native or web counterparts of this web app. `prefer_related_applications`
is a boolean that tells the browser to promote one of those counterparts instead of offering to
install the web app itself. The same array is what `navigator.getInstalledRelatedApps()`
reads at runtime.

Chrome 44 on Android, Samsung Internet 4.0, Android WebView 44, and Edge 17 process both
members (BCD `html.manifest.related_applications`). Chrome on desktop reads the array for
`getInstalledRelatedApps()` on Windows but does not act on `prefer_related_applications`
beyond refusing to install when it is `true`. Firefox 157 parses the members and does
nothing; Safari 27 does not read them.

## Member

- **Type**: `related_applications` is an array of objects with `platform` (string, required),
  `url` (string), `id` (string), `min_version` (string), and `fingerprints` (array of
  `{ type, value }`). At least one of `url` or `id` is required. `prefer_related_applications`
  is a boolean.
- **Allowed `platform` values**: `play` (Google Play), `itunes` (App Store), `windows`
  (Microsoft Store), `chrome_web_store`, `f-droid`, `amazon`, and `webapp` (a PWA identified by
  its manifest `id`).
- **Default**: an empty array, and `false`. Omitting `prefer_related_applications` is the same
  as writing `false`.
- **Example value**: `[{ "platform": "play", "id": "com.example.app" }]` with
  `"prefer_related_applications": true`.

Chromium validates each entry on its own: a missing platform logs `'platform' is a required
field, related application ignored.` and an entry with neither `url` nor `id` logs `one of 'url'
or 'id' is required, related application ignored.`; the remaining entries survive. The relation
is one-way: the native app is not required to point back at the web app, except for
`getInstalledRelatedApps()`, which on Android verifies the Play app's Digital Asset Links
statement before reporting it installed.

`prefer_related_applications: true` has two effects in Chromium. On Chrome for Android (beta
and stable channels only) the install prompt offers the first `play` entry instead of the web
app. Everywhere else it blocks installability: the installability check reports `The manifest
specifies prefer_related_applications: true`, and on other channels or platforms also
`Manifest 'prefer_related_applications' is only supported on Chrome Beta and Stable channels on
Android.`

:::observed
Chrome 155 on macOS 26 (English UI), DevTools > Application > Manifest: with
`"prefer_related_applications": true` in the manifest the **Installability** section reads
`The manifest specifies prefer_related_applications: true` and the omnibox install icon is
absent. An entry written as `{ "url": "https://play.google.com/store/apps/details?id=com.example.app" }`
with no `platform` adds `'platform' is a required field, related application ignored.` under
**Errors and warnings**.
:::

## Examples

The first example is the manifest both members live in; the other two are what a page does
with the array at runtime.

### Pointing at a Play Store app and the Microsoft Store listing

A web app with native siblings lists both. The Play entry carries the package name as `id`
and the store page as `url`; the Microsoft Store entry has only a `url`. Without
`prefer_related_applications` the web app stays installable and the list exists only for
`getInstalledRelatedApps()`.

```json
{
  "name": "Trail Maps",
  "start_url": "/",
  "display": "standalone",
  "related_applications": [
    {
      "platform": "play",
      "url": "https://play.google.com/store/apps/details?id=com.example.trailmaps",
      "id": "com.example.trailmaps"
    },
    {
      "platform": "windows",
      "url": "https://apps.microsoft.com/store/detail/trail-maps/9WZDNCRFHVJL"
    }
  ]
}
```

Add `"prefer_related_applications": true` only for an app that must not be installed as a PWA
on Android; it removes the PWA install path on every other Chromium platform at the same time.

### Hiding the install button when the native app is present

`navigator.getInstalledRelatedApps()` resolves with the entries from the array that are
installed on the device (Chrome 80 on Android; Chrome 85 on Windows for `windows` entries). It
works only from the top-level frame of the app's own origin, and the Play app must publish a
Digital Asset Links statement for the origin. The fallback keeps the button for browsers without
the method.

```js
async function nativeAppInstalled() {
  if (typeof navigator.getInstalledRelatedApps !== 'function') {
    return false; // Safari, Firefox, Chrome iOS: show the web install path
  }
  try {
    const apps = await navigator.getInstalledRelatedApps();
    return apps.some((app) => app.platform === 'play' || app.platform === 'windows');
  } catch {
    return false; // not top-level, or the asset links did not verify
  }
}

nativeAppInstalled().then((installed) => {
  document.querySelector('#install-web-app').hidden = installed;
});
```

The resolved objects carry `platform`, `url`, `id`, and `version`, so the same call can also
detect an outdated native app when `min_version` is set.

### Detecting whether the PWA itself is already installed

A `webapp` entry whose `id` equals the manifest's own `id` lets the site, opened in a browser
tab, ask whether its PWA is installed on this device. Chrome 85 and later resolve it; other
browsers fall through to the display-mode check, which only knows about the current window.

```json
{
  "id": "/",
  "related_applications": [
    { "platform": "webapp", "url": "https://trailmaps.example/manifest.webmanifest" }
  ]
}
```

```js
async function pwaInstalled() {
  if (matchMedia('(display-mode: standalone)').matches) return true; // running as the app
  if (typeof navigator.getInstalledRelatedApps !== 'function') return false;
  const apps = await navigator.getInstalledRelatedApps();
  return apps.some((app) => app.platform === 'webapp');
}
```

Use the answer to replace an "Install" call to action with "Open app"; the `webapp` entry has
no effect on installability or on the install prompt.

## See also

- [getInstalledRelatedApps(): detecting an installed native or PWA counterpart](/reference/installation/get-installed-related-apps/)
- [id manifest member](/reference/manifest/id/)
- [Installability criteria: what makes a PWA installable](/reference/installation/installability-criteria/)
- [Trusted Web Activity (TWA): PWAs in the Play Store](/reference/installation/twa/)
- [Manifest Incubations: related_applications member](https://wicg.github.io/manifest-incubations/#related_applications-member) (wicg.github.io)
- [Navigator: getInstalledRelatedApps() method](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps) (developer.mozilla.org)