favifetch

package module
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 23 Imported by: 0

README

favifetch

Based on Vemetric/favicon-api — a TypeScript/Bun favicon API service.
favifetch is the Go library version of the same concept.

A Go library for discovering and fetching website favicons. Automatically finds the best favicon from HTML <link> tags, web app manifests, common fallback locations, and optionally Vemetric's favicon API.

Features

  • Smart Discovery — Finds favicons from <link rel="icon">, <link rel="apple-touch-icon">, manifest.json, and common fallback paths (/favicon.ico, /apple-touch-icon.png)
  • Quality Ranking — Scores favicons by size, format, and source, returning the best one first
  • Format Detection — Detects PNG, JPEG, GIF, ICO, WebP, SVG, BMP via magic bytes
  • Image Processing — Resize to any pixel size and convert between PNG, JPG, WebP
  • SSRF Protection — Blocks requests to private IPs by default
  • Domain Mappings — Maps app package names (e.g. com.pinterest) to canonical domains
  • Vemetric API Fallback — Optionally uses Vemetric's favicon.vemetric.com as a last-resort source
  • Browser Mode — Selects the regular favicon Chromium would use for a 16px desktop tab from the initial HTML
  • Context Support — Full context.Context integration for cancellation and timeouts
  • Zero cgo — Pure Go image processing (no Sharp/Node dependency)

Installation

go get github.com/kodehat/favifetch

Quick Start

package main

import (
    "context"
    "fmt"
    "os"

    "github.com/kodehat/favifetch"
)

func main() {
    ctx := context.Background()

    // Fetch a favicon
    result, err := favifetch.Fetch(ctx, "github.com")
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }

    fmt.Printf("Format:  %s\n", result.Format) // png, svg, etc. (implements Stringer)
    fmt.Printf("Size:    %dx%d (%d bytes)\n", result.Width, result.Height, result.Size)
    fmt.Printf("Source:  %s\n", result.Source)
    fmt.Printf("URL:     %s\n", result.SourceURL)

    // result.Data contains the raw image bytes
    // os.WriteFile("favicon."+result.Format, result.Data, 0644)
}

Usage

Basic Fetch
result, err := favifetch.Fetch(ctx, "github.com")
// result.Data → raw image bytes
// result.Format → "svg", "png", "ico", etc.

URLs without a scheme default to https://. Full URLs with paths are also supported:

result, err := favifetch.Fetch(ctx, "https://example.com/blog/post")
With Options

Resize to 128×128 and convert to PNG:

result, err := favifetch.Fetch(ctx, "github.com",
    favifetch.WithSize(128),
    favifetch.WithFormat(favifetch.TargetPNG),
)

Custom timeout and user agent:

result, err := favifetch.Fetch(ctx, "example.com",
    favifetch.WithTimeout(10*time.Second),
    favifetch.WithUserAgent("MyApp/2.0"),
)

Disable Vemetric API fallback and SSRF protection:

result, err := favifetch.Fetch(ctx, "internal.company.com",
    favifetch.WithFallbackAPI(false),
    favifetch.WithBlockPrivateIPs(false),
)

Use a self-hosted Vemetric-compatible API (HTTPS is used; a port is optional):

result, err := favifetch.Fetch(ctx, "example.com",
    favifetch.WithVemetricAPIHost("favicons.example.com:8443"),
)
Chromium Browser Mode

Use browser mode when the selected favicon source should follow Chromium-style regular tab-icon discovery instead of favifetch's quality ranking:

result, err := favifetch.Fetch(ctx, "example.com",
    favifetch.WithMode(favifetch.ModeBrowser),
)

Browser mode considers only HTML <link rel="icon"> candidates and falls back to /favicon.ico only when the page declares none. When WithFallbackAPI(true) (the default) is enabled, it uses the Vemetric API only after those candidates fail, or immediately when the initial HTML request fails (for example, a 403). It honors the final page URL and <base href>, returns the original downloaded bytes, and cannot be combined with WithSize or WithFormat. It does not execute JavaScript or reproduce a browser session's cookies and other runtime state. It always uses a Chromium-like User-Agent; WithUserAgent is ignored in this mode.

