Favicon APIs: How to Get Any Website's Favicon Programmatically
Tutorial5 min read

Favicon APIs: How to Get Any Website's Favicon Programmatically

Learn how to fetch favicons from any website using APIs. Compare different approaches and understand best practices for favicon retrieval in your apps.

Katsau

Katsau Team

December 15, 2025

Share:

Favicons are those tiny icons that appear in browser tabs, bookmarks, and link previews. When building apps that display external links, you often need to fetch favicons programmatically. Let's explore the best ways to do this.

The Favicon Challenge

Getting a website's favicon seems simple—just fetch /favicon.ico, right? Unfortunately, it's more complex:

  1. Not all sites use /favicon.ico
  2. Favicons can be in different formats (ICO, PNG, SVG)
  3. Modern sites use multiple sizes
  4. Some sites use data URIs
  5. Fallback chains can be complex

Common Approaches

1. Direct /favicon.ico

The simplest approach, but unreliable:

const faviconUrl = `https://example.com/favicon.ico`;

Problems:

  • Many sites don't have a favicon.ico file
  • You can't check if it exists without fetching it
  • CORS blocks client-side requests

2. Google's Favicon Service

Google provides a favicon proxy:

const faviconUrl = `https://www.google.com/s2/favicons?domain=${domain}`;

Pros:

  • Simple to use
  • No CORS issues
  • Caches results

Cons:

  • Limited sizes (16px default)
  • No guarantee of accuracy
  • May return Google's default icon
  • Not officially supported

3. DuckDuckGo's Service

const faviconUrl = `https://icons.duckduckgo.com/ip3/${domain}.ico`;

Similar limitations to Google's service.

4. Using a Metadata API

The most reliable approach is using an API that properly parses the HTML:

const response = await fetch(
  `https://api.katsau.com/v1/favicon?url=${encodeURIComponent(url)}`,
  {
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
  }
);

const data = await response.json();
console.log(data.data.favicon);    // Best favicon URL
console.log(data.data.favicons);   // All available sizes

Why this works better:

  • Parses actual HTML for link tags
  • Finds all favicon formats and sizes
  • Handles relative URLs
  • Returns the highest quality option
  • Works for any website

How Websites Declare Favicons

Modern websites use multiple link tags:

<!-- Classic favicon -->
<link rel="icon" href="/favicon.ico" />

<!-- PNG favicons in multiple sizes -->
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />

<!-- Apple Touch Icon -->
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />

<!-- SVG favicon (modern browsers) -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />

<!-- Web manifest with icons -->
<link rel="manifest" href="/site.webmanifest" />

A good favicon API parses all of these and returns the best options.

Building a Favicon Display Component

Here's a React component that displays a website's favicon with fallback:

function SiteFavicon({ url, size = 32 }: { url: string; size?: number }) {
  const [faviconUrl, setFaviconUrl] = useState<string | null>(null);
  const [error, setError] = useState(false);

  useEffect(() => {
    async function fetchFavicon() {
      try {
        const res = await fetch(
          `https://api.katsau.com/v1/favicon?url=${encodeURIComponent(url)}`,
          { headers: { 'Authorization': `Bearer ${API_KEY}` } }
        );
        const { data } = await res.json();
        setFaviconUrl(data.favicon);
      } catch {
        setError(true);
      }
    }
    fetchFavicon();
  }, [url]);

  if (error || !faviconUrl) {
    return (
      <div
        className="bg-gray-100 rounded flex items-center justify-center"
        style={{ width: size, height: size }}
      >
        🌐
      </div>
    );
  }

  return (
    <img
      src={faviconUrl}
      alt=""
      width={size}
      height={size}
      className="rounded"
      onError={() => setError(true)}
    />
  );
}

Best Practices

1. Cache Aggressively

Favicons rarely change. Cache them for at least 24 hours:

const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours

async function getCachedFavicon(url) {
  const cacheKey = `favicon:${url}`;
  const cached = localStorage.getItem(cacheKey);

  if (cached) {
    const { favicon, timestamp } = JSON.parse(cached);
    if (Date.now() - timestamp < CACHE_DURATION) {
      return favicon;
    }
  }

  const favicon = await fetchFaviconFromAPI(url);
  localStorage.setItem(cacheKey, JSON.stringify({
    favicon,
    timestamp: Date.now()
  }));

  return favicon;
}

2. Always Have a Fallback

Some sites genuinely don't have favicons:

<img
  src={faviconUrl}
  onError={(e) => {
    e.currentTarget.src = '/default-site-icon.png';
  }}
/>

3. Use Appropriate Sizes

Different contexts need different sizes:

Context Recommended Size
Navigation links 16px
Bookmarks 32px
Tab/sidebar 24px
Cards/previews 48px+

4. Consider SVG When Available

SVG favicons are scalable and look crisp at any size:

const { data } = await response.json();

// Prefer SVG if available
const favicon = data.favicons.find(f => f.type === 'image/svg+xml')
  || data.favicon;

Performance Optimization

Proxy Through Your Backend

Instead of exposing your API key client-side, proxy requests:

// Your API route: /api/favicon
export async function GET(request) {
  const url = request.nextUrl.searchParams.get('url');

  const response = await fetch(
    `https://api.katsau.com/v1/favicon?url=${url}`,
    {
      headers: { 'Authorization': `Bearer ${process.env.KATSAU_API_KEY}` }
    }
  );

  return response;
}

Lazy Load Below the Fold

For lists with many favicons:

<img
  src={faviconUrl}
  loading="lazy"
  decoding="async"
/>

Conclusion

While it seems simple, getting favicons reliably requires handling many edge cases. Using a proper metadata API saves you from dealing with:

  • CORS restrictions
  • Multiple favicon formats
  • Size variations
  • Fallback chains
  • Relative URL resolution

Focus on building your product, not parsing HTML for icons.


Need reliable favicon retrieval? Try Katsau's Favicon API - returns favicons in all available sizes.

Ready to build?

Try Katsau API

Extract metadata, generate link previews, and monitor URLs with our powerful API. Start free with 1,000 requests per month.