Coding agents can place a favicon, but can't see it

Ask a coding agent to “add a favicon” and watch it work. Within a minute it has found the right folder, written plausible markup, added a manifest and produced a tidy diff. The pull request looks finished. Then you open the site on a phone, or in a dark browser tab, and the icon is a black square, a logo with its corners cut off, or a smudge nobody can read at 16 pixels.

Nothing went wrong with the code. The agent solved the part of the favicon problem that is made of text — file paths, <link> tags, JSON — and never saw the part that is made of pictures. Favicons live in both worlds at once, which is why this small task is such a clean example of where coding agents are strong, where they are blind, and how to split the work so you get the best of both.

What a coding agent gets right: the plumbing

Favicon integration is, at its core, a set of conventions. Conventions are exactly what agents are trained on and good at applying. Given a project, a competent agent will usually:

  • Put files where your stack expects them. In a Vite or Create React App project that is public/, referenced from public/index.html; in Next.js App Router it is the file conventions — app/favicon.ico, app/icon.svg, app/apple-icon.png — which Next.js turns into tags for you. On a plain site it is the web root.
  • Write the standard <head> block and keep it in the shared layout so every page declares the same icons.
  • Generate or update site.webmanifest with a name, theme and background colours, and the icon entries Android and Chromium read.
  • Explain the change sensibly — which files it added, what it removed, and why.

The target markup is short and well known. A complete modern set looks like this:

<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
<link rel="shortcut icon" href="/favicon.ico" sizes="32x32" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="manifest" href="/site.webmanifest" />

An agent can produce that block from memory, adapt the paths to your framework and wire it into a template it has never seen before. Let it. That is real work, done quickly and usually correctly. Our framework guides cover the two most convention-heavy cases if you want to check its answers: favicons in Next.js and favicons in a React app.

What it cannot judge: the picture

Here is the other half of the job — the half no diff can show you. Every item below is a visual judgement made in a context the agent does not render: a browser chrome theme, a phone launcher, a search results page.

Is it still readable at 16 pixels?

A favicon spends its life at 16×16 or 32×32 pixels in a tab. At that size a full logo lockup — symbol, wordmark, tagline — collapses into noise. Someone has to shrink the artwork, look at it, decide to drop the text, thicken the strokes or enlarge the symbol, and look again. An agent can resize a file to 16 pixels perfectly; resizing is arithmetic. Judging whether the result is recognisable is taste applied at a size the agent never displays to itself.

Does transparency turn it black on iOS?

The 180×180 Apple Touch Icon must be opaque: iOS fills transparent areas with black, so a neat transparent logo becomes a dark tile with a darker logo on it. The file an agent copies from your brand assets is very often transparent, because that is how logos are supplied. The bug is invisible in the code and obvious on a home screen — if anyone looks at one. The Apple Touch Icon guide shows the failure and the fix: bake a deliberate background into the PNG itself.

Does the Android mask crop the logo?

Android launchers mask home-screen icons into circles, squircles and other shapes, keeping only the central safe zone — a circle about 80% of the icon across — guaranteed visible. A logo drawn edge to edge loses its corners; a wordmark loses its first and last letters. A maskable icon therefore needs a full-bleed background with the mark shrunk into that central circle. An agent can write "purpose": "maskable" into a manifest flawlessly while pointing it at artwork that was never designed to be masked. See manifest and maskable icons explained for the geometry.

Does it survive the dark tab?

A dark navy mark on a transparent background can vanish against a dark browser tab bar. The one format that can adapt is SVG, with a @media (prefers-color-scheme: dark) switch inside the file; the PNG, ICO and touch icons are fixed pictures that must be designed to survive both themes, ideally with a background of their own. Choosing that dark variant — brighter tint, maybe its own background, slightly bolder strokes — is again a matter of looking at both versions at real size, as covered in SVG favicons and dark mode.

Does Google get a usable icon?