Discovery Only

List all discovered favicon sources without fetching any image:

sources, err := favifetch.Discover(ctx, "github.com")
for _, s := range sources {
    fmt.Printf("[%s] score=%d size=%d %s\n", s.Source, s.Score, s.Size, s.URL)
}
// Output:
// [link-tag] score=150 size=0 https://github.githubassets.com/favicons/favicon.svg
// [link-tag] score=70 size=32 https://github.githubassets.com/favicons/favicon.png
// [manifest] score=40 size=192 https://github.githubassets.com/assets/icon-192.png
// [fallback] score=20 https://github.com/apple-touch-icon.png
// [fallback] score=10 https://github.com/favicon.ico
// [fallback-api] score=1 https://favicon.vemetric.com/github.com?size=64

API Reference

Fetch(ctx, url, opts...) (*FaviconResult, error)

Discovers and fetches the best favicon for the given URL.

Discover(ctx, url, opts...) ([]DiscoveredSource, error)

Returns all discovered favicon sources without fetching any image.

Types
type FaviconResult struct {
    Data      []byte          // Raw image bytes
    Format    DetectedFormat  // png, jpg, svg, ico, webp, gif, bmp
    Width     int             // Image width in pixels
    Height    int             // Image height in pixels
    Source    string          // "link-tag", "manifest", "fallback", "fallback-api"
    SourceURL string          // Original URL the favicon was fetched from
    Size      int             // Size of Data in bytes
}

type DiscoveredSource struct {
    URL    string
    Size   int
    Format DetectedFormat
    Source string
    Score  int
}
Options
Option Default Description
WithUserAgent(s) "Favifetch/1.0" User-Agent header
WithTimeout(d) 5s Request timeout
WithMaxImageSize(n) 5MB Max favicon size to accept
WithMaxRedirects(n) 5 Max HTTP redirects
WithBlockPrivateIPs(bool) true Block private IP ranges
WithFallbackAPI(bool) true Use Vemetric favicon API fallback
WithVemetricAPIHost(host) favicon.vemetric.com Set Vemetric-compatible API host (HTTPS)
WithSize(px) 0 Resize to px×px (0 = no resize)
WithFormat(f) TargetUnspecified Convert to TargetPNG, TargetJPEG, or TargetWebP
WithHTTPClient(c) http.DefaultClient Custom HTTP client
WithPreferredFormats(f...) (default order) Set preferred favicon formats in priority order

Favicon Sources & Scoring

The library searches these sources in priority order:

  1. HTML <link> tags<link rel="icon">, <link rel="apple-touch-icon">, <link rel="mask-icon">
  2. Web App Manifestmanifest.json icons array
  3. Common fallbacks/apple-touch-icon.png (score 20), /favicon.ico (score 10)
  4. Vemetric APIfavicon.vemetric.com/<domain>?size=<n> (score 1, optional)

Scoring weights SVG (+100), large sizes (+90 for ≥512px), PNG (+20), WebP (+15), and apple-touch-icon (+10). Mask icons are penalized (−10).

You can customize format priorities with WithPreferredFormats (see below).

Format Preferences

The WithPreferredFormats option lets you control which favicon formats are preferred:

// Prefer SVG, fall back to PNG, then ICO
result, err := favifetch.Fetch(ctx, "example.com",
    favifetch.WithPreferredFormats(favifetch.FormatSVG, favifetch.FormatPNG, favifetch.FormatICO),
)

When preferences are set, sources matching a higher-ranked format get a large score bonus, ensuring they are tried first. Unlisted formats are still tried as a last resort if no preferred format succeeds. Within the same format tier, larger sizes and better sources still win.

// Prefer PNG only — skip SVG entirely unless nothing else works
result, err := favifetch.Fetch(ctx, "example.com",
    favifetch.WithPreferredFormats(favifetch.FormatPNG),
)

When no preferences are set (or nil), the default order is: SVG > PNG > WebP > JPEG > ICO > GIF > BMP.

Error Types

  • favifetch.ErrPrivateIP — returned when the target URL resolves to a private IP and BlockPrivateIPs is enabled
  • favifetch.errInvalidURL — returned for malformed URLs or unsupported schemes

