Skip to content

Web App Manifest Cheat Sheet

This page condenses the web app manifest into one scannable reference: every member with its JSON type, default, effect on installability and browser support, a minimal and a fully annotated complete manifest, the legacy <meta> and <link> tags each member replaces, and every enumerated value you can type into the file. Use it when you are writing or reviewing a manifest and need the exact spelling, shape or constraint of a member right now. The full processing rules, error messages and gotchas behind each row live in the Members Reference; this page links there instead of repeating them.

Key takeaways

  • For Chromium's install criteria you need name or short_name, a parsed start_url, an effective display mode (the first display_override entry Chromium recognizes, otherwise display) of standalone, fullscreen or minimal-ui, or window-controls-overlay or tabbed when it comes from display_override, and one any-purpose PNG, SVG or WebP icon of at least 144 px with sizes declared. Safari and Firefox have no manifest requirements at all.
  • Always set id, start_url and scope explicitly, with root-relative paths. id is permanent: a different id is a different app.
  • URL members resolve against the manifest URL; id resolves against the origin of start_url. Every navigational URL must be same-origin and usually inside scope.
  • Invalid values are ignored, never coerced: "false" is not false, and window-controls-overlay in display is dropped, which leaves the manifest without a valid display and not installable.
  • Keep <link rel="apple-touch-icon"> and <meta name="theme-color">: Safari prefers the former over manifest icons, and the latter is the only working dark-mode theme color today.
  • Integration members (share_target, file_handlers, protocol_handlers, launch_handler, scope_extensions) are Chromium-only; Safari and Firefox ignore them safely.

Serving and linking the manifest

Item Value Why it matters
File name Anything; app.webmanifest or manifest.webmanifest by convention Browsers only follow the <link>; the name has no meaning
MIME type application/manifest+json (any JSON MIME type is acceptable) Chromium does not check it, but CDNs and validators do
Link element <link rel="manifest" href="/app.webmanifest"> in the <head> of every page that should be installable A page without the link is not installable from that page
Credentials Fetched in CORS mode without cookies; add crossorigin="use-credentials" only if the manifest URL requires authentication A cookie-protected manifest returns a login page that fails to parse
Cross-origin manifest Needs Access-Control-Allow-Origin; relative URLs inside resolve against the manifest's origin A CDN-hosted manifest breaks start_url, scope and every in-scope URL member
CSP manifest-src (falls back to default-src) must allow the manifest URL A blocked manifest fetch looks like "no manifest"
Caching Short or revalidated cache lifetime (Cache-Control: no-cache or a few minutes) Browsers re-fetch it to detect updates
JSON Strict JSON: no comments, no trailing commas A syntax error yields an empty manifest and the page is not installable
One app per manifest Keep id constant across every variant (locale, tenant, environment) A document ignores a later manifest with a different id
index.html (head excerpt)
<link rel="manifest" href="/app.webmanifest">

Serving details, dynamic manifests and the fetch pipeline are covered in Web App Manifest.

Minimal installable manifest

The smallest manifest that passes Chromium's installability check on desktop and Android, is honored by Safari on iOS, iPadOS and macOS, and by Firefox for Android:

app.webmanifest (minimal)
{
  "name": "Pocket Notes",
  "start_url": "/",
  "display": "standalone",
  "icons": [
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" }
  ]
}

It works, but it leaves the app's identity tied to start_url, has no maskable icon (Android launchers will shrink the icon onto a white disc), no theme or splash colors, and no screenshots for Chrome's richer install dialog. Add these seven lines before you ship:

app.webmanifest (minimal production)
{
  "id": "/",
  "name": "Pocket Notes",
  "short_name": "Notes",
  "start_url": "/?source=pwa",
  "scope": "/",
  "display": "standalone",
  "background_color": "#f7f4ed",
  "theme_color": "#1f6f5c",
  "icons": [
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
    { "src": "/icons/maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
  ]
}

What each browser needs before it will install or promote:

Browser Manifest requirement What happens without it
Chrome, Edge, Samsung Internet (Chromium) name or short_name; parsed start_url (desktop); display/display_override resolving to standalone, fullscreen or minimal-ui (or window-controls-overlay or tabbed, from display_override only); one any icon ≥ 144 px (PNG, SVG or WebP, with sizes; ≤ 1024 px on desktop); prefer_related_applications not true No beforeinstallprompt, no address-bar install icon; users can still use Install page as app
Safari on iOS and iPadOS 26+ None Every Home Screen site opens as a web app unless the user turns off Open as Web App
Safari on macOS 14+ None Add to Dock works for any site; the manifest only customizes the app
Firefox for Android None formally; a manifest improves name, icon and display Home-screen shortcut built from page metadata
Firefox on Windows (143+) None Sites can be pinned to the taskbar as web apps (Microsoft Store build from 150); no manifest-based install. Linux: disabled by default behind browser.taskbarTabs.enabled; not on macOS

The criteria, error codes and history of the service-worker requirement are explained in Installability Criteria.

All members at a glance

Legend for Install: Required means Chromium's installability check fails without it; Recommended means installation works but the installed app is visibly worse; Blocks means a value that prevents promotion; — means no effect on installability.

Core members (W3C Web Application Manifest)

Member Type Default when absent Install Acted on by Details
name string None Required (or short_name) All engines with manifest support name
short_name string None Required (or name) All engines with manifest support short_name
id string (URL) Processed start_url without fragment Recommended Chromium 96+, Safari 16.4+ (iOS), Safari 17+ (macOS) App Identity
start_url string (URL) The document URL Required (desktop Chromium) All engines with manifest support start_url
scope string (URL) Directory of start_url Recommended All engines with manifest support scope
display string browser Required (not browser) All; Safari only standalone/browser Display Modes
icons array of image resources Empty list Required All; Safari only when no apple-touch-icon Icons
theme_color string (CSS color) None Recommended Chromium, Safari 15+ (iOS), Safari 17+ (macOS), Firefox for Android theme_color
background_color string (CSS color) None Recommended Chromium, Firefox for Android background_color
orientation string None (device behavior) — Android browsers orientation
shortcuts array of shortcut items Empty list — Chromium, Safari 17.4+ (macOS) App Shortcuts
lang string (BCP 47 tag) Unknown language — Limited; fallback language for *_localized in Chrome 148+ lang
dir string auto — Limited; Chromium uses it for shortcut text dir
name_localized, short_name_localized, icons_localized object (language map) None — Chrome and Edge 148+ on desktop *_localized
color_scheme_dark object None — No browser yet color_scheme_dark

Application information members (W3C Group Note)

Member Type Default Install Acted on by Details
description string None — Chromium (install dialogs, desktop app metadata) description
screenshots array of screenshot objects Empty list Recommended (richer install UI) Chrome 94+ Android, Chrome 108+ desktop, stores Rich Install UI
categories array of strings Empty list — Safari 17.4+ on macOS (Launchpad folder names), stores categories
iarc_rating_id string None — Stores and packaging tools only iarc_rating_id

Integration and incubation members (Chromium)

Member Type Default Install Acted on by Details
display_override array of strings Empty list Its first recognized entry replaces display in the check Chromium 89+ Display Modes
launch_handler object (client_mode) { "client_mode": "auto" } — Chromium 110+ desktop (MDN also lists Chrome for Android 110 and Samsung Internet 21.0, where launchQueue is unavailable) launch_handler
share_target object None — Chrome for Android 76+, ChromeOS, Samsung Internet Web Share Target
file_handlers array Empty list — Chromium 102+ desktop File Handling
protocol_handlers array Empty list — Chromium 96+ desktop Protocol Handlers
scope_extensions array Empty list — Chrome and Edge 139+ desktop scope_extensions
migrate_from, migrate_to array, object None — Chrome 150+ desktop (same-site only) App Identity
tab_strip object New tab opens start_url, no home tab — ChromeOS (with tabbed) tab_strip
note_taking object (new_note_url) None — ChromeOS note_taking
related_applications array Empty list — Chromium (native-app promotion, getInstalledRelatedApps()) Detecting Installed Apps
prefer_related_applications boolean false Blocks when true on Android; on desktop only with a chrome_web_store entry (or play on ChromeOS with Android apps) Chromium prefer_related_applications
handle_links string None — No browser (proposal) Advanced Members

Vendor-specific and legacy members

Member Type Status Recommendation
edge_side_panel object (preferred_width) Microsoft Edge; Microsoft's documentation marks it as being deprecated Don't build new features on it
widgets array Microsoft Edge on Windows 11 Widgets Board Only if you target that surface
serviceworker object (src, scope, use_cache) Chromium, for just-in-time payment-handler installs only Not used for PWA installation; see Payments
gcm_sender_id string Obsolete (pre-VAPID Chrome push) Remove it
translations object Behind a Chromium flag; superseded by *_localized Don't use

Support matrix

Support data as of September 2026. ✅ supported (first version), ❌ not supported, ⚠️ partial (see notes below the table). For live data see MDN's manifest reference and caniuse.com.

Member Chrome / Edge desktop Chrome Android Safari macOS Safari iOS / iPadOS Firefox Android Samsung Internet
name, short_name, start_url ✅ 39 ✅ 39 ✅ 17 ✅ 11.3 ✅ 79 ✅ 4.0
scope ✅ 53 ✅ 53 ✅ 17 ✅ 11.3 ✅ 79 ✅ 6.0
id ✅ 96 ✅ 96 ✅ 17 ✅ 16.4 ❌ ✅ 17.0
display ✅ 39 ✅ 39 ⚠️ 17 ⚠️ 11.3 ✅ 47 ✅ 4.0
display_override ✅ 89 ✅ 89 ❌ ❌ ❌ ✅ 15.0
icons ✅ 39 ✅ 39 ⚠️ 17 ⚠️ 15.4 ✅ 79 ✅ 4.0
theme_color ✅ 46 ✅ 46 ✅ 17 ✅ 15 ✅ 79 ✅ 5.0
background_color ✅ 46 ✅ 46 ❌ ❌ ✅ 79 ✅ 5.0
orientation ⚠️ ✅ 39 ❌ ❌ ✅ 79 ✅ 4.0
description ✅ 88 ✅ 88 ❌ ❌ ❌ ✅ 15.0
screenshots ✅ 108 ✅ 94 ❌ ❌ ❌ ⚠️
shortcuts ✅ 96 ✅ 84 ✅ 17.4 ❌ ❌ ✅ 14.0
categories ❌ ❌ ✅ 17.4 ❌ ❌ ❌
*_localized ✅ 148 ❌ ❌ ❌ ❌ ❌
launch_handler ✅ 110 ⚠️ 110 ❌ ❌ ❌ ⚠️ 21.0
share_target ⚠️ 89 ✅ 76 ❌ ❌ ❌ ✅ 12.0
file_handlers ✅ 102 ❌ ❌ ❌ ❌ ❌
protocol_handlers ✅ 96 ❌ ❌ ❌ ❌ ❌
scope_extensions ✅ 139 ❌ ❌ ❌ ❌ ❌
migrate_from, migrate_to ✅ 150 ❌ ❌ ❌ ❌ ❌
related_applications, prefer_related_applications ⚠️ ✅ 44 ❌ ❌ ❌ ✅ 4.0
color_scheme_dark ❌ ❌ ❌ ❌ ❌ ❌
lang, dir ⚠️ ❌ ❌ ❌ ❌ ❌
tab_strip ⚠️ 126 ❌ ❌ ❌ ❌ ❌
note_taking ⚠️ 95 ❌ ❌ ❌ ❌ ❌

Notes on the ⚠️ cells: Safari honors only standalone and browser for display (fullscreen opens as standalone, minimal-ui as a browser tab before iOS 26). Safari uses manifest icons only when the page has no apple-touch-icon and only icons whose purpose is any or absent. Desktop Chromium parses orientation, but app windows don't rotate. window.launchQueue is not available on Android (Chrome or Samsung Internet, whose 21.0 entry MDN derives from Chromium 110), so launch_handler there has no script-visible effect. On desktop, share_target registers only on ChromeOS. Desktop browsers mostly ignore prefer_related_applications, except that desktop Chromium suppresses install promotion when related_applications lists a chrome_web_store entry (or a play entry on ChromeOS with Android apps); desktop Chromium also uses related_applications for getInstalledRelatedApps() (installed web apps from Chrome 140, Windows apps from 85). MDN has no data for screenshots in Samsung Internet. Chrome and Edge 85 to 95 supported shortcuts on Windows only. Chromium parses lang and dir: dir applies to shortcut text and lang is the fallback language of *_localized entries (148+). tab_strip shipped on ChromeOS only and is behind flags on other desktops; note_taking is parsed everywhere but used only on ChromeOS. Firefox on Windows (143+) reads a manifest, when present, for details such as the taskbar icon, but MDN's data records no member support there.

A fully annotated complete manifest

Every member below is valid and processed by at least one shipping browser, except where an annotation says otherwise. Click the numbered markers for the rule behind each line. The JSON stays valid when you copy it: the annotation comments are stripped from the copied text.

app.webmanifest (complete)
{
  "id": "/", // (1)!
  "name": "Acme Tasks: Team Planner", // (2)!
  "short_name": "Tasks", // (3)!
  "description": "Plan, assign and track team tasks, online or offline.", // (4)!
  "lang": "en-US", // (5)!
  "dir": "ltr", // (6)!
  "name_localized": { // (7)!
    "de": "Acme Aufgaben: Teamplaner",
    "fr": { "value": "Acme Tâches : planificateur", "lang": "fr" }
  },
  "start_url": "/?source=pwa", // (8)!
  "scope": "/", // (9)!
  "display": "standalone", // (10)!
  "display_override": ["window-controls-overlay", "standalone"], // (11)!
  "orientation": "any", // (12)!
  "theme_color": "#0b57d0", // (13)!
  "background_color": "#ffffff", // (14)!
  "color_scheme_dark": { "theme_color": "#0f172a", "background_color": "#020617" }, // (15)!
  "icons": [ // (16)!
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
    { "src": "/icons/icon.svg", "sizes": "any", "type": "image/svg+xml", "purpose": "any" },
    { "src": "/icons/maskable-192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" },
    { "src": "/icons/maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" },
    { "src": "/icons/monochrome-512.png", "sizes": "512x512", "type": "image/png", "purpose": "monochrome" }
  ],
  "screenshots": [ // (17)!
    {
      "src": "/shots/board-wide.png", "sizes": "1920x1080", "type": "image/png",
      "form_factor": "wide", "label": "Task board with To do, Doing and Done columns"
    },
    {
      "src": "/shots/today-narrow.png", "sizes": "1080x2340", "type": "image/png",
      "form_factor": "narrow", "label": "Today's tasks on a phone"
    }
  ],
  "categories": ["productivity", "business"], // (18)!
  "shortcuts": [ // (19)!
    {
      "name": "New task", "short_name": "New", "description": "Create a task in your inbox",
      "url": "/tasks/new?source=shortcut",
      "icons": [{ "src": "/icons/shortcut-new-96.png", "sizes": "96x96", "type": "image/png" }]
    },
    {
      "name": "Today", "url": "/tasks/today?source=shortcut",
      "icons": [{ "src": "/icons/shortcut-today-96.png", "sizes": "96x96", "type": "image/png" }]
    }
  ],
  "launch_handler": { "client_mode": ["focus-existing", "auto"] }, // (20)!
  "share_target": { // (21)!
    "action": "/share-target",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "title": "title", "text": "text", "url": "url",
      "files": [{ "name": "attachments", "accept": ["image/png", "image/jpeg", ".png", ".jpg", ".jpeg"] }]
    }
  },
  "file_handlers": [ // (22)!
    {
      "action": "/open-board",
      "name": "Acme task board",
      "accept": { "application/vnd.acme.board+json": [".acmeboard"] },
      "launch_type": "single-client"
    }
  ],
  "protocol_handlers": [ // (23)!
    { "protocol": "web+tasks", "url": "/open?link=%s" }
  ],
  "scope_extensions": [ // (24)!
    { "type": "origin", "origin": "https://help.acme.example" }
  ],
  "related_applications": [ // (25)!
    { "platform": "play", "id": "com.acme.tasks", "url": "https://play.google.com/store/apps/details?id=com.acme.tasks" }
  ],
  "prefer_related_applications": false // (26)!
}
  1. Identity. Resolved against the origin of start_url, so "/" means https://your.origin/. It is compared exactly (/app and /app/ are different apps) and should never change. If you shipped without id, copy the Computed App Id from DevTools (Application → Manifest) into this field instead. See App Identity & Updates.
  2. Full name. Used in install dialogs, the app list, window titles and the Android splash screen. After installation, Chromium treats name changes as security-sensitive and asks the user to approve them.
  3. Short name. Used where space is limited (home-screen label, launcher, task switcher). Launchers truncate long labels, so keep it to one short word or two.
  4. Description. Defined in the Application Information Note, not the core spec. Chromium shows it in the richer install dialog; keep it to one or two sentences.
  5. Language of the default strings. A BCP 47 tag, canonicalized (EN-us becomes en-US). It labels the default text; it does not translate anything.
  6. Base direction of name, short_name and shortcut text: ltr, rtl or auto (default).
  7. Localized names (Chrome and Edge 148+ on desktop). Each key is a language tag; the value is a string or { "value", "lang"?, "dir"? }. Browsers without support fall back to name. short_name_localized and icons_localized work the same way.
  8. Launch URL. Resolved against the manifest URL; must be same-origin with the document and inside scope. The query parameter lets analytics count installed launches. Never put a user identifier here.
  9. Navigation scope. Pages outside it get browser UI: desktop Chromium and Chrome for Android show a toolbar with the origin and a close button, iOS opens them in Safari View Controller, and macOS Safari web apps hand them to the default browser. Prefix matching is string-based, so end it with /. Not the same thing as the service worker scope.
  10. Fallback display mode. One of fullscreen, standalone, minimal-ui, browser. This is the mode used by every browser that doesn't understand the first display_override entry.
  11. Custom fallback chain (Chromium 89+). The first recognized value wins; enhanced modes such as window-controls-overlay and tabbed are only valid here. Safari and Firefox ignore this member.
  12. Default orientation. any keeps tablets and foldables usable; lock only for games or camera tools. Baked into the WebAPK on Android.
  13. Theme color. Title bar and status bar color. Any CSS color that converts to sRGB; alpha may be ignored. A <meta name="theme-color"> in an in-scope page overrides it.
  14. Splash background. Used only while the app loads (Android splash screen). Match your CSS body background to avoid a flash.
  15. Dark-scheme overrides. In the W3C spec but not implemented by any browser as of September 2026. Harmless to include; keep the <meta name="theme-color" media="(prefers-color-scheme: dark)"> tag until it ships.
  16. Icons. At least one any icon of 144 px or more (192 and 512 recommended) for Chromium; separate maskable files with the logo inside the central 80 % circle; optional monochrome for platforms that tint icons. Never combine "any maskable" in one entry. See Icons & Maskable Icons.
  17. Screenshots for Chrome's richer install UI: wide for desktop, narrow (or none) for Android; 320 to 3,840 px per side, long side at most 2.3 times the short side, at most 8 considered, and a label for each. On Android every narrow screenshot must share the first one's aspect ratio, and wide entries still count toward the 8, so list narrow screenshots first. See Rich Install UI.
  18. Store categories. Lowercase strings from the known list below. Advisory only; Safari on macOS uses them to name Launchpad folders.
  19. Shortcuts. name and an in-scope url are required. Chromium reads at most the first 10 array entries, and Chrome for Android keeps only the first four. Put the most important first. See App Shortcuts.
  20. Launch behavior (Chromium desktop). The first recognized client_mode wins; with focus-existing your page must consume window.launchQueue.
  21. Share target. Files require POST with multipart/form-data. One invalid MIME type in accept drops the whole member in Chromium. Your service worker or server must handle the POST to action. See Web Share Target.
  22. File handlers (Chromium desktop). accept maps MIME types to extension lists that start with .; files arrive as FileSystemFileHandle objects through window.launchQueue. See File Handling.
  23. Protocol handlers (Chromium desktop). A safelisted scheme or web+ plus ASCII letters; url must be in scope and contain %s. The user approves the registration on first use.
  24. Scope extensions (Chrome and Edge 139+ desktop). Each listed origin must confirm with /.well-known/web-app-origin-association keyed by this app's processed id.
  25. Related native apps. Used by Chromium on Android for Play Store promotion (with prefer_related_applications: true; desktop Chromium only honors it for a chrome_web_store entry, or play on ChromeOS) and by navigator.getInstalledRelatedApps(). Harmless when you have no native app; omit it then.
  26. Keep false (the default) unless you want Android users sent to the Play Store instead of installing the PWA. A JSON string "false" is ignored, not interpreted.

