Put the image in your site's published files and add this line inside the document's <head>:
<link rel="icon" type="image/png" href="/favicon.png" />
That is the smallest modern setup. The leading slash means “from this hostname's root,” so a page at /products/widget/ still requests https://example.com/favicon.png.
For broader browser, Apple home-screen, and installed-app coverage, use a small deliberate pack rather than one mystery file:
<link rel="icon" href="/favicons/favicon.ico" sizes="any" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="64x64" href="/favicons/favicon-64x64.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png" />
<link rel="manifest" href="/favicons/site.webmanifest" />
<meta name="theme-color" content="#ffffff" />
Generate those assets and a matching snippet with the Favicon Generator, then scan the public page with the Favicon Checker. The sections below explain every file, attribute, path rule, and test so you are not dependent on a copied snippet.
This guide is for static HTML, shared server templates, and developers who want to understand the markup beneath a framework. If a hosted CMS owns the document head, use its supported icon setting rather than editing generated output that the platform will replace.
First decide where the markup belongs
The icon declarations belong in the shared document <head>, not in the visible <body> and not on just one article page.
| Site type | Put files here | Put declarations here |
|---|---|---|
| Hand-written static HTML | Beside published HTML or in /favicons/ | Inside <head> on every document, usually via a shared include |
| Server template | Public/static directory | Base layout or head partial |
| Static-site generator | Its copied static-assets directory | Global layout/template |
| Next.js App Router | Reserved files in app/, or files in public/ | File conventions or Metadata API |
| WordPress | Media/platform-managed location | Site Icon setting, theme API, or a child-theme head hook |
| Single-page app | Build tool's public/static directory | Source index.html or framework metadata API |
If a framework manages metadata, use its native API. Manually editing generated HTML is fragile because the next build overwrites it. Next.js users should follow the tested Next.js setup; platform users can use our WordPress, Shopify, Squarespace, or Wix guides.
Prepare artwork that survives tab size
Start from a square source, ideally a symbol rather than a full horizontal wordmark. Before export:
- Use a 1:1 canvas.
- Leave intentional breathing room around the mark.
- Remove taglines and tiny lettering.
- Thicken details that disappear when downsampled.
- Check contrast on light and dark browser chrome.
- Preview at 16x16 and 32x32, not only at 512x512.
SVG is useful as a master because it stays editable. Export purpose-built raster sizes from it; repeatedly resizing a tiny PNG upward cannot restore missing detail. For a wide brand lockup, make a dedicated symbol or monogram using the square logo design process.
What each file is for
You do not need every historical platform asset. This practical set covers the common jobs without confusing file count with quality.
| File | Typical dimensions | Main job | Keep it when... |
|---|---|---|---|
favicon.ico | Multiple embedded sizes | Broad browser and legacy fallback | Almost always; it is compact compatibility insurance. |
favicon-16x16.png | 16x16 | Small browser UI | You want explicit pixel-tuned tab artwork. |
favicon-32x32.png | 32x32 | Browser UI and high-density tabs | Recommended for a conventional pack. |
favicon-48x48.png or larger | Square | Search and larger browser surfaces | Organic Search or larger UI surfaces matter. |
apple-touch-icon.png | 180x180 | iOS/iPadOS saved home-screen icon | Users may save the site to a device home screen. |
site.webmanifest | JSON | Installed web-app name, colors, and icon candidates | The product supports an installable/PWA experience. |
| 192px and 512px app PNGs | 192x192, 512x512 | Installed-app and launcher surfaces | Referenced by the manifest. |
| Maskable 512px PNG | 512x512 with safe zone | Adaptive launcher crops | You support Android-style maskable installation. |
browserconfig.xml | XML | Historical Microsoft pinned-tile metadata | A compatibility target still requires it. |
An Apple touch icon and manifest icon are not substitutes for rel="icon". Each declaration addresses a different discovery system.
Inside the tested ZIP
Our July 19 pack contained:
favicon-pack/
├── README.txt
├── apple-touch-icon.png
├── browserconfig.xml
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon-48x48.png
├── favicon-64x64.png
├── favicon-96x96.png
├── favicon-128x128.png
├── favicon-256x256.png
├── favicon-512x512.png
├── favicon.ico
├── html-snippet.txt
└── site.webmanifest
The ZIP's exact byte size is not a quality target. Artwork complexity, transparency, compression, ICO contents, dark variants, and generator options all change it. The useful checks are that the referenced files exist, decode correctly, and suit their target surfaces.
Install a complete pack step by step
1. Copy files into the published asset directory
A clean deployment layout is:
site-root/
├── favicons/
│ ├── apple-touch-icon.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon-64x64.png
│ ├── favicon-192x192.png
│ ├── favicon-512x512.png
│ ├── favicon.ico
│ └── site.webmanifest
└── index.html
“Site root” here means the directory your web server publishes, not necessarily the repository root. In Vite it may be public/; in another build it may be copied into dist/; on shared hosting it may be public_html/.
After deployment, open https://example.com/favicons/favicon.ico directly. If that URL fails, do not change HTML yet. Fix file placement or server routing first.
2. Paste declarations into the shared head
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicons/favicon.ico" sizes="any" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="64x64" href="/favicons/favicon-64x64.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png" />
<link rel="manifest" href="/favicons/site.webmanifest" />
<meta name="theme-color" content="#ffffff" />
<title>Example site</title>
</head>
<body>
...
</body>
</html>
Use rel="icon"; do not add rel="shortcut icon" just because an old tutorial does. The MDN rel reference calls the shortcut form a nonconforming historical alternative.
3. Make the manifest paths correct
{
"name": "Example Site",
"short_name": "Example",
"icons": [
{
"src": "/favicons/favicon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/favicons/favicon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}
Manifest src values resolve relative to the manifest URL, unless they start with / or are absolute. Root-relative paths remove ambiguity when a manifest lives inside /favicons/. The MDN manifest icon documentation describes sizes, type, and purpose.
Only set display: "standalone" when the site is designed and tested as an installed app. A manifest is product configuration, not an SEO decoration.
4. Deploy before evaluating the result
Check the public hostname after the build and upload. Local success does not prove that a Docker stage, ignore file, CDN rule, or static-host output directory included the assets.
A compact visual introduction to the basic HTML step. Use the path, platform, and production checks in this guide for the full deployment.
Watch on YouTubePath resolution: the detail that breaks nested pages
We served two nested test pages from an in-memory HTTP server and inspected the resolved link URL in a real browser.
| Test page | Markup | Requested URL | Result |
|---|---|---|---|
/guides/root/ | href="/favicon.png" | /favicon.png | 200, image/png |
/guides/relative/ | href="favicon.png" | /guides/relative/favicon.png | 404, text/plain |
This does not mean root-relative is always correct. Choose based on the deployment:
- Root-relative
/favicons/icon.png: best when the site owns the host root. - Path-relative
./favicons/icon.png: useful for portable folders or pages opened under a known directory. - Absolute
https://cdn.example.com/icon.png: useful for a stable public CDN, with extra host and access-control checks.
Two advanced cases change resolution:
- A document
<base href="...">affects relative URL resolution, including root-relative URLs when the base points to another origin. - A site deployed under
/project/may not serve anything at the host-root/favicons/; its correct public path could be/project/favicons/.
Use the URL constructor mental model: resolve the literal href against the page's effective base URL, then test that absolute result.
Understand every HTML attribute
rel
rel="icon" identifies a browser icon candidate. rel="apple-touch-icon" is Apple's separate home-screen convention. rel="manifest" points to installed-app metadata.
href
This is a URL, not a filesystem path. Backslashes, repository paths, and C:\... do not belong here.
type
This is a hint describing the image media type. Common values include image/png and image/svg+xml. ICO responses are commonly served as image/x-icon or image/vnd.microsoft.icon; omitting type on the ICO fallback avoids making an incorrect claim.
sizes
For raster images, use intrinsic dimensions such as 32x32. For a scalable icon, sizes="any" tells the user agent it can scale. This attribute does not resize or validate the underlying file.
media
Browsers can choose icons based on a media query. A light/dark SVG pair can be declared like this:
<link
rel="icon"
href="/favicons/icon-light.svg"
type="image/svg+xml"
media="(prefers-color-scheme: light)"
/>
<link
rel="icon"
href="/favicons/icon-dark.svg"
type="image/svg+xml"
media="(prefers-color-scheme: dark)"
/>
Keep a conventional fallback and test target browsers. The HTML selection model allows the browser to consider type, media, and sizes; when candidates are equally appropriate, the HTML standard defines how later links participate in selection.
crossorigin
Do not add it reflexively. MDN notes that Chromium does not use crossorigin for rel="icon" as developers may expect. A same-origin icon avoids unnecessary cross-origin complexity.
Configure the server response
Correct markup can still fail when the asset pipeline lies about the file.
Status and body
Each icon should return a successful response whose body is the actual image. Watch for:
404 Not Foundfrom an omitted build artifact403 Forbiddenfrom hotlink or bot protection200 text/htmlfrom an SPA fallback or login page- A redirect loop between
wwwand apex hosts 500because an image optimizer tries to process ICO
MIME types
Typical mappings:
.png image/png
.svg image/svg+xml
.ico image/x-icon or image/vnd.microsoft.icon
.webmanifest application/manifest+json
If a static server does not know .webmanifest, configure the type explicitly or use a valid JSON response type and test actual target browsers.
Caching
Icons are cached aggressively across browsers, service workers, proxies, and CDNs. There are two sound strategies:
- Use versioned filenames with long immutable caching, then update declarations during a redesign.
- Keep a stable URL with a shorter or revalidating policy, purge it deliberately, and preserve that stable location for Google Search.
For a search-facing icon, Google asks for a stable URL. Do not generate a new hashed filename on every unrelated deploy. Inspect cache-control, etag, last-modified, vendor cache headers, and actual bytes before blaming the browser.
Content Security Policy
A restrictive policy or extension can block image loads. Open the Console and look for a CSP violation. Ensure the icon's origin is allowed by the site's relevant image policy, especially when the file lives on a CDN.
Verify everything after deployment
Automated scan
Run the final page through the Favicon Checker. It discovers declared browser and Apple icons, resolves URLs, fetches them, and reports common omissions. It does not replace manifest, device, or Search testing.
Direct command-line checks
curl -Ls https://example.com/ | grep -iE 'rel=["'"'](icon|apple-touch-icon|manifest)'
curl -sS -L -D - -o /tmp/favicon.ico https://example.com/favicons/favicon.ico
file /tmp/favicon.ico
curl -sS https://example.com/favicons/site.webmanifest
If curl -I fails, repeat with GET as shown. Some servers implement the methods differently.
Browser checks
- Open DevTools Network and enable Disable cache.
- Reload and filter for icon and manifest requests.
- Inspect final URLs, status, content type, and response preview.
- Check the rendered
<head>for duplicates. - Test a private profile and another browser.
- Save to an iOS home screen when Apple coverage matters.
- Install the PWA when manifest coverage matters.
Google Search checks
Google needs the icon declaration on the hostname's homepage, a square crawlable file, and time to reprocess it. A browser tab updating immediately does not mean Search will. Use the full Google Search icon troubleshooting guide.
Common mistakes and fixes
| Symptom | Cause | Fix |
|---|---|---|
Works on /, fails on nested pages | Path-relative href resolves inside each route. | Use the correct root or deployment-base path. |
| Icon URL displays the app | Catch-all route returns HTML. | Exclude static assets from the fallback. |
| Works locally, 404s in production | File was not copied into published output. | Inspect build artifact and deploy root. |
| Browser shows an old logo | Cache, service worker, or CDN still has old bytes. | Compare direct response, purge deliberately, update cache version. |
| Apple shortcut uses a screenshot | Touch icon is absent or invalid. | Add and test a 180x180 Apple icon. |
| Installed icon is cropped | Standard artwork ignored maskable safe zone. | Export a separate maskable asset and declare its purpose. |
| Search shows a globe | Homepage/image is not eligible or not reprocessed. | Check Google requirements and request homepage recrawl. |
| SVG looks blank | Missing square viewBox, CSS dependency, or poor contrast. | Make the SVG self-contained and preview small. |
| Duplicate network requests | Several metadata systems declare competing candidates. | Remove obsolete tags and keep one deliberate set. |
Release checklist
- Source artwork is square, simple, and legible at 16px.
- Every asset exists in the published output.
-
hrefvalues resolve on/and nested routes. - The shared
<head>contains one intentional set of declarations. - Raster
sizesmatch intrinsic dimensions. - Direct GET requests return images, not HTML.
- Content types match the files.
- The manifest is valid JSON and every
srcworks. - Apple and maskable assets have been tested on relevant devices.
- Cache and CDN headers match the update strategy.
- No CSP, WAF, or authentication rule blocks public assets.
- The production hostname passes automated and manual checks.
Frequently asked questions
Can I use only favicon.ico?
Yes for basic browser coverage. Add modern PNG or SVG, Apple, and manifest assets when those surfaces matter. A multi-size ICO is still a useful fallback.
Does the favicon have to be in the root directory?
No. It can live in /favicons/, on a deployment base path, or at an absolute CDN URL. The declaration must point to the exact public location. Root /favicon.ico remains a helpful conventional fallback.
Should the link go before or after the title?
Both belong in <head> and their relative order is rarely the problem. Ordering matters when several icon candidates are equally appropriate, so keep candidate declarations grouped and intentional.
Can I use JPG?
Some user agents support it, but JPG has no transparency and is a poor default for tiny graphic marks. PNG, ICO, and SVG cover common favicon needs more predictably.
Why not base64-encode the icon in the HTML?
Data URLs can work in selected browsers but are awkward for external crawlers, caching, inspection, and cross-platform reuse. A stable public asset URL is easier to verify.
Do I need browserconfig.xml?
Most current browser installations do not depend on it. Keep it only when a historical Microsoft pinned-tile target is part of your compatibility requirements; otherwise it is optional.
How do I change an icon without confusing caches?
Verify new bytes at the origin, purge the CDN, update any service-worker cache, and test a clean profile. Use a deliberate filename transition for a rebrand, then settle on a stable final URL rather than rotating it continuously.
Primary references
- WHATWG HTML: Link type
icon - MDN:
relattribute and icon selection - MDN: Web app manifest icons
- Apple: Configuring web applications
- Google Search Central: Favicon requirements
The durable installation is the one you can explain: a small set of purpose-built files, explicit public URLs, valid image responses, and tests on the real surfaces your visitors use.