Credits

Based on Vemetric/favicon-api, a TypeScript/Bun favicon API service by Vemetric.

Built with:

License

MIT

Documentation

Overview

Package favifetch discovers and fetches website favicons.

It automatically finds the best favicon from a website by checking HTML <link> tags, web app manifests, common fallback locations, and optionally Vemetric's favicon API.

Basic usage:

result, err := favifetch.Fetch(ctx, "github.com")
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Format: %s, Size: %d bytes, Source: %s\n",
    result.Format, result.Size, result.Source)
// result.Data contains the raw image bytes

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DetectedFormat added in v0.2.0

type DetectedFormat int

DetectedFormat represents an image format detected from actual image data.

const (
	FormatUnknown DetectedFormat = iota
	FormatPNG
	FormatJPEG
	FormatSVG
	FormatICO
	FormatWebP
	FormatGIF
	FormatBMP
)

func (DetectedFormat) IsWritable added in v0.2.0

func (f DetectedFormat) IsWritable() bool

IsWritable returns true if the format can be encoded to (PNG, JPEG, WebP).

func (DetectedFormat) String added in v0.2.0

func (f DetectedFormat) String() string

func (DetectedFormat) Target added in v0.2.0

func (f DetectedFormat) Target() (TargetFormat, bool)

Target converts to a TargetFormat if the format is writable. The bool is false for non-writable formats (SVG, ICO, GIF, BMP, Unknown).

type DiscoveredSource

type DiscoveredSource struct {
	URL    string
	Size   int
	Format DetectedFormat
	Source string
	Score  int
}

DiscoveredSource represents a favicon URL found during discovery.

func Discover

func Discover(ctx context.Context, rawURL string, opts ...Option) ([]DiscoveredSource, error)

Discover returns all discovered favicon sources for a URL without fetching any image. This is useful for inspection/debugging.

type ErrPrivateIP

type ErrPrivateIP struct {
	Host string
	IP   string
}

ErrPrivateIP is returned when a URL resolves to a private IP and BlockPrivateIps is enabled.

func (*ErrPrivateIP) Error

func (e *ErrPrivateIP) Error() string

type FaviconMode added in v0.4.0

type FaviconMode int

FaviconMode controls how favicon candidates are selected.

const (
	// ModeBest selects the highest-ranked favicon from all supported sources.
	ModeBest FaviconMode = iota
	// ModeBrowser selects a Chromium-style regular tab favicon from the initial
	// HTML document. When enabled, the fallback API is used if those candidates
	// cannot be fetched. It returns the original image bytes and does not support
	// resizing or format conversion.
	ModeBrowser
)

type FaviconResult

type FaviconResult struct {
	// Data is the raw image bytes (PNG, SVG, ICO, etc.)
	Data []byte

	// Format is the detected image format.
	Format DetectedFormat

	// Width and Height are the image dimensions in pixels.
	Width, Height int

	// Source indicates where the favicon was found:
	// "link-tag", "manifest", "fallback", "fallback-api"
	Source string

	// SourceURL is the original URL from which the favicon was fetched.
	SourceURL string

	// Size is the size of Data in bytes.
	Size int
}

FaviconResult holds the fetched favicon image data and metadata.

func Fetch

func Fetch(ctx context.Context, rawURL string, opts ...Option) (*FaviconResult, error)

Fetch discovers and fetches the best favicon for the given URL.

The url parameter can be a full URL ("https://github.com") or just a domain ("github.com"). If no scheme is present, https:// is prepended.

Options can be provided to customize behavior (timeout, size, format, etc.). If no options are given, sensible defaults are used.

type Option

type Option func(*Options)

Option is a functional option for configuring the fetcher.

func WithBlockPrivateIPs

func WithBlockPrivateIPs(block bool) Option

WithBlockPrivateIPs enables or disables blocking of private IP ranges.

func WithFallbackAPI

func WithFallbackAPI(use bool) Option

WithFallbackAPI enables or disables the Vemetric favicon API fallback.

func WithFormat

func WithFormat(format TargetFormat) Option

