Web App Manifest

The manifest is app identity. Treat it like package metadata, not a cosmetic JSON file.

<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0f172a">
{
  "id": "/",
  "name": "Field Ledger",
  "short_name": "Ledger",
  "description": "Offline field ledger for small teams",
  "start_url": "/",
  "scope": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#0f172a",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512-maskable.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ],
  "shortcuts": [
    {
      "name": "New entry",
      "url": "/entries/new",
      "icons": [{ "src": "/icons/new-entry.png", "sizes": "96x96" }]
    }
  ]
}

Fields That Matter

FieldPractical rule
idSet it early and keep it stable to avoid identity changes
start_urlUse a route that can load reliably and handle auth/offline state
scopeKeep it at the app boundary, usually / or a sub-app root
displayUse standalone for most app-like PWAs
theme_colorMatch the top browser/app chrome color
background_colorMatch the startup/splash background
iconsProvide 192 and 512 pixel icons; include maskable variants
screenshotsImprove install UI on surfaces that show richer listings
shortcutsExpose common actions from launcher context menus
capability membersAdd only when the capability is implemented and tested

Gotcha: Changing identity fields after users install can create duplicate app identities or break store package metadata. Version manifest changes deliberately.