POST /v1/sites/:id/favicon
Replace the site’s favicon without touching the nav/footer logo.
By default the favicon is derived from the logo at build time. This endpoint overrides that — useful when the logo is a wide horizontal lockup but you’d rather have a square icon in the browser tab, or when you want a totally different favicon than the logo.
Cost: free — deterministic operation, no LLM call.
How the override survives
The override survives revisions (POST /v1/sites/:id/revisions) — revisions only edit HTML, never touch the favicon files on disk.
The override would only be reset by a full pipeline re-run on the same site_id (rare in normal operator flow). If that happens, just re-call this endpoint.
Request
curl -X POST https://api.warpweb.ai/v1/sites/<site-id>/favicon \
-H "Authorization: Bearer wwk_..." \
-H "Content-Type: application/json" \
-d '{ "source": { "url": "https://example.com/my-icon.png" } }'Body
| Field | Type | Required | Description |
|---|---|---|---|
source.url | string | one of (url, sitePhotoId) | Public http(s):// URL of the new favicon source image. Doesn’t have to be square — the favicon pipeline crops to 180×180 using wide-aspect-edge / attention / center strategies. SSRF-safe download. |
source.sitePhotoId | string (uuid) | one of (url, sitePhotoId) | UUID of a row from this site’s site_photos catalog. Cross-site reuse blocked (403). |
Response (success)
{
"ok": true,
"faviconSourcePath": "images/favicon-source.png",
"favicon": {
"strategy": "source-logo-wide-edge",
"versionHash": "8be5ea86",
"entropy": 3.85
},
"deployedUrl": "https://acme-plumbing-abc123.pages.dev",
"hint": "Favicon swapped. The nav/footer logo was NOT changed. Survives revisions; only POST /v1/sites/:id/retry-build (rare) would reset it."
}| Field | Description |
|---|---|
faviconSourcePath | Where the override source was saved on disk (images/favicon-source.<ext>). |
favicon.strategy | Which crop pipeline branch produced the favicon: source-logo-wide-edge (icon+wordmark lockups), source-logo-attention (square logos), source-logo-center (whitespace-padded marks), or initial-mark (fallback — first letter on the brand accent color). |
favicon.versionHash | 8-char content hash. Used in the <link rel="icon" href="...?v=..."> cache-busting suffix. Changes whenever the favicon bytes change. |
favicon.entropy | Sharp-measured greyscale entropy of the cropped 180×180 buffer. Diagnostic — higher means the crop captured visually meaningful content. |
Crop strategy precedence
When you point the favicon at a source image, the pipeline tries crops in this order until one passes the entropy floor:
source-logo-wide-edge— if the source aspect ratio > 2:1 (icon+wordmark lockups), try a square crop from the left edge and right edge; the higher-entropy edge wins. Captures the icon side of a horizontal lockup cleanly.source-logo-attention— Sobel-attention crop picks the edge-densest 180×180 region. Wins for square logos and icons that fill the canvas.source-logo-center— center cover-crop. Rescues whitespace-padded marks where attention lands on a featureless region.- Site-photos fallback — if the source is unreadable (e.g. an
.icofile the extractor saved aslogo.pngand sharp can’t decode), querysite_photosfor alogo_or_brand-tagged row and retry the pipeline on those bytes. initial-mark— render the first letter of the business name on the brand accent color as a styled SVG. Last resort.
Errors
| Status | Body | Cause |
|---|---|---|
400 | { "error": "source.url or source.sitePhotoId required" } | Body missing both source variants. |
400 | { "error": "source.url must be http(s)://" } | URL scheme isn’t http or https. |
400 | { "error": "favicon_download_failed", "detail": "..." } | SSRF guard rejected, network error, or response wasn’t an image. |
403 | { "error": "sitePhotoId does not belong to this site" } | sitePhotoId belongs to a different site. |
404 | { "error": "sitePhotoId not found" } | No row matches the given UUID. |
404 | { "error": "site_not_found" } | Site doesn’t exist or isn’t owned by this API key. |
500 | { "error": "favicon_swap_failed", "detail": "..." } | Unexpected server-side failure. Safe to retry. |
Related
POST /v1/sites/:id/logo— swap the nav/footer logo (separate from favicon)GET /v1/sites/:id/research—site_photoscatalog withids forsitePhotoId