WithFormat sets the desired output format.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient sets a custom http.Client.

func WithMaxImageSize

func WithMaxImageSize(size int64) Option

WithMaxImageSize sets the maximum favicon image size in bytes.

func WithMaxRedirects

func WithMaxRedirects(n int) Option

WithMaxRedirects sets the maximum number of HTTP redirects.

func WithMode added in v0.4.0

func WithMode(mode FaviconMode) Option

WithMode sets the favicon selection mode.

func WithPreferredFormats added in v0.3.0

func WithPreferredFormats(formats ...DetectedFormat) Option

WithPreferredFormats sets the preferred favicon formats in priority order. Example: WithPreferredFormats(FormatSVG, FormatPNG) prefers SVG favicons and falls back to PNG if no SVG is found.

func WithSize

func WithSize(size int) Option

WithSize sets the desired output size (resize to size×size pixels).

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the request timeout.

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent sets the User-Agent header. It is ignored in ModeBrowser, which always uses its Chromium-like User-Agent.

func WithVemetricAPIHost added in v0.4.1

func WithVemetricAPIHost(host string) Option

WithVemetricAPIHost sets the host, optionally including a port, for a self-hosted Vemetric-compatible favicon API. Requests use HTTPS.

type Options

type Options struct {
	// Mode controls how favicon candidates are selected. The default ModeBest
	// ranks all supported favicon sources by quality. ModeBrowser emulates
	// Chromium's regular tab-icon selection from the initial HTML document.
	Mode FaviconMode

	// UserAgent sent in HTTP requests for HTML and manifest fetching.
	// ModeBrowser always uses its Chromium-like User-Agent instead.
	UserAgent string

	// RequestTimeout is the maximum time for the entire fetch operation.
	RequestTimeout time.Duration

	// MaxImageSize is the maximum size (in bytes) of a favicon image to accept.
	MaxImageSize int64

	// MaxRedirects limits the number of HTTP redirects to follow.
	MaxRedirects int

	// BlockPrivateIps controls whether requests to private IP ranges are rejected.
	BlockPrivateIps bool

	// UseFallbackAPI enables the Vemetric favicon API as a last-resort fallback.
	UseFallbackAPI bool

	// VemetricAPIHost is the host, optionally including a port, of a
	// Vemetric-compatible favicon API. Requests use HTTPS.
	VemetricAPIHost string

	// Size is the desired output size in pixels (resizes favicon to size×size).
	// 0 means no resizing.
	Size int

	// Format is the desired output format. Zero value (TargetUnspecified) means keep original.
	Format TargetFormat

	// HTTPClient is the *http.Client to use for all requests. If nil, a default
	// client is created from the other options.
	HTTPClient *http.Client

	// PreferredFormats is an ordered list of preferred favicon formats.
	// The first format is most preferred, the last is least.
	// During discovery, sources matching a higher-preference format get a
	// large score bonus, so they are tried before lower-preference formats.
	// Unlisted formats are still tried as a last resort.
	// When nil or empty, the default preference order (SVG > PNG > WebP > JPEG > ICO > GIF > BMP) is used.
	PreferredFormats []DetectedFormat
}

Options holds all configuration for the favicon fetcher.

func DefaultOptions

func DefaultOptions(opts ...Option) *Options

DefaultOptions returns the default configuration. Optional Option arguments can be passed to override defaults.

type TargetFormat added in v0.2.0

type TargetFormat int

TargetFormat represents an output format for encoding (PNG, JPEG, WebP).

const (
	TargetUnspecified TargetFormat = iota
	TargetPNG
	TargetJPEG
	TargetWebP
)

func ParseTargetFormat added in v0.2.0

func ParseTargetFormat(s string) (TargetFormat, error)

ParseTargetFormat parses a string into a TargetFormat. Accepts "png", "jpg", "jpeg", "webp" (case-insensitive).

func (TargetFormat) Detected added in v0.2.0

func (t TargetFormat) Detected() DetectedFormat

Detected converts TargetFormat to its corresponding DetectedFormat.

func (TargetFormat) String added in v0.2.0

func (t TargetFormat) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL