Favicon ICO — Create and Implement .ico Files for Your Website
The favicon.ico file is the icon shown in browser tabs, bookmarks, and history. Here's how to create an ICO file, what sizes it needs, and how to add it to your HTML properly.
The favicon.ico file is a special image format that browsers look for automatically at the root of your website. It appears in browser tabs, bookmarks, search results, and desktop shortcuts. Getting it right requires understanding the ICO format, required sizes, and correct HTML implementation.
Use the Favicon Generator to create favicon.ico files from any image.
What is the ICO format?
ICO is a container format — a single .ico file can embed multiple images at different sizes. Browsers pick the most appropriate size for the context (16×16 for tabs, 32×32 for taskbars, 48×48 for desktop shortcuts).
A complete favicon.ico for modern browsers typically contains:
| Size | Purpose |
|---|---|
| 16×16 | Browser tab (primary use) |
| 32×32 | Taskbar shortcut, Windows desktop |
| 48×48 | Windows shortcut |
| 64×64 | High-DPI contexts |
Not all sizes are required. At minimum, 16×16 and 32×32 cover most cases.
How browsers find your favicon
Browsers check two places:
1. Default location (no HTML needed):
https://yourdomain.com/favicon.ico
Browsers automatically request this URL for every site. If the file exists, it loads. This is the safest approach — works even in contexts where your <head> tags aren’t loaded.
2. HTML link element:
<head>
<link rel="icon" href="/favicon.ico" type="image/x-icon">
</head>
Use the HTML approach when:
- Your favicon isn’t at the root (e.g., it’s in
/static/icons/) - You want to specify different icons for different pages
- You’re using multiple formats (SVG, PNG, ICO)
Creating favicon.ico
From a PNG (command line, ImageMagick)
# Single-size ICO:
convert favicon-32.png favicon.ico
# Multi-size ICO (recommended):
convert favicon-16.png favicon-32.png favicon-48.png favicon.ico
# From a high-res source image:
convert source-512.png -define icon:auto-resize=64,48,32,16 favicon.ico
Node.js (to-ico)
import toIco from 'to-ico';
import fs from 'fs/promises';
async function createFavicon() {
// Read PNG files at different sizes:
const images = await Promise.all([
fs.readFile('favicon-16.png'),
fs.readFile('favicon-32.png'),
fs.readFile('favicon-48.png'),
]);
// Combine into ICO:
const ico = await toIco(images);
await fs.writeFile('favicon.ico', ico);
console.log('favicon.ico created');
}
createFavicon();
Python (Pillow)
from PIL import Image
def create_favicon(source_path, output_path='favicon.ico'):
"""Create multi-size favicon.ico from a source image."""
img = Image.open(source_path).convert('RGBA')
sizes = [(16, 16), (32, 32), (48, 48), (64, 64)]
# Generate each size:
resized_images = []
for size in sizes:
resized = img.resize(size, Image.LANCZOS)
resized_images.append(resized)
# Save as ICO (first image sets the container, rest are added automatically):
resized_images[0].save(
output_path,
format='ICO',
sizes=sizes,
append_images=resized_images[1:]
)
print(f'Created {output_path}')
create_favicon('logo-512.png')
Complete favicon HTML setup
Modern browsers support multiple favicon formats. A robust setup:
<head>
<!-- ICO: fallback for all browsers including IE -->
<link rel="icon" href="/favicon.ico" sizes="any">
<!-- SVG: modern browsers, scales to any size -->
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<!-- PNG: for specific sizes when SVG isn't supported -->
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<!-- Apple touch icon: iOS home screen icon -->
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<!-- Web manifest: Android and PWA -->
<link rel="manifest" href="/site.webmanifest">
</head>
Browser priority (highest to lowest):
- SVG (Chrome, Firefox, modern browsers)
- PNG at matching size
- ICO (fallback)
Adding favicon to popular frameworks
Next.js (App Router)
// app/favicon.ico — just place the file here, Next.js handles it automatically
// Or use metadata API for more control:
// app/layout.tsx
export const metadata = {
icons: {
icon: '/favicon.ico',
shortcut: '/favicon-16x16.png',
apple: '/apple-touch-icon.png',
},
};
Vite / React
<!-- index.html -->
<head>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
</head>
Place favicon.ico in /public/ — Vite serves it at the root automatically.
Astro
<!-- src/layouts/Base.astro -->
<head>
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
</head>
Place icons in /public/ — Astro copies them to the build output root.
Testing favicon implementation
Check browser tab: Open your page. The icon should appear in the browser tab within a few seconds.
Check different contexts:
- Bookmark the page — does the icon appear in bookmarks?
- On Windows: create a desktop shortcut — does the correct size display?
- On iOS: add to home screen — does the apple-touch-icon appear?
Browser cache: Browsers aggressively cache favicons. After updating, clear cache or use incognito mode to see changes.
Favicon checker tools:
- Browser DevTools → Network tab → filter by “favicon” to see which file loaded
- Check for 404 errors in the console
Common favicon mistakes
Missing favicon.ico at root: Even with <link> tags, some contexts (RSS readers, API clients, link preview crawlers) only check /favicon.ico. Always keep one there.
Wrong MIME type: Serving ICO as image/ico instead of image/x-icon can cause some browsers to reject it. Use image/x-icon or image/vnd.microsoft.icon.
Too small source: Designing at 16×16 makes the icon look pixel-art at larger sizes. Design at 512×512 and downscale — let the resize algorithm do the work.
Not handling dark mode: A white logo on white favicon is invisible on light-mode browsers. For SVG favicons, you can use CSS prefers-color-scheme to adapt:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<style>
@media (prefers-color-scheme: dark) {
path { fill: white; }
}
path { fill: black; }
</style>
<path d="M16 2..."/>
</svg>
Related tools
- Favicon Generator — generate favicon.ico from any image
- How to Add Favicon — complete implementation guide
- SVG Favicon Guide — modern vector favicons
Related posts
- Apple Touch Icon — Add an iOS Home Screen Icon to Your Website — The apple-touch-icon is the image iOS uses when someone adds your site to their …
- Favicon Caching — Force Browser Refresh After Favicon Change — Browsers aggressively cache favicons, sometimes for days or weeks. Learn how to …
- Favicon Size Guide — All the Sizes You Need for Every Browser and Device — Favicons require multiple sizes for browsers, mobile home screens, and bookmarks…
- Favicon Size Requirements — Complete Guide to Favicon Dimensions — Favicons need to be provided at multiple sizes for different contexts: 16×16 for…
- How to Add a Favicon to Your Website — Complete Guide — Adding a favicon requires placing the icon file and linking it in HTML. Here's h…
Related tool
Generate favicon package from any image or emoji. Multiple sizes (16, 32, 48, 180, 192, 512), manifest.json, and HTML snippet.
Written by Mian Ali Khalid. Part of the Frontend & Design pillar.