···11# favicon.blueat.net
2233-A small [Cloudflare Worker](https://developers.cloudflare.com/workers/) that fetches a website’s favicon by domain, caches responses at the edge, and returns the image (or a redirect fallback).
33+The fastest way to fetch favicons for any website.
44+55+A [Cloudflare Worker](https://developers.cloudflare.com/workers/) that fetches a website’s favicon by domain, caches responses at the edge, and returns the image (or a redirect fallback).
4655-## Quick start
77+## Endpoint
6877-```bash
88-npm install
99-npm run dev
99+```
1010+GET https://favicon.blueat.net/{domain}
1111+GET https://favicon.blueat.net/{domain}?larger=true
1012```
11131212-Open `http://localhost:8787/example.com` while `dev` is running.
1414+## Parameters
13151414-Deploy:
1616+| Parameter | Default | Description |
1717+|-----------|---------|-------------|
1818+| `larger` | `false` | Return a high-res icon (128px+). Prefers SVG, then large PNG. |
1919+| `default-avatar` | — | URL to redirect to when no favicon is found. Must be URL-encoded. |
2020+| `throw-error-on-404` | `false` | Return HTTP 404 instead of a placeholder when no favicon is found. |
15211616-```bash
1717-npx wrangler login # once per machine
1818-npm run deploy
1919-```
2222+## Examples
20232121-Edit `wrangler.toml` and set `name` to the Worker name you want in Cloudflare.
2222-2323-## Usage
2424+### HTML
24252525-Request path is the domain (no protocol):
2626+```html
2727+<!-- Standard 16px favicon -->
2828+<img src="https://favicon.blueat.net/github.com"
2929+ width="16" height="16" alt="GitHub" />
26302727-| URL | Meaning |
2828-|-----|--------|
2929-| `/{domain}` | Resolve favicon for `domain` |
3131+<!-- High-resolution (128px+) -->
3232+<img src="https://favicon.blueat.net/github.com?larger=true"
3333+ width="64" height="64" alt="GitHub" />
30343131-**Query parameters**
3535+<!-- Custom fallback when no favicon is found -->
3636+<img src="https://favicon.blueat.net/unknown.xyz?default-avatar=https%3A%2F%2Fexample.com%2Fdefault.png"
3737+ width="16" height="16" alt="favicon" />
3838+```
32393333-| Param | Effect |
3434-|--------|--------|
3535-| `larger=true` | Prefer larger icons (e.g. Google s2 at 128px, SVG, or big apple-touch sizes from HTML) |
3636-| `default-avatar=<url>` | If no favicon is found, `302` redirect to this URL |
3737-| `throw-error-on-404=true` | If no favicon is found, return `404` instead of redirecting |
4040+### JavaScript
38413939-Successful responses include `Cache-Control`, `Access-Control-Allow-Origin: *`, and `X-Favicon-Source` describing where the icon came from.
4242+```javascript
4343+const res = await fetch("https://favicon.blueat.net/github.com?larger=true");
4444+const blob = await res.blob();
4545+document.getElementById("icon").src = URL.createObjectURL(blob);
4646+```
40474148## How it works
4249···44512. If `larger`, try Google’s favicon service at 128px.
45523. Otherwise fetch the site HTML and parse `<link rel="icon">` / apple-touch-icon tags.
46534. Fall back to `/favicon.ico`, then Google’s 32px favicon.
4747-5. If nothing works, redirect to a default image or your `default-avatar`, or `404` when requested.
5454+5. If nothing works, redirect to a default image or your `default-avatar`, or return 404 when requested.
5555+5656+### Why might a favicon not be found?
5757+5858+| Reason | Details |
5959+|--------|---------|
6060+| Site has no favicon | The domain has no `/favicon.ico`, no `<link rel="icon">` tag, and Google has no cached icon for it. Rare for established sites, common for new or private ones. |
6161+| Site blocks bots | The domain's server returns a 403 or 429 for automated requests, preventing the HTML parse step. The `/favicon.ico` direct fetch and Google S2 fallbacks are still attempted. |
6262+| Request timeout | Each upstream fetch has a 5 second timeout. Slow or unresponsive origins will be skipped. If all strategies time out, the fallback image is returned. |
6363+| Icon behind authentication | Some sites only serve their favicon to authenticated users, so the HTML fetch returns a login page with no `<link>` tags pointing to a real icon. |
6464+| Non-standard content type | The worker validates that responses have an image content type (`image/*`, icon, svg, or octet-stream). Files served with an unexpected content type are rejected. |
6565+| Domain doesn't exist | DNS resolution fails for the domain, so all direct fetch strategies return nothing. Google S2 is still tried as a last resort since Google may have a cached record. |
6666+| Icon is an inline data URI | Some sites embed their icon directly as a `data:` URL in the `<link>` tag. These are intentionally skipped — only external URLs are fetched. |
6767+6868+## Try it
6969+7070+| | |
7171+|--|--|
7272+| default | [https://favicon.blueat.net/BlueAT.net](https://favicon.blueat.net/BlueAT.net) |
7373+| larger=true | [https://favicon.blueat.net/BlueAT.net?larger=true](https://favicon.blueat.net/BlueAT.net?larger=true) |
7474+7575+---
7676+7777+## Development & deploy
7878+7979+```bash
8080+npm install
8181+npm run dev
8282+```
8383+8484+Open `http://localhost:8787/github.com` while `dev` is running.
8585+8686+Deploy:
8787+8888+```bash
8989+npx wrangler login # once per machine
9090+npm run deploy
9191+```
9292+9393+Edit `wrangler.toml` and set `name` to the Worker name you want in Cloudflare.
48944995## Files
5096