Google shows a favicon beside your site name in search results and asks for a square icon in a supported raster format (PNG and ICO are on its list; SVG is not), at least 8×8 pixels and ideally larger than 48×48, at a stable, crawlable URL. An agent asked for “a favicon” may hand Google a 32×32 PNG (below the recommended size), or helpfully rename the file every iteration and restart Google’s slow refresh each time. The compliance details are in the favicon sizes and formats cheat sheet.

A nuance worth stating fairly: some agents can open an image file, and multimodal models can describe one. That is not the same as previewing the icon in situ — at 16 pixels, in a dark tab, masked into a circle, composited on black by iOS, next to competing icons on a real home screen. The checks that catch favicon failures are comparisons across those contexts, and they take a person (or a tool built for it) seconds with the right previews in front of them.

The failure pattern: a correct diff with the wrong files

When an agent-led favicon goes wrong, it is rarely because the markup is broken. It is because the agent had to source the artwork somehow, and every shortcut it takes is invisible in review:

  • It reuses the website logo as-is — transparent, wide, detailed — and scales it down into every slot, including the touch icon and the maskable icon.
  • It renames instead of converting. A JPEG saved as favicon.png, or a single-size PNG saved as favicon.ico, may be accepted by one browser and silently rejected by another. The file name in the diff tells you nothing.
  • It declares only the modern icon, or only the legacy one. SVG-only leaves out Safari 18 and earlier’s tab icon, Google Search and the platform icons; ICO-only gives up crisp scaling, dark mode and any say over home screens.
  • It mixes two systems. In Next.js, dropping files into app/ and pasting manual <link> tags can produce duplicate or competing declarations. In any stack, two sets of tags — one from a theme or plugin, one from the agent — means the browser, not you, picks the winner.
  • It upscales a small source. A 512×512 manifest icon generated from a 64×64 upload is technically 512 pixels of blur, and it is the version Android shows largest.

Code review catches none of this, because there is almost no code. The review that matters is opening the previews.

A better workflow: design visually, then hand over the package

The reliable division of labour is simple: a person designs the icon with live visual previews, the agent integrates the finished package, and a checker verifies the deployed result. It looks like this:

  1. Start from the best source. Use the original SVG logo, or a square PNG of at least 512×512. If the mark is detailed, simplify it for small sizes before generating anything.
  2. Design the variants where you can see them. In EasyFaviconGenerator, adjust background, margins and corner handling while watching the icon in light and dark browser tabs and in light and dark Google results; set the dark-mode variant for the SVG; check the iOS preview for an opaque, uncrowded touch icon and the Android previews for the masked home-screen and splash views. This ten-minute visual pass is the step the agent cannot do for you.
  3. Download the complete package. That means favicon.svg, favicon-96x96.png, favicon.ico, apple-touch-icon.png (180×180), the 192×192 and 512×512 manifest icons, site.webmanifest and the matching HTML snippet — generated from one artwork pass, so the sizes agree with each other. The generator runs in your browser, so an unreleased logo is never uploaded.
  4. Hand the package to the agent with precise instructions (next section), and let it place files and edit templates.
  5. Verify the deployed site, not the local files — the step after that.

What to tell your agent: a handoff prompt that works

Agents follow constraints well when the constraints are explicit. The vague request “add a favicon” invites invention; the request below removes the decisions the agent should not be making. Adapt the paths to your stack and paste it with the downloaded files:

Add this favicon package to the project. The files are final artwork:
do not regenerate, resize, rename or re-encode them.

1. Copy the files to the location this project serves static
   assets from, keeping these names: favicon.svg,
   favicon-96x96.png, favicon.ico, apple-touch-icon.png,
   web-app-manifest-192x192.png, web-app-manifest-512x512.png,
   site.webmanifest. Keep favicon.ico reachable at /favicon.ico.