Sub-object shapes

Image resource (icons, screenshots, shortcuts[].icons)

Member Required Type Values and rules
src Yes string (URL) Resolved against the manifest URL; may be cross-origin (subject to CSP img-src)
sizes Strongly recommended string Space-separated WxH tokens ("192x192", "16x16 32x32") or "any" for scalable images; lowercase x
type Recommended string (MIME type) image/png, image/svg+xml, image/webp; lets browsers skip formats they can't use without downloading
purpose No string Space-separated any, maskable, monochrome; default any; unknown tokens are dropped, and an entry with no valid token is discarded
label No (screenshots: recommended) string Accessible name; for screenshots, the alternative text
form_factor Screenshots only string narrow or wide
platform Screenshots only string See the platform list below

Shortcut item

Member Required Type Notes
name Yes string Non-empty; menu label
url Yes string (URL) Within scope, resolved against the manifest URL
short_name No string Used where space is limited
description No string May be exposed to assistive technology
icons No array of image resources 96 × 96 is the common size; Android uses them in the long-press menu
name_localized, short_name_localized, description_localized, icons_localized No language maps Chrome and Edge 148+ desktop

share_target

Member Required Values
action Yes URL within scope
method No GET (default) or POST
enctype No application/x-www-form-urlencoded (default) or multipart/form-data (only with POST)
params.title, params.text, params.url No Names of the query or form fields that receive each part
params.files No Array of { "name", "accept" }; accept is a MIME type or extension, or an array of them; requires POST + multipart/form-data

