API ReferencePOST /v1/sites/:id/favicon

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

FieldTypeRequiredDescription
source.urlstringone 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.sitePhotoIdstring (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."
}
FieldDescription
faviconSourcePathWhere the override source was saved on disk (images/favicon-source.<ext>).
favicon.strategyWhich 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.versionHash8-char content hash. Used in the <link rel="icon" href="...?v=..."> cache-busting suffix. Changes whenever the favicon bytes change.
favicon.entropySharp-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:

  1. 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.
  2. source-logo-attention — Sobel-attention crop picks the edge-densest 180×180 region. Wins for square logos and icons that fill the canvas.
  3. source-logo-center — center cover-crop. Rescues whitespace-padded marks where attention lands on a featureless region.
  4. Site-photos fallback — if the source is unreadable (e.g. an .ico file the extractor saved as logo.png and sharp can’t decode), query site_photos for a logo_or_brand-tagged row and retry the pipeline on those bytes.
  5. initial-mark — render the first letter of the business name on the brand accent color as a styled SVG. Last resort.

Errors

StatusBodyCause
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.