GNOME Web App Icons: Metadata, Manifests, and Platform Quirks
GNOME Web (Epiphany) supports installing web applications as standalone desktop apps, but the icon that appears in the GNOME Shell application grid, the dock, and the Activities overview depends on a chain of metadata parsing — web app manifest icons, HTML link elements, favicon fallbacks — where each step has its own sizing expectations, format preferences, and failure modes that differ from how Chromium or Safari handle the same metadata. This page documents how GNOME Web selects and processes app icons: the manifest icons array parsing, the HTML <link> element fallback, the size selection logic, the image format handling, the caching behaviour, and the specific conditions that produce blurry, missing, or generic placeholder icons on the GNOME desktop. The analysis is based on testing across GNOME Web 43–46 on GNOME Shell 43–46 under Fedora and Ubuntu installations. This page sits within the web development section and relates to the GNOME apps and web APIs technical note and the open web topic hub.
The short version
GNOME Web reads the web app manifest first when installing a site as a web application. It looks for an icon in the icons array that is at least 128×128 pixels, preferring PNG format. If the manifest does not provide a suitable icon, GNOME Web falls back to HTML <link rel="icon"> elements, then to the site favicon. The most common cause of blurry or missing app icons is a manifest that only declares small icon sizes (64×64 or below) or declares large sizes but serves images that are actually smaller than declared. GNOME Shell renders app icons at 96–128px in the application grid and 48–64px in the dock — any source image smaller than 128×128 produces visible scaling artefacts.
How GNOME Web selects an icon
When you use GNOME Web's "Install as Web Application" feature, the browser needs to find an icon to represent the app in the GNOME Shell. The selection follows a defined priority order:
1. Web app manifest icons array
GNOME Web fetches and parses the web app manifest referenced in the HTML <link rel="manifest"> element. From the icons array, it evaluates each entry's sizes and type properties.
The selection logic prefers:
- Square icons (equal width and height)
- Sizes at or above 128×128 pixels
- PNG format (
image/png) over other formats - The smallest icon that meets the minimum size threshold
GNOME Web 44–46 consistently selects the icon entry closest to 128×128 from above. Given a manifest with icons at 48×48, 96×96, 192×192, and 512×512, it selects the 192×192 icon — the smallest that exceeds its 128px threshold. It does not select the 512×512 icon even though that would provide better quality when downscaled. This differs from Chromium, which typically selects the largest available icon and downscales it. The practical consequence: if your 192×192 icon is a low-quality export but your 512×512 is crisp, GNOME Web uses the low-quality version while Chromium uses the high-quality one.
2. HTML link elements
If the manifest is absent, unparseable, or does not contain a suitable icon, GNOME Web falls back to scanning the HTML <head> for icon link elements:
<link rel="icon" type="image/png" sizes="128x128" href="/icons/icon-128.png">
<link rel="icon" type="image/png" sizes="32x32" href="/icons/icon-32.png">
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png">
GNOME Web checks rel="icon" elements first, preferring those with explicit sizes attributes that meet the 128px minimum. It also recognises rel="apple-touch-icon" as a valid icon source — a pragmatic choice, since many sites provide high-quality square icons only as Apple touch icons.
3. Favicon fallback
If no link elements provide a suitable icon, GNOME Web falls back to /favicon.ico at the site root. Since most favicons are 16×16 or 32×32, this fallback almost always produces a blurry, heavily upscaled icon in the application grid.
Many sites provide a comprehensive icon set in their HTML <head> but do not include a web app manifest. GNOME Web's HTML fallback parsing works, but it is less reliable than manifest parsing — the browser must load and parse the full HTML document, evaluate multiple link elements, and make size selection decisions without the structured metadata that a manifest provides. If you want your site to produce good app icons on GNOME, provide a manifest with an explicit icons array. It takes five minutes and eliminates the ambiguity.
Manifest icon declaration
A manifest that produces good results across GNOME Web, Chromium, and Safari includes multiple icon sizes with explicit format declarations:
{
"name": "My Application",
"short_name": "MyApp",
"icons": [
{ "src": "/icons/icon-48.png", "sizes": "48x48", "type": "image/png" },
{ "src": "/icons/icon-72.png", "sizes": "72x72", "type": "image/png" },
{ "src": "/icons/icon-96.png", "sizes": "96x96", "type": "image/png" },
{ "src": "/icons/icon-128.png", "sizes": "128x128", "type": "image/png" },
{ "src": "/icons/icon-144.png", "sizes": "144x144", "type": "image/png" },
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icons/icon-256.png", "sizes": "256x256", "type": "image/png" },
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" }
],
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#1a1a2e"
}
The 128×128 and 192×192 entries are the most critical for GNOME Web. The 512×512 serves Chromium and Android. The smaller sizes serve favicons and tab icons. Including all of them covers the full range of contexts where a browser or operating system needs an icon for your application.
Size handling and scaling behaviour
GNOME Shell renders application icons at several sizes depending on context:
| Context | Rendered size | Minimum source recommended |
|---|---|---|
| Application grid | 96×96 or 128×128 (depends on display scaling) | 128×128 |
| Dock / dash | 48×48 or 64×64 | 128×128 (downscaled) |
| Alt+Tab switcher | 64×64 | 128×128 (downscaled) |
| Notification | 48×48 | 128×128 (downscaled) |
GNOME Shell uses simple bilinear or nearest-neighbour scaling depending on the GTK/GDK rendering path. Downscaling from a larger source produces acceptable results. Upscaling from a smaller source — a 64×64 icon displayed at 128×128 — produces visibly blurry icons with soft edges that look out of place next to the crisp native application icons in the grid.
On HiDPI displays (2× scaling), GNOME Shell requests icons at double the logical size — 256×256 for a 128×128 logical grid cell. Web apps whose manifests only provide icons up to 192×192 still look acceptable at 2× scaling (192px source for a 256px render is a 1.3× upscale, which produces mild softness). Web apps with only 128×128 icons look noticeably blurry at 2× scaling — the 128px source is upscaled to 256px, a 2× enlargement that turns sharp edges into visible pixel smearing.
GNOME Web does not support SVG icons from the web app manifest, even though the type field allows image/svg+xml and SVG icons would scale perfectly to any size. The browser skips SVG entries in the manifest icons array and proceeds to the next candidate. Chromium also does not use SVG manifest icons. If you provide SVG icons, include them alongside PNG entries — they will not be used for installed web apps on any current browser, but they may be used for tab favicons on some browsers.
Format handling
GNOME Web handles PNG icons reliably. Other formats introduce varying degrees of unpredictability:
PNG — fully supported, preferred. Both indexed-colour and truecolour PNG icons work correctly. Alpha transparency is preserved and composited correctly against the GNOME Shell background.
ICO — supported for favicon fallback but not recommended for manifest icons. Multi-resolution ICO files (containing multiple sizes in one file) are parsed but GNOME Web may not select the optimal size from within the container.
WebP — support depends on the GNOME Web version and the underlying GDK-PixBuf loaders installed. GNOME Web 44+ on systems with the WebP GDK-PixBuf loader handles WebP icons, but older versions or systems without the loader silently skip WebP entries and fall back to the next candidate. This makes WebP a risky choice for the primary manifest icon.
JPEG — technically loadable but inappropriate for icons. JPEG does not support transparency, and the lossy compression produces visible artefacts at small sizes. GNOME Web will use a JPEG icon if nothing else is available, but the result looks poor against the GNOME Shell background.
Declaring an icon in the manifest with "type": "image/png" but serving a file that is actually a JPEG renamed to .png causes silent failures in some GNOME Web versions. The browser trusts the declared MIME type, attempts to decode the file as PNG, fails, and falls back to the next icon candidate or the generic placeholder. This is more common than you might expect — image processing pipelines that convert formats sometimes produce mismatched extensions. Verify your icon files with file icon-192.png on the command line to confirm the actual format matches the declared type.
The installed app icon pipeline
When GNOME Web installs a web application, the icon goes through a specific pipeline:
- Fetch — the browser downloads the selected icon URL
- Decode — the image is decoded using GDK-PixBuf
- Scale — if necessary, the image is scaled to the target size for the
.desktopfile icon - Write — the processed icon is saved to
~/.local/share/icons/or~/.local/share/epiphany/app-epiphany-*/(path varies by version) - Register — a
.desktopfile is written to~/.local/share/applications/referencing the saved icon path
The icon is fetched once at installation time. It is not refreshed when the manifest changes — if you update your site's icons after a user has installed the web app, their app icon does not change. Reinstalling the web app (remove and re-add) is the only way to pick up icon changes.
Earlier GNOME Web versions (pre-42) stored installed web app icons in a less structured location within the Epiphany profile directory. The icon selection logic was simpler — it took the first icon from the manifest that was larger than 48×48 without strong size preference. The result was that sites with only large icons (512×512) would have those stored and then downscaled at render time, which actually produced better visual results than the current "closest from above" selection that sometimes picks a medium-resolution icon when a higher-resolution option is available.
GNOME Web 43+ uses a more structured icon storage path aligned with the freedesktop icon theme specification. The selection logic is more deliberate — targeting the 128px range specifically — but this means sites need to provide icons at that size for optimal results. The .desktop file integration is tighter, supporting GNOME Shell's icon theme system for consistent visual presentation alongside native applications.
Debugging icon problems
When a web app installs with a missing, blurry, or generic icon, the diagnostic approach follows the selection pipeline:
curl -s https://example.com/manifest.json | python3 -m json.tool | grep -A3 '"icons"'
Verify that the manifest is valid JSON, that the icons array contains entries with sizes at or above 128×128, and that the src URLs are absolute or resolve correctly relative to the manifest URL.
curl -sI https://example.com/icons/icon-192.png | head -10
curl -s https://example.com/icons/icon-192.png | file -
The first command checks that the icon URL returns HTTP 200 with the correct Content-Type. The second verifies the actual file format matches expectations. A Content-Type: image/png header with a file that file identifies as JPEG is a format mismatch that will cause problems.
find ~/.local/share -name "*.png" -path "*epiphany*" -newer /tmp/marker_file 2>/dev/null
Create a marker file before installing the web app (touch /tmp/marker_file), install the app, then run the find command to locate the newly saved icon. Inspect the saved icon's dimensions with identify (ImageMagick) or file to verify GNOME Web downloaded and stored what you expected.
GNOME Web's web app installation feature has matured from an experimental capability in GNOME 3.x — where icon handling was minimal and many sites produced generic placeholder icons — to a production-quality feature in GNOME 44+ where manifest parsing, icon selection, and desktop integration work reliably when sites provide proper metadata. The gap has narrowed but has not closed: Chromium's icon handling remains more forgiving of imperfect manifests, partly because Chromium has a larger engineering investment in PWA support and partly because it aggressively caches and reprocesses icons with more sophisticated scaling algorithms. For site operators who want their web app to look good on GNOME, the practical advice is straightforward: provide a manifest with a 192×192 PNG icon at minimum, and the result will be a crisp, properly integrated desktop application icon.
What consistently goes wrong
After observing icon failures across dozens of web applications installed via GNOME Web, the failure modes cluster into a few patterns:
No manifest at all. The site relies on HTML link elements for icons. GNOME Web's fallback works but is less reliable. The fix is trivial: add a manifest file.
Manifest icons only at 512×512. The site targets Chromium/Android, which prefers the largest icon. GNOME Web selects the 512×512 (it meets the 128px minimum) but the download is unnecessarily large. Adding a 192×192 entry alongside the 512×512 serves both platforms efficiently.
Manifest icons only at 48×48 and 64×64. Common on sites that treat the manifest as a favicon declaration rather than an app icon source. Neither size meets GNOME Web's 128px minimum, so it falls back to HTML link elements or the favicon. Add a 128×128 or 192×192 entry.
Icon URL returns 404. The manifest references an icon path that does not exist on the server, often because the icons were moved or renamed after the manifest was generated. GNOME Web falls back silently, and the user gets a generic placeholder.
CORS blocking the icon fetch. If the manifest is served from a CDN or a different origin and the icon URLs are relative to the manifest, CORS policies on the icon server may block GNOME Web from fetching them. This is rare but produces confusing failures since the icon URLs work fine when opened directly in the browser.
For broader context on how GNOME applications interact with web platform APIs, the GNOME apps and web APIs technical note covers the integration points beyond just icon handling. The open web topic hub connects this to the wider landscape of cross-platform web standards implementation.