Manifest · Manifest member
id manifest member
Published
id is the string that identifies the web application. Before the member existed, each
browser derived identity from something else, usually start_url, so changing the launch URL
made the manifest describe a new app and a later install sat beside the old one. With id
set, the identity and the launch URL are separate values: start_url can move, the identity
stays.
Chrome 96, Edge 96, Samsung Internet 17.0, Safari on iOS 16.4, and Safari 17 on macOS process
the member (BCD html.manifest.id). Firefox 157 parses it without effect, because Firefox on
desktop installs no web apps from the manifest. Browsers that ignore id keep their previous
identity rule, so adding the member never breaks an install elsewhere.
Member
Section titled “Member”- Type: string, parsed as a URL against the origin of
start_url. A value that resolves to another origin is rejected; Chromium logsproperty 'id' ignored, should be same origin as document.and falls back to the default. - Default: the resolved
start_url. An absent, empty, or unparsableidcouples the identity to the launch URL, which is the situation the member exists to avoid. - Example value:
"/?homescreen=1", which for an app onhttps://example.comresolves tohttps://example.com/?homescreen=1.
The resolved value is compared with the identity of every installed app when a manifest is
processed. A match means “update this app”; no match means “a new app”. Because the comparison
is on the full resolved URL, "/" and "/?v=2" are different apps, and a value should be
chosen once and left alone. Chromium’s update check runs once a day for an installed app and
applies most field changes only after every window of the app closes (web.dev, “How Chrome
handles updates to the web app manifest”); a changed start_url is accepted as an update only
when id is present and unchanged.
navigator.getInstalledRelatedApps() does not read id: it reports related native apps and,
on Chrome 80+, a PWA listed in related_applications with platform: "webapp", matched by
manifest URL rather than by id.
Examples
Section titled “Examples”The manifests below show the value to pick before the first release, the change id makes
safe, and how to recover an identity for an app that shipped without one.
Fixing the identity before the first install
Section titled “Fixing the identity before the first install”A short root-relative path is enough; the member resolves against the origin of start_url,
so a scheme and host add nothing. The launch URL carries an analytics parameter that may
change later without touching the identity.
{ "name": "Ledger", "id": "/", "start_url": "/app/?source=pwa", "scope": "/app/", "display": "standalone"}Chrome 96+ and Safari 16.4+ record the identity as https://example.com/; a later manifest
with "start_url": "/dashboard/?source=pwa" updates the installed app instead of creating a
second one.
Moving start_url without a duplicate install
Section titled “Moving start_url without a duplicate install”With the identity fixed, a redesign that changes the launch path only edits start_url and
scope. The identity line is the one that must not move.
{ "name": "Ledger", "id": "/", "start_url": "/home/", "scope": "/", "display": "standalone"}On Chrome 155 the installed app picks up the new start_url at the next daily manifest check
and applies it after the last app window closes; on a browser that ignores id, the same
change still works as long as that browser never keyed the identity on start_url.
Adopting id for an app that shipped without one
Section titled “Adopting id for an app that shipped without one”An app installed before id was declared has the identity Chromium computed from its
start_url. To keep those installs, set id to exactly the computed value shown in DevTools;
the script below reads the manifest the page links and prints the value to copy, falling back
to a note when the manifest fetch fails.
async function suggestedId() { const link = document.querySelector('link[rel="manifest"]'); if (!link || !('fetch' in window)) return null; // Nothing to inspect. const manifest = await fetch(link.href).then((r) => r.json()).catch(() => null); if (!manifest) return null; if (manifest.id) return new URL(manifest.id, location.origin).href; return new URL(manifest.start_url ?? '/', link.href).href; // Chromium's default identity.}
const id = await suggestedId();console.log(id ? `Set "id" to ${new URL(id).pathname + new URL(id).search}` : 'Manifest not readable');For "start_url": "/app/?source=pwa" the printed value is /app/?source=pwa; declaring that
string as id freezes the identity existing users already have, after which start_url is
free to change.
See also
Section titled “See also”- start_url manifest member
- How installed PWAs pick up manifest changes
- The N+1 install problem: one PWA, multiple independent installs
- getInstalledRelatedApps(): detecting an installed native or PWA counterpart
- Web Application Manifest: id member (w3.org)
- Uniquely identifying PWAs with the web app manifest id property (developer.chrome.com)
- WebKit Features in Safari 16.4 (webkit.org)
Specifications
| Specification | Status |
|---|---|
| manifest: id | W3C |
| Web Application Manifest: start_url member | W3C |
- Legend
- Yes
- Partial
- Flag
- No
- Unknown
| Browser / Platform | Support | Versions | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Desktop) | Yes | 96 | high | source | — |
| Chrome (Android) | Yes | 96 | high | source | 1 |
| Edge (Desktop) | Yes | 96 | high | source | 2 |
| Firefox (Desktop) | No | — | high | source | 3 |
| Firefox (Android) | No | — | high | source | 4 |
| Safari (macOS) | Yes | 17 | high | source | — |
| Safari (iOS) | Yes | 16.4 | high | source | — |
| Samsung Internet | Yes | 17.0 | high | source | 5 |
| WebView (Android) | Yes | 96 | high | source | 6 |
- Derived by browser-compat-data mirroring from Chrome.
- Derived by browser-compat-data mirroring from Chrome.
- The property parses, but has no effect.
- No Firefox for Android support is recorded in browser-compat-data.
- Derived by browser-compat-data mirroring from Chrome Android.
- Derived by browser-compat-data mirroring from Chrome Android.