2. Add exactly this snippet to the <head> of the shared layout,
   adjusting only the paths if the files live elsewhere:
   <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
   <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
   <link rel="shortcut icon" href="/favicon.ico" sizes="32x32" />
   <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
   <link rel="manifest" href="/site.webmanifest" />
3. Remove any existing favicon <link> tags or generated icon
   declarations these replace, so only one set remains.
4. If this framework has an icon file convention (for example
   Next.js app/favicon.ico), use it instead of manual tags and
   tell me which convention you used.
5. Do not invent additional sizes or formats. Show me the final
   diff and list every file you added, moved or deleted.

Two lines in that prompt do most of the work. “Do not regenerate, resize, rename or re-encode” stops the agent from helpfully rebuilding your artwork from the website logo. “Remove any existing tags” prevents the duplicate-declaration problem that causes the favicon not showing up in the first place. The closing instruction — list every file — gives you a diff you can actually review.

After the agent finishes: check like a visitor, not like a compiler

A green build says the markup is valid. It says nothing about whether any platform displays the icon. Spend three minutes checking the deployed result the way visitors will meet it:

  • Open each icon URL directly — /favicon.svg, /favicon.ico, /apple-touch-icon.png, /site.webmanifest — and confirm the new artwork loads with no 404, redirect or login page in between.
  • Look at the tab at real size, then toggle your operating system between light and dark appearance and open a fresh tab: the SVG variant should switch and stay legible at 16 pixels in both.
  • Test in a private window or a second browser before blaming the deploy. Favicons sit in a persistent cache that page refreshes often do not clear; if the private window shows the new icon, your visitors are fine and only your cache is behind. Versioned URLs such as /favicon.svg?v=2 are the durable fix — ask the agent to apply one consistently, then leave the URL stable for Google.
  • Add the site to a phone home screen. On iPhone, check the tile is opaque, unclipped and recognisable among real apps; on Android, check the masked shape has not eaten the logo. Delete and re-add the shortcut after any icon change.
  • Run one automated pass. The favicon checker fetches your live page, lists every declaration it finds, validates each file’s status, format and real size, inspects the manifest and previews the icon in browser tabs, Google results, iOS and Android views. Anything surprising can be cross-checked against the compatibility matrix, which records which file each browser and platform actually uses.

If the checker is clean but your own tab still shows the old icon, you have confirmed local caching rather than a deployment problem — a much better position than redeploying at random.

Quick questions

Can I just ask the agent to draw an icon?

You can ask an image model for artwork, and it may produce a fine starting point. You still need the unglamorous second half: export the exact sizes, make the touch icon opaque, design the maskable variant around the safe zone, add the dark-mode SVG switch and preview everything at 16 pixels. Generation is not the bottleneck; verification is. Treat any generated artwork as a logo draft, then put it through the same visual workflow as any other source file.

Should I let the agent hand-edit the SVG favicon?

For mechanical edits — updating a path, fixing a viewBox, changing a colour value you specify — yes. For the dark-mode variant, give it the two colour schemes rather than asking it to choose them; it cannot see contrast at tab size. And keep the SVG self-contained: scripts and external fonts or images are not loaded in favicon context, whatever the agent may assume from normal web SVG.

What if my site has no logo yet?

Then the order matters even more. An agent can scaffold the integration around a placeholder, but deciding the mark itself — symbol, colours, how it reads at 16 pixels — is the visual decision this whole article is about. A simple bold letter or shape, checked at real size, beats a detailed placeholder that every platform renders as mush.

The short version

Coding agents know where a favicon goes: the folder, the tags, the manifest, the framework convention. They do not know what it should look like on iOS, inside an Android mask, in a dark tab or beside your competitors in Google results, because knowing that means looking at it in those places. So split the job along that line. Design the icons where the previews are — in the favicon generator — hand the agent a finished package with instructions that forbid improvisation, and verify the deployed site with the favicon checker and your own eyes. The agent still does the plumbing. You just stop asking it to see.