README.md

@cutticat/favicon-fetch

Favicon discovery and metadata library.

Table of Contents

Overview

@cutticat/favicon-fetch finds favicon candidates on a page and enriches them with metadata:

  • <link rel="icon">, apple-touch-icon, mask-icon, and others
  • icons from Web App Manifest (<link rel="manifest">)
  • well-known paths on the origin (/favicon.ico, /favicon.png, …)

The library does not download icon bytes through the API, does not perform SSRF checks, and does not cache — that is the caller’s responsibility (for example, the CuttiCat backend). Use the CLI for downloading and debugging.

After scanning, use pickFavicon to choose the best candidate from the list.

HTTP probe errors are not thrown — they are passed to the onProbeFailure callback. To abort the scan, throw from the callback.

Installation

pnpm i @cutticat/favicon-fetch

CLI

The package ships the favicon-fetch command (bin field). In the library repository, use the favicon:fetch script (fetch is taken by pnpm’s built-in command).

# In the @cutticat/favicon-fetch repository (after pnpm run build)
pnpm favicon:fetch --list https://github.com
pnpm favicon:fetch https://github.com
pnpm favicon:fetch https://github.com ./favicon.svg

# In a project with @cutticat/favicon-fetch as a dependency
favicon-fetch --list https://github.com
favicon-fetch https://github.com ./icon.png
Mode Behavior
--list JSON array of FaviconMetadata[] (all discovered candidates)
no flags pickFavicon → download the best icon; JSON { output, href, bytes }

The second argument is the output file path. By default, the filename from the icon URL is used (for example, favicon.ico, favicon.svg).

Quick Start

import { pickFavicon, scanFaviconsFromUrl } from "@cutticat/favicon-fetch"

const favicons = await scanFaviconsFromUrl("https://example.com", {
  // HTML + manifest discovery only, no synthetic paths or HEAD probe
  scanPaths: [],
  probe: [],
  mimeTypeFetchPolicy: "never",
  sizesFetchPolicy: "never",
})

const best = pickFavicon(favicons)
console.log(best?.href) // https://example.com/favicon.png

Full page URL scan (HTML + manifest + synthetic paths + HEAD probe for synthetic):

import { pickFavicon, scanFaviconsFromUrl } from "@cutticat/favicon-fetch"

const favicons = await scanFaviconsFromUrl("https://example.com")
const best = pickFavicon(favicons)

Scanning already-fetched HTML:

import { pickFavicon, scanFaviconsFromHtml } from "@cutticat/favicon-fetch"

const favicons = await scanFaviconsFromHtml(html, {
  pageUrl: "https://example.com/page",
})
const best = pickFavicon(favicons)

API

Scanning (high level)

Function Description
scanFaviconsFromUrl(url, options?) GET page HTML → scan link + manifest + synthetic paths
scanFaviconsFromHtml(html, options?) Scan from an HTML string
scanFaviconsFromManifest(manifest, options?) Scan from manifest JSON
scanFaviconsFromManifestUrl(url, options?) GET manifest → scan icons[]

Attribute extraction (without enrich)

Function Description
faviconAttributesFromHtml(html, options?) <link> + manifest icons → FaviconAttributes[]
faviconAttributesFromManifest(manifest) icons[]FaviconAttributes[]
faviconAttributesFromManifestUrl(url, options?) GET manifest → attributes

Enrichment and selection

Function Description
scanFaviconsFromAttributes(attrs, options?) Resolve URL, dedup, mime/sizes probe, HEAD existence probe
pickFavicon(favicons) Best candidate from FaviconMetadata[]
faviconPriority(meta) Numeric priority (for custom sorting)

Types

  • FaviconMetadatahref, rel, optionally source, mimeType, width, height
  • FaviconAttributes — raw attributes before scan
  • FaviconSource"html" | "manifest" | "synthetic"
  • FetchPolicy"always" | "never" | "if-not-specified"
  • FaviconProbeKind"page" | "manifest" | "mime-type" | "dimensions" | "existence"
  • FaviconProbeFailureReason"http-error" | "network-error" | "bad-content-type" | "bad-payload"
  • FaviconProbeFailure — failed probe event
  • OnProbeFailure(failure: FaviconProbeFailure) => void

Constants

  • defaultRelValues — rel tokens for HTML link
  • defaultScanPaths — well-known paths for scanFaviconsFromUrl
  • defaultProbeSources["synthetic"] — sources for HEAD existence probe
  • allProbeSources["html", "manifest", "synthetic"]
  • manifestIconRel"manifest" for icons from JSON
  • imageProbeMaxBytes — Range GET limit when determining dimensions (64 KiB)

Scan Options

Option Default Purpose
fetch globalThis.fetch HTTP client
pageUrl page URL in scanFaviconsFromUrl Base for HTML <link href> and FaviconProbeFailure.pageUrl
manifestUrl manifest URL in scanFaviconsFromManifestUrl Base for relative src in manifest icons
onProbeFailure Callback on failed HTTP probe
relValues defaultRelValues Which rel values from HTML to accept
mimeTypeFetchPolicy if-not-specified HEAD for content-type
sizesFetchPolicy if-not-specified Range GET for width/height
probe ["synthetic"] HEAD existence filter by source
scanPaths defaultScanPaths Synthetic paths in scanFaviconsFromUrl
seenHrefs new Set() Dedup across calls
noDeduplication false Disable dedup by href
cheerio cheerio.load options in scanFaviconsFromHtml

When scanning from HTML, manifest icons are resolved relative to the manifest URL automatically. For scanFaviconsFromManifest, pass manifestUrl explicitly.

Probe Diagnostics

import { scanFaviconsFromUrl, type FaviconProbeFailure } from "@cutticat/favicon-fetch"

const failures: FaviconProbeFailure[] = []

await scanFaviconsFromUrl("https://example.com", {
  onProbeFailure(failure) {
    failures.push(failure)
    // throw failure — to abort the scan
  },
})

FaviconProbeFailure fields:

Field Description
kind Probe kind: page, manifest, mime, dimensions, existence
url Request URL
method GET or HEAD
reason Failure reason
pageUrl Source page URL for the scan
response HTTP response, if the request reached the server
error Network or parsing error
candidate Candidate during existence probe
dropped true if the candidate was filtered out (existence HEAD)

Supported URLs

Allowed:

  • http: and https: (absolute URLs)
  • relative paths (/favicon.ico, icons/a.png) — HTML via pageUrl, manifest src via manifestUrl
  • protocol-relative (//cdn.example.com/icon.png) — resolved via pageUrl or manifestUrl

Absolute URLs with any other scheme (data:, file:, javascript:, ftp:, etc.) are discarded.

Documentation

Full API documentation is in source JSDoc comments and in dist/index.d.ts.

Requirements

  • Node.js >= 22.0.0
  • pnpm >= 10.17.0
  • TypeScript >= 5.9.0
Описание
Library for fetching website icons
Конвейеры
5 успешных
3 с ошибкой
Разработчики