file_handlers[]

Member Required Values
action Yes URL within scope
accept Yes Object: MIME type (wildcards such as image/* allowed) → array of extensions starting with . (at most 16 characters each per spec; Chromium caps the total at 300 extensions)
name No File-type display name
icons No File-type icons
launch_type No single-client (default: one launch with all files) or multiple-clients (one launch per file)

protocol_handlers[]

Member Required Values
protocol Yes Safelisted scheme (bitcoin, ftp, ftps, geo, im, irc, ircs, magnet, mailto, matrix, mms, news, nntp, openpgp4fpr, sftp, sip, sms, smsto, ssh, tel, urn, webcal, wtai, xmpp) or web+ followed by one or more ASCII lowercase letters; no trailing colon. Chromium (since 86) also accepts the non-standard decentralized-web schemes cabal, dat, did, doi, dweb, ethereum, hyper, ipfs, ipns and ssb
url Yes Same-origin https URL within scope, containing %s (replaced with the percent-encoded URL being handled)
Object Shape Notes
launch_handler { "client_mode": "<mode>" } or { "client_mode": ["<mode>", "<fallback>"] } Chromium reads only client_mode; fields such as route_to from the old origin trial are ignored
scope_extensions[] { "type": "origin", "origin": "https://other.example" } https origins only; Chromium accepts at most 10; each origin confirms with a .well-known/web-app-origin-association file
related_applications[] { "platform", "url"?, "id"?, "min_version"?, "fingerprints"? } platform plus at least one of url or id; Chromium acts on play, windows, webapp and chrome_web_store
migrate_from[] "<old id>" or { "id", "install_url"?, "behavior"? } behavior: suggest (default) or force; ids resolve against the manifest URL and must be same-site; requires an explicit top-level id
migrate_to { "id", "install_url"? } Optional signal in the old app's manifest
tab_strip { "home_tab": { "scope_patterns": [...] }, "new_tab_button": { "url": "..." } } Only with "display_override": ["tabbed"]
note_taking { "new_note_url": "/notes/new" } Within scope; ChromeOS only
edge_side_panel { "preferred_width": 480 } Microsoft Edge; being deprecated

Value lists

display and display_override values

Value Valid in display Valid in display_override What the user sees Notes
fullscreen ✅ ✅ No browser UI, no status bar where the OS allows it Safari opens it as standalone
standalone ✅ ✅ Own window, no URL bar; OS status bar and title bar remain The default choice
minimal-ui ✅ ✅ Own window with minimal navigation controls (back, reload) Falls back to browser where unsupported, including Safari
browser ✅ ✅ A normal browser tab Not installable in Chromium; the spec default
window-controls-overlay ❌ (ignored) ✅ App content extends into the title bar area on desktop Chromium desktop; see Window Controls Overlay
tabbed ❌ (ignored) ✅ App window with a tab strip ChromeOS; behind flags elsewhere
unframed ❌ ✅ (IWA only) Window without a title bar Isolated Web Apps only; formerly borderless in Chromium

The standard fallback chain is fullscreen → standalone → minimal-ui → browser: when a browser can't provide the requested mode, it tries the next one. display_override replaces that chain with your own list, and the browser then falls back to display. The matching CSS media feature is @media (display-mode: <value>), which also has a picture-in-picture value that is not a manifest value.

orientation values

Value Meaning
any Rotates freely
natural The device's natural orientation (portrait on most phones, landscape on many tablets)
portrait Either portrait variant, following rotation
portrait-primary Upright portrait only
portrait-secondary Upside-down portrait only
landscape Either landscape variant
landscape-primary Primary landscape only
landscape-secondary Secondary (rotated 180°) landscape only

These are the Screen Orientation API's lock types. screen.orientation.lock() can change the orientation at runtime where locking is allowed, and unlock() returns to the manifest value. WCAG 2.2 success criterion 1.3.4 (Orientation, level AA) forbids locking unless a specific orientation is essential.

Icon purpose values

Value Meaning Design rule
any (default) Use the icon as-is in any context Transparent background allowed; logo can fill the canvas
maskable The OS may crop the icon to its own shape Opaque, full-bleed background; all important content inside a centered circle of 40 % radius (the central 80 %)
monochrome The OS uses only the alpha channel and fills it with one color Single-color glyph on transparency; color information is discarded

Combining tokens ("any maskable") is valid syntax, but it makes the same padded image appear small wherever it's used unmasked. Ship separate files.

categories known values

The W3C Application Information Note lists these known categories; the member accepts any string, but stores recognize these, and lowercase is recommended:

beauty, books, books & reference, business, cars, dating, design, developer, developer tools, development, education, entertainment, events, fashion, finance, fitness, food, fundraising, games, government, graphics, graphics & design, health, health & fitness, kids, lifestyle, magazines, medical, multimedia, multimedia design, music, navigation, network, networking, news, parenting, personalization, pets, photo, photo & video, politics, productivity, reference, security, shopping, social, social networking, sports, transportation, travel, utilities, video, weather.

screenshots form_factor and platform values

Field Values
form_factor narrow (phones; used by Chrome for Android), wide (desktop; the only value desktop Chrome uses)
platform (operating systems) android, chromeos, ios, ipados, kaios, macos, windows, xbox
platform (distribution) chrome_web_store, play, itunes, microsoft-inbox, microsoft-store

Chromium does not read platform. Use it only for screenshots that show platform-specific features.

launch_handler.client_mode values

Value Behavior when the app is already open
auto (default) The browser decides: desktop Chromium opens a new window; mobile reuses the existing one
navigate-new Opens a new app window at the launch URL
navigate-existing Focuses the most recently used app window and navigates it (unsaved state is lost)
focus-existing Focuses the most recently used app window without navigating and enqueues LaunchParams in window.launchQueue

share_target methods and encodings

method enctype Data arrives as Files
GET application/x-www-form-urlencoded (only valid value) Query string on action (spaces as +; decode with URLSearchParams) ❌
POST application/x-www-form-urlencoded Form body ❌
POST multipart/form-data Multipart body; read with request.formData() in the service worker ✅

dir values

ltr, rtl, auto (default). Write every enumerated manifest value in lowercase exactly as listed on this page; don't rely on any engine normalizing case.

URL resolution rules

Member Resolved against Constraint If it fails
start_url Manifest URL Same origin as the document Falls back to the document URL (and desktop Chromium reports start-url-not-valid)
id Origin of start_url Same origin as start_url Falls back to start_url
scope Manifest URL Same origin as the document; start_url must be inside it Falls back to the directory of start_url
icons[].src, screenshots[].src Manifest URL None (cross-origin allowed; CSP applies) Entry dropped
shortcuts[].url Manifest URL Within scope Shortcut dropped
share_target.action Manifest URL Within scope Whole member dropped
file_handlers[].action Manifest URL Within scope Handler dropped
protocol_handlers[].url Manifest URL Same origin, within scope, contains %s Handler dropped
note_taking.new_note_url Manifest URL Within scope Ignored
related_applications[].url Manifest URL None Entry needs url or id
migrate_from[].id Manifest URL Same site as the document Entry dropped

"Within scope" is a string-prefix test on the processed URLs. "scope": "/app" also matches /apple; end scopes with /. Details: App Identity & Updates.

Legacy and iOS meta tags: equivalence table

Before manifests, every vendor invented <meta> and <link> tags. Some still matter, some are fallbacks, some are dead weight:

Tag Manifest equivalent Read by (September 2026) Keep?
<meta name="theme-color" content="…" media="…"> theme_color (and future color_scheme_dark) Chromium (in installed apps on desktop), Safari 15+ (installed web apps only since Safari 26), Samsung Internet Keep. Per-page override within scope, and the only working light/dark theme color
<link rel="apple-touch-icon" href="…"> icons Safari on iOS, iPadOS and macOS; Chromium's fallback metadata Keep a 180 × 180 opaque PNG; Safari ignores manifest icons when it is present
<link rel="apple-touch-icon-precomposed"> icons Legacy iOS (before iOS 7 applied gloss effects) Remove; plain apple-touch-icon is enough
<meta name="apple-mobile-web-app-capable" content="yes"> "display": "standalone" Safari before iOS 26 (made a Home Screen icon open standalone); Chromium's fallback metadata when the unprefixed tag is absent Legacy. iOS 26+ opens every Home Screen site as a web app unless the user opts out
<meta name="mobile-web-app-capable" content="yes"> "display": "standalone" Chromium's fallback metadata for sites without a complete manifest Legacy; use the manifest
<meta name="apple-mobile-web-app-title" content="…"> short_name Safari (Home Screen label default) Optional; keep it identical to short_name
<meta name="apple-mobile-web-app-status-bar-style" content="…"> None Safari on iOS and iPadOS, in web app mode Optional: default, black or black-translucent (content extends under the status bar; pair with viewport-fit=cover and env(safe-area-inset-*))
<link rel="apple-touch-startup-image" href="…" media="…"> background_color + icons + name (Android builds its splash from these) Safari on iOS and iPadOS Optional; one image per device size and orientation, selected by media queries. Safari doesn't generate a splash screen from the manifest
<meta name="application-name" content="…"> name Chromium's fallback metadata Optional fallback
<link rel="icon" href="…"> icons All browsers (tabs, bookmarks); Chromium's fallback install icon Keep for tabs
<link rel="mask-icon" href="…" color="…"> Closest: icons with purpose: "monochrome" Legacy Safari on macOS (monochrome pinned-tab icon; Safari 12 and later show regular favicons in tabs) Optional legacy; unrelated to installation
<meta name="msapplication-TileColor">, msapplication-TileImage, msapplication-config, msapplication-starturl, msapplication-navbutton-color theme_color, icons, start_url Internet Explorer and EdgeHTML-based Edge, both retired Remove
<meta name="viewport" content="…, viewport-fit=cover"> None All mobile browsers Keep when you use black-translucent or fullscreen, so env(safe-area-inset-*) is non-zero

A head that covers every engine without redundancy:

index.html (head excerpt)
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<link rel="manifest" href="/app.webmanifest">

<!-- Light and dark theme colors: the manifest's color_scheme_dark isn't implemented yet. -->
<meta name="theme-color" content="#0b57d0" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#0f172a" media="(prefers-color-scheme: dark)">

<!-- Tab icons. -->
<link rel="icon" href="/favicon.ico" sizes="32x32">
<link rel="icon" href="/icons/icon.svg" type="image/svg+xml">

<!-- Safari uses this instead of manifest icons: 180x180, opaque, square corners. -->
<link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">

<!-- Optional Safari refinements for Home Screen web apps. -->
<meta name="apple-mobile-web-app-title" content="Tasks">
<meta name="apple-mobile-web-app-status-bar-style" content="default">

Splash screens per device and status-bar handling are covered in Splash Screens & Theming and iOS & iPadOS.

Size and count limits

Item Limit Source of the limit
Primary install icon (Chromium) At least 144 × 144; at most 1024 × 1024 on desktop Chromium installability check
Maskable safe zone Centered circle with a radius of 40 % of the icon size Web App Manifest spec
Shortcuts read First 10 array entries (Chromium) Chromium manifest parser
Shortcuts used on Android First four processed items (kMaxShortcuts = 4) Chromium on Android
Screenshots considered At most 8. On Android the count includes wide entries, so list narrow ones first; DevTools warns above 5 for mobile Chromium richer install UI
Screenshot dimensions 320 to 3,840 px per side; long side at most 2.3 × the short side Chromium richer install UI
scope_extensions entries 10, each origin string at most 2,000 characters Chromium manifest parser
file_handlers extensions 300 in total; each extension at most 16 characters (spec) Chromium parser; manifest incubations spec

What changes after installation

Manifest edits reach installed apps through the browser's update process, not instantly:

Change Desktop Chromium 144+ Chrome for Android (WebAPK) Safari
name, short_name Pending until the user approves it (Review app update in the app menu) Confirmation dialog, then a new WebAPK is minted. Checks run only when the WebAPK is launched and at least a day has passed since the last check; the new APK installs in the background, often hours later Name fixed at install time (the user can edit it while adding)
icons Only if the icons entries change (new URLs); under 10 % image difference applies silently (throttled to once a day), otherwise user review Below an 11 % image difference (Chromium's WEB_APK_ICON_UPDATE_BLOCKED_AT_PERCENTAGE, an average per-pixel color difference): applied with the next WebAPK. Larger changes need an icon confirmation dialog that current Chromium keeps disabled by default, so they are not applied Fixed at install time
start_url, scope, display, colors, shortcuts, handlers Applied silently on the next page load that links the manifest New WebAPK for the members baked into it Fixed at install time on iOS
id Can't change: a new id is a new app Same Same

Replacing an icon file in place without changing its URL never reaches desktop Chromium users. Publish new icons under new URLs. The full model is in App Identity & Updates.

Common validation mistakes

Mistake What the browser does Fix
"display": "window-controls-overlay" Ignores it; browser applies and Chromium won't install "display": "standalone", "display_override": ["window-controls-overlay"]
"prefer_related_applications": "false" Ignores the string; default false applies (by luck) Use JSON booleans
"categories": "productivity" Ignored (not an array) ["productivity"]
"sizes": "192X192" or missing sizes Icon can't satisfy the size check Lowercase x, always declare sizes
Only maskable icons Chromium: manifest-missing-suitable-icon Add any icons
"purpose": "any maskable" Valid, but the padded icon looks shrunken in any contexts Separate files
start_url outside scope scope is discarded; the default scope applies Put start_url inside scope
Relative URLs in a manifest on a CDN Resolve against the CDN origin and fail the same-origin checks Serve the manifest from the app origin, or use absolute URLs
Shortcut or handler URL outside scope Entry dropped with a console warning only Keep every navigational URL inside scope
Changing start_url without an id Existing installs keep the old app; new installs get a second one Set id to the old computed identity first
Trailing comma or comment in the JSON Whole manifest discarded Validate JSON in CI
Cache-Control: max-age=31536000 on the manifest Updates take up to a year to be seen Revalidate the manifest

Debugging a manifest quickly

  • Chrome and Edge: DevTools → Application → Manifest shows every processed member, the computed app ID, parser warnings (prefixed Manifest: in the console) and installability errors. The Identity section's Computed App Id is the value to copy into id.
  • Safari: connect Web Inspector to the device; Safari has no manifest pane, so check the Home Screen result directly. Remember that apple-touch-icon overrides manifest icons.
  • Firefox: DevTools → Application → Manifest displays the parsed members and icons, even though desktop Firefox doesn't install from manifests.
  • CI: use the Chrome DevTools Protocol's Page.getAppManifest and Page.getInstallabilityErrors, as shown in Installability Criteria, or the tools in Browser DevTools and Automated Testing.

Further reading

On this site

External references