One Logo Has To Work In Several Places
A finished logo is not a finished icon system. Browser tabs, bookmarks, Apple home screens, Android launchers, installed web apps and shared links each read different files and crop them differently.
Do this after the logo is final and before the first deploy. Repeat it whenever the logo changes: an old icon survives in tabs, launchers and link previews long after the header has been updated.
Steps
Guide
Freeze The Source Mark Before Generating Files
Start from the icon-only SVG. Do not squeeze a wide wordmark into a square and call it a favicon.
Confirm these inputs before generating anything:
- approved SVG source
- icon-only version
- how the mark reads on light and dark tab bars
- site name and short name
- canonical site URL
- theme and background colours
At 16x16 pixels detail disappears. If the mark is unreadable at that size, simplify the source mark instead of sharpening a miniature wordmark.
- 2
Generate The Pack From That One Source
Read GuideProduce
favicon.ico, an SVG icon, a 180x180 Apple touch icon, 192x192 and 512x512 Android/PWA PNGs, and a web app manifest. Keep the raster files even when SVG is the main icon: not every browser and launcher reads SVG.The Built by meN-G.BE Favicon Generator builds the browser, Apple, Android, manifest and 1200x630 social-image files from one logo. The favicon generator comparison covers five other routes and when each one fits better.
A downloaded ZIP is an input, not proof that the site is configured. The checks at the end confirm that the public files and the rendered markup point to the intended assets.
Declare Any And Maskable Icons Separately
A normal
anyicon and amaskableicon solve different problems. Theanyicon can use transparency and a tight crop. Themaskableicon needs an opaque background and padding, because Android cuts it into a circle, squircle or rounded square: web.dev puts the safe zone at a centred circle 80% of the icon's width.Avoid
"purpose": "any maskable"on one file. Many generators still write it. It forces one image to do both jobs: without padding, Android crops the mark; with padding, every other surface shows a shrunken mark. The same set can look right on an iPhone, which uses the Apple touch icon, and wrong on Android, which reads the manifest.Check whether your pack contains a padded maskable file. If it does not, make one from the 512x512 icon in the Maskable.app editor and preview it against the common masks before accepting it.
{ "icons": [ { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-512-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } ] }The field reference is on MDN.
Install The Pack In Next.js
Pick one route and do not mix them for the same file:
- File conventions -
favicon.icoat the root ofapp, plusicon.svg(oricon.png) andapple-icon.pnginapp. Next.js writes the head tags itself. publicfolder plusmetadata.icons- the files sit inpublicand the root layout lists them with their sizes and types. This is the usual route when a generator hands you a ready-made folder.
For the manifest, either add
app/manifest.tsreturning a typed object, or keep the generator'ssite.webmanifestinpublicand pointmetadata.manifestat it. Raster icons need exact pixel sizes and a MIME type; an SVG icon takessizes: "any".Either way, open the rendered page head and check
rel,href,sizesandtype. Filenames alone prove nothing. The conventions are in the Next.js app-icon documentation and the manifest documentation.- File conventions -
Generate One 1200x630 OG Image Per Page Template
Create
opengraph-image.tsxbeside the dynamic route'spage.tsx. Load the record by slug, pick its artwork, and return anImageResponsefromnext/og. Next.js adds theog:imagetags for that route automatically.Two details break most first attempts. The renderer does not fetch a relative path such as
/media/cover.png, so read local files and pass them as a data URL, or use an absolute URL. It does not decode WebP, so keep PNG or JPEG copies of the artwork for the social image.import { readFile } from "node:fs/promises"; import path from "node:path"; import { ImageResponse } from "next/og"; export const size = { width: 1200, height: 630 }; export const contentType = "image/png"; const FALLBACK = "/og/placeholder.png"; async function toDataUrl(publicPath: string) { const file = await readFile(path.join(process.cwd(), "public", publicPath)); return `data:image/png;base64,${file.toString("base64")}`; } export default async function OpenGraphImage({ params, }: { params: Promise<{ slug: string }>; }) { const { slug } = await params; const page = await getPage(slug); const image = await toDataUrl(page?.ogImagePng ?? FALLBACK); return new ImageResponse( ( <div style={{ display: "flex", width: "100%", height: "100%" }}> <img src={image} alt="" width={1200} height={630} /> </div> ), size, ); }Keep the layout simple.
ImageResponsesupports flexbox and a subset of CSS, and every element with more than one child needsdisplay: flex. Test the longest realistic title before polishing the normal case. Reference: Next.js opengraph-image and ImageResponse.On n-g.be, every article's OG image is a card built by this route: the article's banner on the left, its title, description, format and date on the right. The banners are WebP on the page, so the route reads a PNG copy of each one. An article without a banner gets a shared placeholder.
Make The Fallback Part Of The Main Path
A page without artwork must still return a valid social image. Keep one branded placeholder that works with any title and makes no route-specific assumptions.
Treat a missing image and a missing page as two different cases. A known page without artwork uses the placeholder. An unknown slug should never produce a convincing preview for a page that does not exist; return a neutral brand card or follow the site's not-found behaviour.
The fallback is done only when its public OG URL returns an image. A conditional that has never run is an untested branch.
Check Files, Markup, Masks And Real Page URLs
On the deployed site, open
favicon.ico, the SVG icon, the Apple icon, the Android icons, the manifest and a few OG routes directly. Confirm a200response, the right content type and the intended dimensions.Then inspect the page head, open the manifest in the browser developer tools' Application panel, and confirm the maskable icon's safe area. Capture representative pages on desktop and mobile with the Built by meN-G.BE Website Screenshot Generator to review them together.
Test at least one page with its own artwork, one on the fallback, and one with an unusually long title. Social platforms cache previews, so check the source OG URL before treating a stale shared card as a generation failure.
Be Aware
The favicon contains the full wordmark and becomes unreadable.
Return to the icon-only SVG and simplify detail for the smallest sizes instead of scaling the wordmark further.
The home-screen icon looks right on iPhone but is cropped or tiny on Android.
The manifest probably declares any maskable on one file. Split it into an any icon and a padded maskable icon, then preview the masks.
The OG route works in one place and returns a blank or broken image in another.
Check the image source: relative paths are not fetched and WebP is not decoded. Pass PNG or JPEG as a data URL or absolute URL, remove unsupported CSS, then open the fallback route directly.
A corrected social image still shows the old preview.
Open the source OG URL first. If it is correct, the platform is caching the old card; refresh it with the platform's own debugging tool instead of changing the generator again.
Favicon And OG Image Setup Brief
Copy / paste
Create and verify the complete favicon, app-icon, manifest, and dynamic Open Graph image setup for this Next.js website.
Read the project files before changing anything. Confirm these inputs:
- approved final logo and icon-only SVG
- site name and short name
- canonical site URL
- theme colour and background colour
- page templates and content lookup functions
- artwork field or image source for each template
- branded fallback image
Stop before implementation if the final logo, canonical URL, page lookup, or fallback decision is missing. Do not invent brand values or public routes.
Required icon outputs:
- favicon.ico
- SVG site icon
- 180x180 Apple touch icon
- 192x192 and 512x512 normal Android/PWA icons
- separate 512x512 maskable Android/PWA icon with safe padding (mark inside the central 80% circle)
- web app manifest with exact sizes, MIME types, and separate "any" and "maskable" purposes; never "any maskable" on one file
Next.js implementation:
- use either the App Router icon file conventions or public files listed in metadata.icons, not both for the same file
- expose the manifest through app/manifest.ts or a public site.webmanifest referenced by metadata.manifest
- create a 1200x630 opengraph-image.tsx for each page template that needs a unique preview
- use the page's own artwork when available and the approved placeholder when it is absent
- pass images to ImageResponse as PNG or JPEG, via a data URL or absolute URL; never a relative path or WebP
- keep ImageResponse layouts within its supported CSS subset
Acceptance checks:
- build and type checks pass
- every required asset returns 200 at its public URL
- the rendered head contains the correct icon, manifest, and Open Graph declarations
- normal and maskable icons are separate and the maskable preview keeps the mark visible
- a page with artwork returns the correct 1200x630 OG image
- a page without artwork returns the 1200x630 fallback
- the longest realistic title fits
- representative desktop and mobile pages have been visually checked
Report the files changed, URLs tested, checks run, and any decision that still needs human approval.




