avicon
Tutorial

How to Add a Favicon to a Static HTML Site

The exact <link> tags a plain HTML site needs in <head>, explained line by line.

· 5 min read

Quick answer: put your icon files in the site root and add a handful of <link> tags inside <head> — one for favicon.ico, one or two sized PNGs, one apple-touch-icon, and one pointing at your site.webmanifest — and every browser and OS will pick up the right size on its own.

This is the framework-agnostic version of favicon setup: no build step, no file conventions, just plain HTML tags in <head>. If you're working in a framework instead, the Next.js guide or the React guide covers the equivalent for those, but the underlying tags are the same ones described here either way.

Why tags at all, if browsers already check /favicon.ico?

Before getting into each tag, it's worth knowing that browsers have a built-in fallback: if a page has no favicon <link> tags at all, most browsers will still automatically request /favicon.ico at the site's root and use it if it exists. That's why plenty of old sites "just work" without ever touching <head>.

But that fallback only covers one file, one format, and one use case: the browser tab. It says nothing about iOS home-screen icons, Android/PWA manifest icons, or serving different resolutions to different pixel densities. The <link> tags below exist to take control of all of that deliberately, rather than leaving it to whatever a browser happens to guess.

The tags, one at a time

favicon.ico

<link rel="icon" href="/favicon.ico" sizes="any" />

This declares your classic multi-resolution ICO file — typically bundling 16×16, 32×32, and sometimes 48×48 pixel versions inside one container file. The sizes="any" attribute tells the browser this file can supply any size, so it's a safe universal fallback alongside the more specific PNG tags below. Even in 2026, this file is worth keeping; our guide on whether ICO is still needed goes into exactly why.

The sized PNGs

<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />

These give the browser exact PNG files at exact sizes, rather than making it extract a size from inside the ICO container. Browsers generally prefer using the size that matches their actual rendering context most closely — 32×32 for higher-density tab rendering, 16×16 for standard density — so shipping both avoids any resampling on the browser's end.

The Apple touch icon

<link rel="apple-touch-icon" href="/apple-touch-icon.png" />

This is what iOS and iPadOS use when someone taps "Add to Home Screen" in Safari, and it's also what shows in Safari's pinned-tab and top-sites views. If you're only shipping one size, 180×180px is the safe modern target and you don't need a sizes attribute at all — Safari will use it regardless of the declared size. If you want to be explicit, or you're shipping more than one apple-touch-icon size, you can add sizes="180x180" the same way you would for the PNG favicon tags. Skip this tag entirely and iOS falls back to a screenshot of the page instead of an icon — see favicon vs. apple-touch-icon for the full difference between the two.

The web app manifest

<link rel="manifest" href="/site.webmanifest" />

This points at a JSON file describing your app's Android and PWA icons — typically 192×192 and 512×512px versions — along with metadata like the app's name and theme color. The icons declared inside the manifest are separate from everything above; they're not read from your <link rel="icon"> tags. Our manifest icons guide covers what belongs inside that JSON file and why it needs its own icon sizes.

The complete snippet

Put together, a solid modern favicon setup looks like this:

<head>
  <link rel="icon" href="/favicon.ico" sizes="any" />
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
  <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
  <link rel="manifest" href="/site.webmanifest" />
</head>

Every file referenced here needs to actually exist at that path with that exact name, or you'll get quiet 404s in the console — annoying to debug later, since a missing icon file doesn't break the page, it just silently fails. If you'd rather not hand-export five files and get the naming right yourself, the favicon generator produces this entire set — ICO, both PNG sizes, the touch icon, and the manifest — from one source image or icon in a single pass.

Where the tags go, and whether order matters

All of these tags must live inside <head>, not <body> — placing them outside <head> means browsers will typically ignore them entirely. Within <head>, the order doesn't functionally matter to browsers; they'll parse whichever <link> tags are present regardless of sequence. The convention of listing favicon.ico first, followed by PNGs, then the touch icon, then the manifest, is just for human readability when someone else opens your source later — it's not something any browser checks for.

Confirming it actually works

Once the tags are in place, open your site and check the Network tab in dev tools for each icon path — you're looking for 200 responses, not 404s. Because favicons are cached far more aggressively than most assets, a browser tab that was already open before your change may keep showing the old icon well after the new files are live; a private window or a completely different browser is a more reliable check. For a check that bypasses your own browser's cache entirely, run the live URL through a favicon checker to see exactly what's being served. If something's still not showing up after that, common favicon-not-showing causes and fixing a 404 in the console cover the usual reasons.

Try the Generator

Drop in artwork, type a word, or pick an emoji. Watch it land in a real browser tab, then export every size a modern site needs.

Open Generator