The favicon is the one image on your site you have never actually looked at. You looked at the 512 pixel export in your design tool, thought it was fine, and uploaded it. The browser is showing a 16 pixel version of that file, wedged between eleven other tabs, and at that size your careful lettering has collapsed into three grey pixels that could belong to anybody.
The rest of the set fails in ways you can see, once you go and look. On an Android home screen the launcher puts a circular mask over the icon and the corners of your logo are gone. On an iPhone the transparent background you exported turns black, so a dark mark disappears into a dark tile. In Chrome’s install dialog the icon is soft, because the only file the manifest offered was 192 pixels and it is being drawn much larger.
The old answer to all of this was a generator that handed you thirty two files, a browserconfig.xml and fourteen lines to paste into your head. Most of those files are addressed to browsers that stopped shipping years ago. What a site needs in 2026 is six images, one JSON file and about five lines of markup.
The short list
Two PNGs at 16 and 32 for the browser tab, bookmark lists and history. One apple-touch-icon at 180, opaque, for the iOS home screen. A 192 and a 512 for Android and for the install dialog, both named in the manifest rather than in the head. One 512 marked maskable, drawn with room around it, so Android has something safe to cut into a circle. And a site.webmanifest that ties the last three together.
<link rel="icon" href="https://cdn.wp-image-editor.com/icons/favicon-32.png" sizes="32x32" type="image/png">
<link rel="icon" href="https://cdn.wp-image-editor.com/icons/favicon-16.png" sizes="16x16" type="image/png">
<link rel="apple-touch-icon" href="https://cdn.wp-image-editor.com/icons/apple-touch-icon.png" sizes="180x180">
<link rel="manifest" href="https://cdn.wp-image-editor.com/icons/site.webmanifest">
<meta name="theme-color" content="#3B66FF">
That is the whole head block. Everything Android touches is reached through the manifest, which is why the head has shrunk so much: one line replaces the dozen link rel="icon" tags that generators used to emit for every Chrome size. The tool below takes one image or SVG and produces the thirteen PNGs, the head block and the manifest, with the file paths already pointing at wherever you plan to put them. It runs entirely inside this browser tab: nothing is uploaded, and your logo never leaves your device.
Favicon and app icon generator
Drop in one image, ideally square and at least 512 px, or an SVG, and get every favicon and app icon a site needs, with the head block and the manifest that point at them. Nothing is uploaded: the image is decoded, padded and re-encoded on a canvas inside this browser tab.
16 px is the browser tab, 32 px is the same tab on a retina screen and the bookmarks bar. Everything else is an app icon that people see once.
Android crops a maskable icon to its own shape, a circle, a squircle or a rounded square. Only the dashed circle, 80% of the width, is guaranteed to survive. Everything dimmed can be cut away.
The files you can stop generating
A generator from 2014 gave you apple-touch-icon-57x57 through -152x152, because iOS once picked its icon by file name and every device generation had its own. That ended with the 180 pixel icon, which iOS has scaled for every screen since. The mstile PNGs and browserconfig.xml drove Windows 8 start tiles through Internet Explorer, which was retired in 2022, and Windows 11 has no live tiles at all. The safari-pinned-tab.svg and its rel="mask-icon" were for the monochrome pinned tab strip in Safari 9 to 11; Safari has preferred the ordinary icon since Safari 12. The android-chrome-36x36 family predates the manifest. None of it hurts if it is already on your server, but every extra tag in the head is one more thing that goes stale when the logo changes.
Sixteen pixels is a different drawing
Scale is the part people get wrong, and the arithmetic is blunt. 16 divided by 512 is one thirty second. A 6 pixel hairline in your 512 master is 0.19 of a pixel in the tab. The rasteriser cannot draw a fifth of a pixel, so it draws a whole one at roughly a fifth of the opacity, and you get a pale grey ghost of a line. To land one solid pixel at 16, a stroke has to be 32 pixels wide in the 512 master. Almost no logo is drawn that heavily.
Count the budget the other way. A 16 pixel icon is 256 pixels in total, and once the mark is inset you are drawing inside about 180 of them. That is not enough for a wordmark, a gradient and a thin outline. It is enough for one shape and maybe one counter inside it.
The tool measures this rather than leaving it to taste. It draws your mark at 16 pixels, scales that back up to full size with the same interpolation, and compares the edge energy of the result with the edge energy of the mark drawn properly. What survives is the structure a browser tab can still show. Below 62 per cent you get a warning, because that is the point where the shape people recognise has stopped arriving. A clean, chunky mark gets a positive line instead.
When the warning appears, the fix is not a sharpen filter. It is a second drawing: thicker strokes, the wordmark dropped, often just the initial or the symbol alone. Feed that simplified version through for 16 and 32, the full logo for 180 and up, and keep both files. The tool handles one source at a time, so that means two passes, which is the honest shape of the job.
The maskable icon and Android’s safe circle
Android does not show your icon as the square you exported. The launcher applies a mask, and which one depends on the device and the skin: a circle, a squircle, a rounded square, on some phones a teardrop. Give it an ordinary icon and it is either clipped or dropped onto a white square with a shadow, which looks like a sticker.
A maskable icon is the deal you strike with that. You promise that everything important sits inside a centred circle whose diameter is 80 per cent of the icon, and the platform promises never to cut inside that circle. On a 512 pixel canvas the safe circle is 409.6 pixels across, so nothing that matters may sit further than 204.8 pixels from the centre.
That is the measurement the tool reports as ink radius, in half widths from the centre: 1.0 means the ink reaches the middle of an edge, and the safe limit is 0.80. The consequences are not intuitive. A square logo that bleeds to the edges has corners at 1.41, so it has to shrink to 57 per cent of the canvas width, which is 22 per cent padding on each side. A circular mark needs only 10 per cent. A wide 4:1 wordmark can be 78 per cent of the width, because its half diagonal is barely longer than its half width. Wide and flat survives a round mask better than square does.
In the tool, the maskable preview dims everything outside the safe circle, so you see exactly what a launcher is allowed to keep. The padding slider runs from 0 to 35 per cent with the value echoed beside the label, and “Fit inside the circle” jumps to the padding your mark needs, then switches itself off because there is nothing left to fix.
Padding is deliberately not applied everywhere. Inset the 16 pixel icon by 22 per cent and you have thrown away width you did not have. So padding and the background colour touch only the apple-touch-icon and the maskable file, and the note under the controls says so. For a consistent inset across the whole set, “Pad and fill every PNG” is there, off by default, and the note changes to match.
Why iOS turns your transparency black
The iOS home screen icon has never supported an alpha channel. Transparent pixels are composited onto black, so a dark logo exported on nothing arrives as a dark logo on a black tile, and a logo with a soft transparent glow around it arrives with a dark halo. iOS also rounds the corners itself, which is why pre-rounded corners come out looking clipped and slightly wrong.
So the apple-touch-icon is always drawn on an opaque tile, and the background colour control decides what that tile is. Picker and hex field stay in step, an invalid hex is refused and the last good colour is kept, so a half typed value never turns the tile black on you. That colour is also what goes into the manifest as background_color.
The theme colour is a separate control doing a separate job. It is the meta name="theme-color" tag and the manifest’s theme_color, and it tints browser chrome: the address bar area on Android, the window furniture around an installed app. Matching it to the tile background is a reasonable default, but they are not the same field. If you have not settled on the colour yet, choosing a palette from one decision beats sampling something out of the logo and hoping.
The manifest fields that matter
A web app manifest can carry a couple of dozen keys. Five decide how your icon behaves. name and short_name are what appears under the icon on a home screen, and short_name is the one that survives on a phone. The icons array carries the files, each with src, sizes and type. theme_color and background_color are the two colours above.
{
"name": "Northlight Studio",
"short_name": "Northlight",
"icons": [
{ "src": "https://cdn.wp-image-editor.com/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "https://cdn.wp-image-editor.com/icons/icon-512.png", "sizes": "512x512", "type": "image/png" },
{ "src": "https://cdn.wp-image-editor.com/icons/maskable-512.png", "sizes": "512x512",
"type": "image/png", "purpose": "maskable" }
],
"theme_color": "#3B66FF",
"background_color": "#0E1013"
}
The field doing the real work is purpose. Its default is any, meaning the launcher may not crop and will usually add its own plate behind the icon. Only an entry marked maskable tells the platform it may cut, because you have promised the safe circle. Mark your only icon maskable and every context that does not crop, an install dialog for instance, shows your mark floating small inside its padding. Keep the entries separate, which is what the generated manifest does.
The manifest the tool writes covers six icon sizes, the maskable entry, the app name and the two colours. It does not write start_url, scope or display: those decide whether your site behaves as an installed application, which is a larger decision than an icon set. Add them by hand when you want that.
What the WordPress site icon covers
WordPress has had this built in since 4.3. The field lives in Settings, General on current versions and in the customizer on themes that still put it there. It refuses anything under 512 pixels square, hands you a cropper, and stores the attachment ID in the site_icon option.
On upload it registers four extra crop sizes, site_icon-270, site_icon-192, site_icon-180 and site_icon-32, and generates those files alongside everything your theme already asks for. They are ordinary intermediate sizes and behave like the rest of the pile, which the breakdown of every file a single upload creates goes through properly. Then wp_site_icon(), hooked to wp_head at priority 99, prints exactly four tags: an icon at 32×32, an icon at 192×192, an apple-touch-icon with no sizes attribute at all, and an msapplication-TileImage at 270 for those retired Windows tiles.
Read that against the short list at the top and the gaps are obvious. No 16 pixel file, so a 1x display gets the 32 squeezed down by the browser. No manifest link, no theme-color, and above all no maskable icon, so every Android home screen is cropping or plating a square that was never drawn for it. Core gives you the tab and the iOS tile, not the installed app.
There is one thing core does quietly well. Request /favicon.ico on a WordPress site with no real file at the web root and the request reaches PHP, where the template loader recognises it and redirects to get_site_icon_url( 32 ), falling back to the WordPress logo if no icon is set. The old crawlers get served without you writing an ICO container at all.
For everything core leaves out, one hook does it. Priority 100 puts your tags after core’s, so the two sets read in a sensible order in the source.
add_action( 'wp_head', function () {
echo '<link rel="icon" href="https://cdn.wp-image-editor.com/icons/favicon-16.png" sizes="16x16" type="image/png">' . "n";
echo '<link rel="manifest" href="https://cdn.wp-image-editor.com/icons/site.webmanifest">' . "n";
echo '<meta name="theme-color" content="#3B66FF">' . "n";
}, 100 );
That belongs in a small plugin or a child theme’s functions.php, not the parent theme’s header.php, where the next update removes it. If you are unsure what belongs in that file, the guide to functions.php is the safer starting point. Keep the site icon set as well: the same function runs on login_head.
Where the tool stops
No .ico file is produced, on purpose, which is why the head block references PNGs only. ICO is a container that packs several bitmaps into one file, and it only matters when something asks for that file by name, a case the WordPress redirect above already covers. If you truly need the container, for an intranet with ancient clients, use a desktop converter.
There is no SVG favicon output either. A single SVG icon with a prefers-color-scheme query inside it is a genuinely elegant trick for dark browser chrome, and Chromium and Firefox honour it, but Safari has been the laggard, so the 32 pixel PNG has to exist anyway. If you go that route, run the file through a cleaner first, because an export straight out of a design tool carries editor metadata and sometimes a script node. Cleaning an SVG before it goes anywhere near your site covers what to strip and why.
An SVG dropped into the generator is treated as untrusted. It is parsed in its own document, script elements, on* handlers and references to other servers are removed, then it is serialised again and rasterised through an img, never inserted into the live page. A raster source is reduced to a 1024 pixel base before any icon is drawn, ample headroom for a 512 pixel target, and the canvas re-encode drops EXIF, GPS and colour profiles. An animated GIF contributes its first frame.
Two warnings are worth taking seriously. Under 512 pixels on the shorter side means the large outputs are upscaled and the install dialog will show it. A non-square source is centred with the rest left transparent, which is rarely what anybody wants: crop it square first. The rest is convenience. Clicking any card downloads that file, “Download all” takes the set, and both copy buttons select the field first so the keyboard shortcut works even when the clipboard API does not.
One performance note, because you will see it. A full thirteen file pass costs about 70 milliseconds on a photographic source, too slow to run on every step of a slider. So dragging the padding slider redraws only the three icons the previews show, dims the card grid and says “redrawing at every size”, and the full set lands 180 milliseconds after your hand comes off.
Where this leaves your header
The icon set is one of the few parts of a site where the correct answer got shorter over a decade rather than longer. Platforms stopped asking for a file per device and started reading one manifest. If your head still carries fourteen icon tags and a browserconfig.xml, you are maintaining a museum in a place nobody looks, so it will keep pointing at the old logo long after the redesign.
What remains hard is not the file list. It is that one drawing has to work at 16 pixels in a tab and at 512 behind a circular mask, and those contexts want opposite things: maximum weight and no detail on one side, breathing room on the other. That is why the two measurements matter more than the file count. Ink radius tells you whether a mask will cut you and how much padding fixes it. Edge energy at 16 tells you whether the mark you are proud of is arriving at all. Both are numbers you can act on, unlike squinting at a tab.
Set the site icon in WordPress so the tab and the iOS tile are handled, generate the set, add the three missing lines on wp_head, and then do the thing almost nobody does: open the site on an Android phone, add it to the home screen, and look at what the launcher kept. It takes a minute and it is the only test that matters, because that is the size everybody else sees.