Before a browser offers to install your PWAWhat is pwa?A web app enhanced with browser APIs so it can install on a device, work offline, and send push notifications like a native app., it needs to know what your app is called, what icon to put on the home screen, and what color to use for the splash screen. All of that lives in a single file: manifest.json. Without it, the browser treats your site as just a website, with it, you unlock the install prompt and the native-app experience.
What the manifest controls
Think of the manifest as the equivalent of the metadata you fill in when submitting to the App Store, but as a plain JSONWhat is json?A text format for exchanging data between systems. It uses key-value pairs and arrays, and every programming language can read and write it. file you control directly.
{
"name": "My Super Application",
"short_name": "MyApp",
"description": "An incredible PWA to manage your tasks",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#6366f1",
"orientation": "portrait",
"scope": "/",
"lang": "en",
"icons": [
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}The fields that matter most
Identity fields
name is the full name shown on the splash screen when the app launches. short_name is what appears under the icon on the home screen, keep it under 12 characters or Android will truncate it. description doesn't appear to users directly but search engines and app stores read it.
Display mode
The display field is where a PWAWhat is pwa?A web app enhanced with browser APIs so it can install on a device, work offline, and send push notifications like a native app. feels most like a native app. standalone is the right choice for most apps, it removes the browser address bar and toolbar so the app gets the full screen.
| Value | What the user sees |
|---|---|
browser | Normal browser tab, full address bar |
standalone | Own window, no address bar (most native-feeling) |
fullscreen | Full screen, no system UI at all |
minimal-ui | Small browser controls at top |
display mode, it falls back gracefully, fullscreen → standalone → minimal-ui → browser. You always get something sensible.Colors
theme_color tints the browser chrome on mobile (the status bar on Android, the toolbar on desktop Chrome). background_color is the color of the splash screen shown while the app loads, set it to match your app's background so there's no jarring flash.
Icons
You need at least two sizes. The purpose field tells the browser how to use the icon:
"icons": [
{
"src": "/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]| Purpose value | When it's used |
|---|---|
any | Standard square icon |
maskable | Icon that adapts to circular/squircle shapes on Android |
monochrome | Used in some OS monochrome contexts |
A maskable icon needs its main content in the center 80% of the image (the "safe zone"), because the OS will crop the edges into the device's shape. Use maskable.app to check yours.
Linking the manifest in HTML
Place this in your <head>:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- PWA manifest -->
<link rel="manifest" href="/manifest.json">
<!-- Matches theme_color in manifest -->
<meta name="theme-color" content="#6366f1">
<!-- iOS-specific overrides (Safari ignores most manifest fields) -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="MyApp">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="apple-touch-icon" href="/icon-192.png">
<title>My PWA</title>
</head>apple-mobile-web-app-* meta tags for things like the home screen title and status bar color. Always include both the manifest and the iOS meta tags.Icon sizes reference
| Size | Where it's used |
|---|---|
| 72×72 | Android low-resolution screens |
| 96×96 | Android standard |
| 144×144 | Microsoft platforms |
| 152×152 | iPad home screen |
| 192×192 | Android/Chrome, required for install prompt |
| 384×384 | Android high-resolution |
| 512×512 | Splash screen, required for Chrome install |
You can start with just 192 and 512 and add the others if you need broader compatibility.
Testing the manifest
Open Chrome DevTools, go to Application → Manifest. You'll see all parsed fields, any warnings about missing icons, and a button to trigger the install prompt manually. If the browser can't parse your manifest or can't fetch an icon, the install prompt won't appear, this panel tells you exactly why.
Quick reference
| Field | Required | Purpose |
|---|---|---|
name | Yes | Full app name |
short_name | Recommended | Under-icon label (max 12 chars) |
start_url | Yes | URL launched when app opens |
display | Yes | standalone for native feel |
icons | Yes | At minimum 192×192 and 512×512 PNG |
theme_color | Recommended | Browser chrome tint color |
background_color | Recommended | Splash screen background |
// Complete manifest.json
{
"name": "TaskMaster, Task Manager",
"short_name": "TaskMaster",
"description": "Organize your daily tasks with a fast and intuitive PWA",
"start_url": "/",
"display": "standalone",
"background_color": "#f8fafc",
"theme_color": "#4f46e5",
"orientation": "portrait",
"scope": "/",
"lang": "en",
"dir": "ltr",
"icons": [
{
"src": "/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
}
],
"screenshots": [
{
"src": "/screenshots/home.png",
"sizes": "1280x720",
"type": "image/png",
"form_factor": "wide"
},
{
"src": "/screenshots/mobile.png",
"sizes": "750x1334",
"type": "image/png",
"form_factor": "narrow"
}
],
"categories": ["productivity", "utilities"],
"shortcuts": [
{
"name": "New Task",
"short_name": "New",
"description": "Create a new task",
"url": "/new-task",
"icons": [{ "src": "/icons/new-task.png", "sizes": "96x96" }]
}
]
}
// index.html, Linking the manifest
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- PWA -->
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#4f46e5">
<!-- iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="TaskMaster">
<link rel="apple-touch-icon" href="/icons/icon-192x192.png">
<!-- Icons -->
<link rel="icon" type="image/png" sizes="32x32" href="/icons/icon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/icons/icon-16x16.png">
<title>TaskMaster</title>
</head>
<body>
<div id="app"></div>
</body>
</html>