Progressive Web Apps (PWA)

Web App Manifest

18 min Lesson 2 of 30

Understanding the Web App Manifest

The Web App Manifest is a JSON file that tells the browser how your PWA should behave when installed on the user's device. It controls the app's appearance, behavior, and provides metadata that makes your web app feel like a native application.

Creating manifest.json

Create a file named manifest.json in your project root and link it in your HTML:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My PWA</title>
<link rel="manifest" href="/manifest.json">
</head>
<body>
<h1>Progressive Web App</h1>
</body>
</html>

Essential Manifest Properties

Here's a complete example of a manifest.json file with all essential properties:

{
"name": "My Progressive Web App",
"short_name": "MyPWA",
"description": "A powerful progressive web application",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#2196F3",
"orientation": "portrait-primary",
"icons": [
{
"src": "/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable any"
}
]
}

Property Breakdown

name vs short_name:

name: Full application name shown during installation and in app launchers (max 45 characters recommended).

short_name: Abbreviated name shown on home screen under the icon (max 12 characters recommended).

1. Display Modes

The display property controls how your app appears:

/* standalone - Most common for PWAs */
"display": "standalone"
// Looks like native app, no browser UI

/* fullscreen - Immersive experience */
"display": "fullscreen"
// Full screen, hides all browser UI and status bar

/* minimal-ui - Some browser controls */
"display": "minimal-ui"
// Minimal browser UI (back/forward/reload)

/* browser - Default browser experience */
"display": "browser"
// Opens in regular browser tab
Best Practice: Use "standalone" for most PWAs. It provides the best balance between native feel and user familiarity.

2. Colors

Colors enhance the app experience and branding:

{
"theme_color": "#2196F3",
// Affects browser toolbar, status bar
// Shows in task switcher on Android

"background_color": "#ffffff"
// Splash screen background while app loads
// Should match your app's actual background
}

3. Start URL

Controls where the app opens when launched:

{
"start_url": "/"
// Home page

"start_url": "/dashboard"
// Specific page

"start_url": "/?source=pwa"
// With tracking parameter
}

4. Orientation

Lock screen orientation for better UX:

{
"orientation": "portrait-primary"
// portrait-primary, portrait-secondary
// landscape-primary, landscape-secondary
// portrait, landscape, any (default)
}

Icon Requirements

Icons are crucial for the installed app appearance. You need multiple sizes:

Critical Icon Sizes:

192x192: Required - Chrome/Android home screen
512x512: Required - Splash screens and app stores
72x72 to 384x384: Recommended for various devices

Use PNG format with transparent backgrounds. The purpose field supports:
"any" - Standard icon
"maskable" - Adaptive icon for Android (safe zone in center)
"maskable any" - Both purposes

Advanced Manifest Properties

{
"scope": "/",
// Defines navigation scope for the PWA

"categories": ["productivity", "utilities"],
// App categories for app stores

"screenshots": [
{
"src": "/screenshots/desktop.png",
"sizes": "1280x720",
"type": "image/png",
"form_factor": "wide"
},
{
"src": "/screenshots/mobile.png",
"sizes": "750x1334",
"type": "image/png",
"form_factor": "narrow"
}
],
// Used in app stores and installation prompts

"shortcuts": [
{
"name": "New Message",
"short_name": "New",
"description": "Start a new message",
"url": "/messages/new",
"icons": [{ "src": "/icons/new.png", "sizes": "192x192" }]
},
{
"name": "Inbox",
"short_name": "Inbox",
"description": "View your inbox",
"url": "/messages/inbox",
"icons": [{ "src": "/icons/inbox.png", "sizes": "192x192" }]
}
],
// App shortcuts (right-click menu on desktop)

"lang": "en-US",
// Primary language

"dir": "ltr",
// Text direction: ltr, rtl, auto

"prefer_related_applications": false,
// Prefer native app over PWA

"related_applications": [
{
"platform": "play",
"url": "https://play.google.com/store/apps/details?id=com.example.app",
"id": "com.example.app"
}
]
}

Validating Your Manifest

Testing Checklist:

1. Chrome DevTools:
• Open DevTools > Application > Manifest
• Check all properties display correctly
• Verify icons load at all sizes

2. Lighthouse Audit:
• Run Lighthouse PWA audit
• Should pass "Installable" checks

3. Browser Compatibility:
• Test manifest in Chrome, Edge, Safari
• Verify installation prompts appear

4. Icon Quality:
• Use high-resolution source images
• Ensure maskable icons have safe zone
• Test on actual devices

Common Manifest Mistakes

Avoid These Errors:

❌ Missing required icon sizes (192x192, 512x512)
❌ Incorrect MIME type in <link> tag (use application/manifest+json)
❌ Invalid JSON syntax (trailing commas, unquoted keys)
❌ Icons with wrong aspect ratio or low resolution
❌ start_url not matching actual app structure
❌ theme_color not matching app design
❌ Forgetting to serve manifest with HTTPS

Practical Example: Complete Setup

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Task Manager PWA</title>

<!-- Manifest -->
<link rel="manifest" href="/manifest.json">

<!-- Theme color for browser UI -->
<meta name="theme-color" content="#2196F3">

<!-- Apple-specific meta tags -->
<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="TaskMgr">
<link rel="apple-touch-icon" href="/icons/icon-192x192.png">
</head>
<body>
<h1>Task Manager</h1>
<button id="installBtn" style="display: none;">Install App</button>

<script>
// Installation prompt handling
let deferredPrompt;
const installBtn = document.getElementById('installBtn');

window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
installBtn.style.display = 'block';
});

installBtn.addEventListener('click', async () => {
if (!deferredPrompt) return;

deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
console.log(`User response: ${outcome}`);

deferredPrompt = null;
installBtn.style.display = 'none';
});
</script>
</body>
</html>
Next Steps: In the next lesson, we'll dive deep into Service Workers - the engine that powers offline functionality and makes your PWA truly powerful.