npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@reinforcezwei/favicon-fetcher

v1.0.5

Published

A Node.js library to fetch website favicons and titles with optional image metadata extraction

Readme

Favicon Fetcher

A Node.js library to fetch website favicons and titles with optional image metadata extraction. The library uses browser-like headers to bypass basic bot detection.

Features

  • 🌐 Fetch website favicons and page titles from multiple sources
  • 🏷️ Extract titles with rich metadata (HTML, OpenGraph, Twitter, manifest)
  • 📝 Extract descriptions with rich metadata (HTML, OpenGraph, Twitter, manifest)
  • 🔍 Parse multiple icon sources (HTML, manifest.json, default favicon.ico)
  • 📊 Optional image metadata extraction (dimensions, format, file size)
  • 🤖 Browser-like headers to bypass basic bot detection
  • ⚡ Support for various icon types (favicon, apple-touch-icon, manifest icons)
  • 🔗 Automatic URL resolution for relative paths
  • 📘 Full TypeScript support with comprehensive type definitions
  • 🎯 ES Modules with modern JavaScript syntax
  • 🛡️ Graceful error handling with partial results and detailed error reporting

Installation

npm install

Dependencies

  • axios - HTTP client for fetching URLs
  • cheerio - Fast HTML parser
  • image-size - Extract image dimensions and format

Usage

TypeScript

This library is written in TypeScript and provides full type definitions out of the box.

import { fetchFavicon, type FetchResult, type Icon } from '@reinforcezwei/favicon-fetcher';

const result: FetchResult = await fetchFavicon('https://github.com');
console.log('Title:', result.title);
console.log('Icons:', result.icons);

JavaScript (ES Modules)

import { fetchFavicon } from '@reinforcezwei/favicon-fetcher';

const result = await fetchFavicon('https://github.com');
console.log('Title:', result.title);
console.log('Icons:', result.icons);

Basic Usage

import { fetchFavicon } from '@reinforcezwei/favicon-fetcher';

try {
  const result = await fetchFavicon('https://github.com');
  
  console.log('Title:', result.title);
  console.log('URL:', result.url);
  console.log('Icons found:', result.icons.length);
  
  result.icons.forEach(icon => {
    console.log(`- ${icon.type} (${icon.sizes || 'no size'}): ${icon.url}`);
  });
} catch (error) {
  console.error('Error:', error.message);
}

Extract Titles from Multiple Sources

The library extracts titles from various sources and returns them with rich metadata:

import { fetchFavicon } from '@reinforcezwei/favicon-fetcher';

try {
  const result = await fetchFavicon('https://github.com');
  
  // Use the primary title (for backward compatibility)
  console.log('Primary Title:', result.title);
  
  // Access all titles with metadata
  console.log('\nAll Titles:');
  result.titles.forEach(title => {
    console.log(`- ${title.value}`);
    console.log(`  Source: ${title.source}`);
    console.log(`  Property: ${title.property}`);
  });
  
  // Example output:
  // - GitHub · Change is constant
  //   Source: html
  //   Property: title
  // - GitHub
  //   Source: opengraph
  //   Property: og:title
  // - GitHub
  //   Source: twitter
  //   Property: twitter:title
  // - GitHub
  //   Source: manifest
  //   Property: name
  
} catch (error) {
  console.error('Error:', error.message);
}

Extract Descriptions from Multiple Sources

The library extracts descriptions from various sources with rich metadata:

import { fetchFavicon } from '@reinforcezwei/favicon-fetcher';

try {
  const result = await fetchFavicon('https://github.com');
  
  // Access all descriptions with metadata
  console.log('All Descriptions:');
  result.descriptions.forEach(description => {
    console.log(`- ${description.value}`);
    console.log(`  Source: ${description.source}`);
    console.log(`  Property: ${description.property}`);
  });
  
  // Example output:
  // - GitHub is where people build software...
  //   Source: html
  //   Property: description
  // - GitHub is where over 100 million developers...
  //   Source: opengraph
  //   Property: og:description
  // - GitHub is where over 100 million developers...
  //   Source: twitter
  //   Property: twitter:description
  // - Collaborate on code with GitHub
  //   Source: manifest
  //   Property: description
  
} catch (error) {
  console.error('Error:', error.message);
}

With Image Metadata

import { fetchFavicon } from '@reinforcezwei/favicon-fetcher';

try {
  const result = await fetchFavicon('https://example.com', {
    includeMetadata: true,
    timeout: 5000
  });
  
  console.log('Title:', result.title);
  
  result.icons.forEach(icon => {
    console.log(`\nIcon: ${icon.type}`);
    console.log(`URL: ${icon.url}`);
    
    if (icon.metadata) {
      console.log(`Dimensions: ${icon.metadata.width}x${icon.metadata.height}`);
      console.log(`Format: ${icon.metadata.format}`);
      console.log(`Size: ${icon.metadata.size} bytes`);
    }
  });
} catch (error) {
  console.error('Error:', error.message);
}

Custom Options

import { fetchFavicon } from '@reinforcezwei/favicon-fetcher';

const options = {
  includeMetadata: false,    // Enable/disable image metadata extraction
  timeout: 10000,            // Request timeout in milliseconds
  userAgent: 'CustomBot/1.0' // Custom user agent (optional)
};

const result = await fetchFavicon('https://example.com', options);

TypeScript with Type Safety

import { fetchFavicon, type FetchOptions, type FetchResult } from '@reinforcezwei/favicon-fetcher';

const options: FetchOptions = {
  includeMetadata: true,
  timeout: 10000,
  userAgent: 'MyBot/1.0'
};

const result: FetchResult = await fetchFavicon('https://example.com', options);

// TypeScript provides autocomplete and type checking
result.titles.forEach(title => {
  console.log(title.value);     // string
  console.log(title.source);    // 'html' | 'opengraph' | 'twitter' | 'manifest'
  console.log(title.property);  // string
});

result.descriptions.forEach(description => {
  console.log(description.value);     // string
  console.log(description.source);    // 'html' | 'opengraph' | 'twitter' | 'manifest'
  console.log(description.property);  // string
});

result.icons.forEach(icon => {
  console.log(icon.url);      // string
  console.log(icon.type);     // string
  console.log(icon.source);   // 'html' | 'manifest' | 'default'
  
  if (icon.metadata) {
    console.log(icon.metadata.width);   // number
    console.log(icon.metadata.height);  // number
    console.log(icon.metadata.format);  // string
  }
});

API

fetchFavicon(url, options)

Fetches favicon and title from a given URL.

Parameters

  • url (string, required): The URL to fetch favicon from
  • options (object, optional): Configuration options
    • includeMetadata (boolean, default: false): Include image metadata
    • timeout (number, default: 10000): Request timeout in milliseconds
    • userAgent (string, optional): Custom user agent string

Returns

Promise that resolves to an object with the following structure:

{
  url: string,              // Original/normalized URL
  title: string,            // Page title (primary, for backward compatibility)
  titles: [                 // Array of titles from all sources with metadata
    {
      value: string,        // Title text
      source: string,       // Source type (html, opengraph, twitter, manifest)
      property: string      // Property name (title, og:title, twitter:title, name, etc.)
    }
  ],
  descriptions: [           // Array of descriptions from all sources with metadata
    {
      value: string,        // Description text
      source: string,       // Source type (html, opengraph, twitter, manifest)
      property: string      // Property name (description, og:description, twitter:description)
    }
  ],
  icons: [
    {
      url: string,          // Absolute icon URL
      type: string,         // Icon type (favicon, apple-touch-icon, etc.)
      sizes: string,        // Size attribute (e.g., "192x192")
      source: string,       // Where found (html, manifest, default)
      metadata: {           // Optional (if includeMetadata: true)
        width: number,      // Image width in pixels
        height: number,     // Image height in pixels
        format: string,     // Image format (png, ico, svg, etc.)
        size: number        // File size in bytes
      }
    }
  ],
  errors: [                 // Optional array of non-critical errors
    {
      step: string,         // Step where error occurred
      message: string,      // Error message
      url: string           // Optional URL that caused the error
    }
  ]
}

Throws

  • Error if URL is invalid or malformed
  • Error if HTML fetch fails (network error, timeout, DNS failure, HTTP 4xx/5xx)
  • Note: Non-critical errors (title parsing, manifest fetching, metadata extraction) do not throw. Instead, they return partial results with an errors array.

TypeScript Types

The library exports the following TypeScript types for your convenience:

import { 
  fetchFavicon,
  type FetchOptions,
  type FetchResult,
  type FetchError,
  type Icon,
  type Title,
  type Description,
  type ImageMetadata,
  type RequestOptions,
  type ManifestIcon,
  type WebAppManifest
} from '@reinforcezwei/favicon-fetcher';

FetchOptions

Configuration options for favicon fetching:

interface FetchOptions {
  includeMetadata?: boolean;  // Include image metadata
  timeout?: number;           // Request timeout in ms
  userAgent?: string;         // Custom user agent
}

FetchResult

Result returned by fetchFavicon():

interface FetchResult {
  url: string;              // Normalized URL
  title: string;            // Page title (primary, for backward compatibility)
  titles: Title[];          // Array of titles from all sources with metadata
  descriptions: Description[]; // Array of descriptions from all sources with metadata
  icons: Icon[];            // Array of found icons
  errors?: FetchError[];    // Optional array of non-critical errors
}

FetchError

Error information for non-critical failures:

interface FetchError {
  step: string;    // Step where error occurred (e.g., 'parse_title', 'fetch_manifest')
  message: string; // Error message
  url?: string;    // Optional URL that caused the error
}

Icon

Icon object structure:

interface Icon {
  url: string;                    // Absolute icon URL
  type: string;                   // Icon type
  sizes: string;                  // Size attribute
  source: 'html' | 'manifest' | 'default';  // Source
  metadata?: {                    // Optional metadata
    width: number;
    height: number;
    format: string;
    size: number;
    buffer: Buffer;
  };
}

Title

Title object structure with source metadata:

interface Title {
  value: string;                  // Title text
  source: 'html' | 'opengraph' | 'twitter' | 'manifest';  // Source type
  property: string;               // Property name (e.g., 'title', 'og:title', 'twitter:title', 'name', 'short_name')
}

Description

Description object structure with source metadata:

interface Description {
  value: string;                  // Description text
  source: 'html' | 'opengraph' | 'twitter' | 'manifest';  // Source type
  property: string;               // Property name (e.g., 'description', 'og:description', 'twitter:description')
}

ImageMetadata

Image metadata structure (when includeMetadata: true):

interface ImageMetadata {
  width: number;    // Width in pixels
  height: number;   // Height in pixels
  format: string;   // Image format (png, ico, jpeg, etc.)
  size: number;     // File size in bytes
  buffer: Buffer;   // Raw image data
}

Icon Detection

The library searches for icons in the following order:

  1. HTML <link> tags:

    • <link rel="icon">
    • <link rel="shortcut icon">
    • <link rel="apple-touch-icon">
    • <link rel="apple-touch-icon-precomposed">
    • <link rel="mask-icon">
  2. Web App Manifest (manifest.json):

    • Fetches and parses icons from manifest file
  3. Default Favicon:

    • Falls back to /favicon.ico if no icons found
  4. OpenGraph Image (fallback):

    • <meta property="og:image"> if no other icons found

Title Detection

The library extracts titles from multiple sources with rich metadata:

HTML Sources

  1. HTML <title> tag:

    <title>Page Title</title>
    • Source: html
    • Property: title
  2. OpenGraph title:

    <meta property="og:title" content="OpenGraph Title">
    • Source: opengraph
    • Property: og:title
  3. Twitter title:

    <meta name="twitter:title" content="Twitter Title">
    • Source: twitter
    • Property: twitter:title

Manifest Sources

  1. Manifest name:
    {
      "name": "App Name",
      "short_name": "App"
    }
    • Source: manifest
    • Property: name or short_name

All titles are returned in the titles array, while the primary HTML title is also available in the title field for backward compatibility.

Description Detection

The library extracts descriptions from multiple sources with rich metadata:

HTML Sources

  1. HTML meta description:

    <meta name="description" content="Page description">
    • Source: html
    • Property: description
  2. OpenGraph description:

    <meta property="og:description" content="OpenGraph description">
    • Source: opengraph
    • Property: og:description
  3. Twitter description:

    <meta name="twitter:description" content="Twitter description">
    • Source: twitter
    • Property: twitter:description

Manifest Sources

  1. Manifest description:
    {
      "description": "App description"
    }
    • Source: manifest
    • Property: description

All descriptions are returned in the descriptions array with their respective source and property metadata.

Browser-Like Headers

The library uses the following headers to mimic browser behavior:

{
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...',
  'Accept': 'text/html,application/xhtml+xml,...',
  'Accept-Language': 'en-US,en;q=0.9',
  'Accept-Encoding': 'gzip, deflate, br',
  'Connection': 'keep-alive',
  'Upgrade-Insecure-Requests': '1',
  'Sec-Fetch-Dest': 'document',
  'Sec-Fetch-Mode': 'navigate',
  'Sec-Fetch-Site': 'none'
}

Error Handling

The library implements graceful error handling with partial results:

Critical vs Non-Critical Errors

Critical Error (throws exception):

  • HTML Fetch Failure: If the initial HTML cannot be fetched, the function throws an error. This is the only critical step because all other operations depend on it.

Non-Critical Errors (returns partial results):

  • Title Parsing: Returns empty string if parsing fails
  • Multiple Title Parsing: Returns empty array if parsing from multiple sources fails
  • Description Parsing: Returns empty array if parsing from multiple sources fails
  • Icon Link Parsing: Returns empty array if parsing fails
  • Manifest URL Parsing: Skips manifest step if parsing fails
  • Manifest Fetching: Continues without manifest icons/titles/descriptions if fetch fails
  • Metadata Extraction: Returns icons without metadata if extraction fails

Error Reporting

Non-critical errors are collected and returned in an optional errors array:

const result = await fetchFavicon('https://example.com', { includeMetadata: true });

// Check if any non-critical errors occurred
if (result.errors && result.errors.length > 0) {
  console.log('Some operations failed:');
  result.errors.forEach(error => {
    console.log(`- ${error.step}: ${error.message}`);
    if (error.url) {
      console.log(`  URL: ${error.url}`);
    }
  });
}

// Still able to access partial results
console.log('Title:', result.title);
console.log('Icons found:', result.icons.length);

Error Steps

The following step identifiers may appear in the errors array:

  • parse_title - Failed to parse page title
  • parse_titles - Failed to parse titles from multiple sources
  • parse_descriptions - Failed to parse descriptions from multiple sources
  • parse_icon_links - Failed to parse icon links from HTML
  • get_manifest_url - Failed to extract manifest URL
  • fetch_manifest - Failed to fetch or parse manifest.json
  • add_metadata - Failed to add metadata to icons

Example: Handling Errors

import { fetchFavicon } from '@reinforcezwei/favicon-fetcher';

try {
  const result = await fetchFavicon('https://example.com');
  
  // Check for partial failures
  if (result.errors) {
    console.warn(`⚠️ ${result.errors.length} non-critical error(s) occurred`);
    result.errors.forEach(err => {
      console.warn(`  - ${err.step}: ${err.message}`);
    });
  }
  
  // Use partial results
  console.log(`✓ Successfully fetched ${result.icons.length} icon(s)`);
  console.log(`✓ Title: ${result.title || '(no title)'}`);
  
} catch (error) {
  // Only critical HTML fetch failures throw
  console.error('✗ Critical error - could not fetch page:', error.message);
}

Resilient Metadata Fetching

When includeMetadata: true is set, the library uses Promise.allSettled to fetch metadata for all icons. If some icons fail, others will still have their metadata extracted:

const result = await fetchFavicon('https://example.com', { includeMetadata: true });

const successCount = result.icons.filter(icon => icon.metadata).length;
const failCount = result.icons.length - successCount;

console.log(`Metadata: ${successCount} successful, ${failCount} failed`);

Architecture

The project is structured as follows:

src/
├── index.ts       # Main entry point & public API
├── types.ts       # TypeScript type definitions
├── fetcher.ts     # HTTP client with browser-like headers
├── parser.ts      # HTML parsing for icons and title
├── manifest.ts    # Manifest.json handler
└── metadata.ts    # Image metadata extractor

Compiled JavaScript and type definitions are output to the dist/ directory.

Development

Building from Source

  1. Install dependencies:
npm install
  1. Build the project:
npm run build

This compiles TypeScript files from src/ to JavaScript in dist/, generating:

  • .js files (compiled JavaScript)
  • .d.ts files (TypeScript type definitions)
  • .js.map and .d.ts.map files (source maps)

Scripts

  • npm run build - Compile TypeScript to JavaScript
  • npm run dev - Watch mode for development
  • npm test - Run tests
  • npm run example - Run example scripts

License

ISC