A website favicon checklist catches a small asset problem before it becomes a confusing first impression. Check the icon on the deployed URL, not in a local browser tab. A CDN, route prefix, redirect, or stale cache can make a favicon that works on a local host fail after release.
This guide covers the HTML link, the icon response, the optional Apple touch icon, and the web app manifest. It also shows how to debug a favicon that is not showing and how to keep the checks in CI. A favicon is part of page identity, not a substitute for a useful title, description, or accessible content.
Website favicon checklist for the deployed URL
Start with the exact HTTPS URL that people will open. Use a clean browser profile or a private window, then inspect the initial HTML and the Network panel. Write down the release, host, path, and asset URLs so another developer can reproduce the result.
Your release contract should answer these questions:
- Does the document declare a
link rel="icon"in its<head>? - Does the linked file return a successful image response instead of an HTML fallback?
- Does the page include an
apple-touch-iconwhen people can save the site to a mobile home screen? - If the site is installable, does the manifest return valid JSON with the right identity and icons?
- Do the icon URLs stay stable, crawlable, and correct for the production host?
Google's favicon documentation says a favicon may appear beside a site's search result when the home page links to a crawlable, square icon. It recommends an icon larger than 48 by 48 pixels, requires at least 8 by 8 pixels, and says Google does not guarantee display. Treat those as search-result guidance, not a promise that every browser or search surface will use one file.
Add an explicit favicon HTML link
Put the icon link in the document head that the public URL returns. An explicit link is easier to inspect than relying on a browser's fallback request for /favicon.ico:
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="icon" href="/favicon-48.png" type="image/png" sizes="48x48">
Use a path that exists in the deployed asset directory. Keep the sizes value truthful, and use the type value to describe the file. The HTML rel attribute reference explains that browsers can use media, type, and sizes to select between multiple icon links.
A few common mistakes are easy to miss in a code review:
- The link starts with a development path such as
/src/assets/favicon.svgthat the production server does not expose. - The asset works at
/favicon.svg/but the HTML points to/favicon.svg, or vice versa. - The file name has different case on a case-sensitive host.
- A catch-all single-page-app route returns the application shell with
200for a missing icon. - A framework emits a default icon in one layout while a nested route emits a different one.
Open the exact href from the final HTML. Confirm the status, content type, and response body. A response that contains your app's HTML is not a valid image response even if the status is 200.
Add an apple-touch-icon for saved mobile shortcuts
If people can add the site to a phone or tablet home screen, provide a dedicated touch icon:
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
The MDN page metadata guide documents apple-touch-icon as the link that a device can use for a home-screen icon. Treat it as a separate platform hint from the ordinary browser favicon, so do not assume one asset will be selected everywhere.
Check the touch icon URL, then save the page to a supported device or emulator. Look for a sharp, recognizable image and verify that the shortcut opens the intended host. Test a clean install or a different profile when an old icon might be cached. Keep the source path stable and replace the file as part of a planned brand change.
Validate the web app manifest when it applies
A normal marketing or documentation page does not need a manifest. Add one when the site is intended to behave like an installable web app, and test it as its own public response:
<link rel="manifest" href="/manifest.webmanifest">
The MDN web app manifest guide describes a manifest as JSON that gives browsers information such as the app name, icons, display mode, and start URL. A small example looks like this:
{
"name": "Example Docs",
"short_name": "Docs",
"start_url": "/",
"display": "standalone",
"theme_color": "#18212b",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
The web.dev manifest guide recommends a name, icons, and a launch URL for a typical manifest and explains why Chromium install flows use 192 and 512 pixel icons in common configurations. Browser install criteria change, so use DevTools and a real device for the final install test. Do not advertise installability because a manifest parses; the service worker, HTTPS, scope, and browser-specific requirements still matter.
Check that the manifest link resolves from every HTML layout that can start an install. Request it from the URL, confirm a JSON-valid content type such as application/manifest+json or application/json, and parse the body. Verify each icon path in the icons array. A valid JSON document with a missing icon is still a broken install experience.
Test the icon response and caching behavior
Use the final host to test each asset. Follow redirects, but record when an icon leaves the preferred origin:
for path in /favicon.svg /favicon-48.png /apple-touch-icon.png /manifest.webmanifest; do
printf '\n%s\n' "$path"
curl -sSIL "https://example.com${path}" | sed -n '1p;/[Cc]ontent-[Tt]ype:/p;/[Ll]ocation:/p'
done
For each response, check:
- The final status is successful and the final URL is the one you intended.
- The content type matches the file. Serve the SVG as an image, and serve the manifest as JSON rather than an HTML document shell.
- The body is the current asset, not a login page, error page, or old deployment.
- The URL is reachable without credentials and is not blocked by an unintended crawler rule.
Google notes that both the home page and favicon file must be crawlable before it can consider a search favicon. The robots.txt and sitemap guide covers the separate crawl controls. Do not use robots.txt as a privacy mechanism for a private icon or app asset; use access control instead.
When a favicon is not showing, compare the exact HTML href with the Network request. The request exposes a typo, wrong base path, wrong MIME type, HTML fallback, or cached response. Test again in a clean profile before changing file names. Changing an icon URL on every build can make cache behavior and search recrawls harder to reason about, so keep stable paths unless a planned version change is needed.
Keep the favicon checks in CI
Once the production contract is known, assert the stable parts on every preview or release. A Playwright request check can catch a missing link and a bad image response without depending on which browser surface happens to display the icon:
import { test, expect } from "@playwright/test";
test("production page exposes working identity assets", async ({ page, request }) => {
await page.goto("https://example.com/");
const iconHref = await page.locator('link[rel~="icon"]').first().getAttribute("href");
expect(iconHref).toBeTruthy();
const icon = await request.get(new URL(iconHref!, page.url()).toString());
expect(icon.ok()).toBeTruthy();
expect(icon.headers()["content-type"]).toMatch(/^image\//);
const manifestHref = await page.locator('link[rel="manifest"]').getAttribute("href");
if (manifestHref) {
const manifest = await request.get(new URL(manifestHref, page.url()).toString());
expect(manifest.ok()).toBeTruthy();
expect(manifest.headers()["content-type"]).toMatch(/json/);
expect((await manifest.json()).name).toBeTruthy();
}
});
Keep a separate browser check for the mobile save-to-home-screen flow. The automated request test proves that the declared files resolve; it cannot prove how every operating system crops or caches an icon. The mobile website testing routine gives you a repeatable narrow-viewport pass, and the website regression testing guide shows how to compare the same checks after deployment.
Run a website favicon audit with Slop Audit
Run a Slop Audit on the public page after deployment. The report checks whether the initial HTML declares a favicon and an Apple touch icon, probes a declared manifest, and records the document language that helps assistive technology and translation tools interpret the page. It keeps the observed URL and response evidence beside the finding so a missing icon becomes a concrete release task.
The audit has a limited scope. It does not render every browser or device, certify PWA installability, inspect every icon dimension, or guarantee that Google will show a favicon. Use the website audit report example to turn the observed evidence into an owner, fix, and rescan.
Favicon release checklist
- The production HTML contains one favicon strategy with accurate
href,type, andsizesvalues. - Each icon URL returns the expected image content type and a current asset.
- The touch icon exists when mobile home-screen shortcuts are part of the experience.
- Link the manifest when an installable web app is intended, and make sure its JSON parses with real names, start URL, and icon paths.
- The home page and icon responses are reachable without credentials and are not blocked by an unintended crawler rule.
- CI checks the declared files, while a browser or device pass checks the surfaces that request them.
- A clean post-deploy check records the host, release, asset URLs, and any cache limitation.
An icon should make the page easier to recognize, not hide a broken route or unclear content. Finish the identity checks, then review the rest of the website launch checklist for developers before sharing the URL.