Favicon & Logo Extractor: Icons from Any Website avatar

Favicon & Logo Extractor: Icons from Any Website

Pricing

$2.00 / 1,000 site checkeds

Go to Apify Store
Favicon & Logo Extractor: Icons from Any Website

Favicon & Logo Extractor: Icons from Any Website

Favicon, apple-touch icon, manifest icons, og:image and logo of any website, with the real size read from each file and the best icon picked. $2 per 1K sites.

Pricing

$2.00 / 1,000 site checkeds

Rating

0.0

(0)

Developer

Kaizoku Data

Kaizoku Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 days ago

Last modified

Security

Limited permissions

Share

Get the favicon, apple-touch icon, web-app manifest icons, og:image and header logo of many websites in one run. You get one row per site. Every candidate file is fetched and its real format and pixel size are read from the file itself, not taken from what the HTML claims. The row also names the best icon and the best logo by a published rule. Optionally, a copy of both is stored with a public link. No browser, no proxy, no key.

Price: $2.00 per 1,000 sites ($0.002 per site with at least one verified icon), plus Apify's default Actor-start event. Sites where no icon could be verified, blocked sites and errors are free.

  • Every source in one row: <link rel="icon">, shortcut icon, apple-touch-icon, mask-icon, the icons in manifest.json / site.webmanifest, og:image, twitter:image, logo images in the page header, and /favicon.ico as a fallback.
  • Real sizes, not declared ones: PNG, ICO (every size inside the file), SVG (width/height or viewBox), JPEG, WebP, GIF, AVIF and BMP are measured from the first bytes of each file, without an image library. HTML error pages served as "icons" are recognised and skipped.
  • A clear pick: bestIcon is the largest square icon, or the one closest to your Preferred size. bestLogo is the logo image that names the site or sits in its header. The rule is printed below.
  • Optional stored copy: with Store a copy on, the best icon and logo (at most 2 MB each) are saved to the run's key-value store, and each gets a public link. An SVG with scripts or external references is never stored.
  • Quick start: press Start. The prefilled input checks crawlee.dev and apify.com (two sites run by Apify). It takes under a minute (about 15 seconds of checking) and costs $0.004.

Polite by design. robots.txt is read for every host the Actor contacts and obeyed for the homepage, the manifest and every image. The Actor sends an honest User-Agent, makes at most one request per second per host (longer when robots.txt asks for a Crawl-delay), and fetches at most 12 files per site. Blocks (401, 403, 429, 503, challenge pages) become free rows and are never worked around.

What it does

For each site:

  1. Guard. Social-media, video and Google hosts, and their image CDNs (gstatic, ggpht, googleusercontent, fbcdn, twimg, cdninstagram, licdn, ytimg …), are refused before any DNS lookup (platform). Every request goes to public addresses only. This is checked on every redirect hop and again when connecting, so private, loopback, link-local and cloud-metadata addresses are refused (ssrf).

  2. Homepage. robots.txt, then one GET of https://host/ (redirects followed, at most 5). Only the first 1 MB of HTML is read. It is scanned in a separate worker thread with a time and memory limit, for icon links, the manifest link, og:image / twitter:image, <base href> and logo images. Script, style, template, noscript and inline SVG content is skipped, so an icon link inside a script string is not a candidate.

  3. Manifest. If the page links a web-app manifest, it is fetched (at most 256 KB, with its shape checked before parsing) and its icons are added.

  4. Fallback. /favicon.ico on the site's origin is always a candidate. It is also tried when the homepage answers with an HTTP error or is not HTML.

  5. Verify. At most 12 files per site, in this order:

    1. icon links, larger declared sizes first;
    2. manifest icons;
    3. /favicon.ico;
    4. at most 2 og/twitter images;
    5. at most 3 logo images (those that name the site first, then those in the header);
    6. the mask icon.

    Each file is fetched with one GET, and the first 128 KB is read. A file under 128 KB is read whole. Its real format and size are taken from its header bytes.

  6. Pick bestIcon and bestLogo (rule below). With Store a copy on, save each to the key-value store. A file already read whole is reused; a larger one gets one more GET, capped at 2 MB.

Up to 5 sites are checked at the same time. Requests to one host are spaced at least 1 second apart. Each site has a hard 30-second budget for its requests, plus at most 20 seconds of waiting for the rate limit and Crawl-delay. The delay is never shortened: when it would pass that limit, the remaining files are marked not-checked.

Input

FieldWhat it does
Domains (domains)Host names or URLs, one per line, up to 1,000 per run. example.org, www.example.org and https://example.org/any/path all work: the homepage / of that host is read. Without a scheme, https:// is used; write http://host for a site without HTTPS. Duplicates are checked once.
Store a copy of the best icon and logo (downloadImages)Default off. On: the best icon and best logo (at most 2 files per site, each at most 2 MB) are saved in the run's key-value store, and the row gets bestIconStoredUrl / bestLogoStoredUrl. Same price.
Preferred icon size (px) (preferredSize)Optional, 16–1024. The best icon becomes the smallest square raster icon at least this wide. If none is that large, an SVG is picked; if there is no SVG either, the largest icon. Empty: the largest icon.

Example inputs

1. Icons for a list of company domains (CRM enrichment):

{
"domains": ["crawlee.dev", "apify.com", "python.org", "mozilla.org"]
}

2. A 64 px icon for each site, with a stored copy you can embed:

{
"domains": ["https://www.wikipedia.org/", "rust-lang.org", "go.dev"],
"preferredSize": 64,
"downloadImages": true
}

3. High-resolution app icons (512 px manifest icons when a site has them):

{
"domains": ["github.com", "ubuntu.com"],
"preferredSize": 512
}

Output

One item per site (JSON, CSV, Excel or XML). The Overview view shows the best icon as an image. Example (shortened):

{
"input": "crawlee.dev",
"domain": "crawlee.dev",
"url": "https://crawlee.dev/",
"finalUrl": "https://crawlee.dev/",
"status": "ok",
"billable": true,
"bestIconUrl": "https://crawlee.dev/img/favicon.ico",
"bestIconSize": "202x202",
"bestIconFormat": "png",
"bestIconSource": "icon",
"bestIconStoredUrl": "https://api.apify.com/v2/key-value-stores/<store id>/records/icon-crawlee.dev-19b2bfc42aee.png",
"bestLogoUrl": "https://crawlee.dev/img/crawlee-light.svg",
"bestLogoSize": "106x28",
"bestLogoStoredUrl": "https://api.apify.com/v2/key-value-stores/<store id>/records/logo-crawlee.dev-192e40bd55d9.svg",
"ogImageUrl": "https://crawlee.dev/img/crawlee-og.png",
"bestIcon": {
"url": "https://crawlee.dev/img/favicon.ico", "source": "icon", "format": "png", "width": 202, "height": 202, "bytes": 28248,
"storedKey": "icon-crawlee.dev-19b2bfc42aee.png", "storedUrl": "https://api.apify.com/v2/key-value-stores/<store id>/records/icon-crawlee.dev-19b2bfc42aee.png",
"storedBytes": 28248, "sha256": "19b2bfc42aee2cdc…", "storeError": null, "storeMessage": null
},
"bestLogo": { "url": "https://crawlee.dev/img/crawlee-light.svg", "source": "logo", "format": "svg", "width": 106, "height": 28, "…": "…" },
"manifestUrl": null,
"manifestError": null,
"candidates": [
{
"url": "https://crawlee.dev/img/favicon.ico", "source": "icon", "declaredSizes": null, "declaredType": null, "purpose": null,
"inHeader": null, "hint": null, "nameMatch": null, "color": null, "verified": true, "httpStatus": 200, "contentType": "image/vnd.microsoft.icon",
"finalUrl": null, "format": "png", "width": 202, "height": 202, "sizes": null, "bytes": 28248, "svgSafe": null, "svgFlags": null,
"error": null, "message": null
},
{ "url": "https://crawlee.dev/favicon.ico", "source": "favicon.ico", "verified": false, "httpStatus": 404, "error": "http", "…": "…" }
],
"candidateCount": 5,
"verifiedCount": 4,
"inlineIcons": 0,
"pageNote": null,
"errorCode": null,
"message": null,
"checkedAt": "2026-10-26T18:20:00.000Z",
"siteKey": "https://crawlee.dev:443"
}

The example shows why real sizes matter: crawlee.dev's favicon.ico is really a 202×202 PNG.

FieldMeaning
statusok (at least one icon verified, charged), no-icon (the site was read but no icon could be verified, free), error (see errorCode, free).
bestIconUrl, bestIconSize, bestIconFormat, bestIconSourceThe best icon, its real size (180x180, or scalable for an SVG without a size), format and where it was found.
bestLogoUrl, bestLogoSizeThe best logo image, or null.
bestIconStoredUrl, bestLogoStoredUrlPublic links to the stored copies (with Store a copy on).
bestIcon, bestLogoThe same plus bytes, storedKey, storedBytes, sha256, and storeError / storeMessage when no copy was stored.
ogImageUrlThe page's og:image (else twitter:image).
candidates[]Up to 30. For each: url, source (see below), what the page declared (declaredSizes, declaredType, purpose for manifest icons, color for mask icons), logo hints (inHeader, hint: class/id/alt/file-name/parent, nameMatch), whether it was verified, the HTTP answer (httpStatus, contentType, finalUrl after redirects), what the file really is (format, width, height, sizes for every image inside an ICO, bytes), SVG safety (svgSafe, svgFlags) and error / message.
source valuesicon, shortcut icon, apple-touch-icon, mask-icon, manifest, favicon.ico, og:image, twitter:image, logo.
manifestUrl, manifestErrorThe manifest link and why it could not be read (too-large, too-complex, bad-manifest, http, refused …).
inlineIconsIcons embedded as data: URIs (counted, not listed).
pageNoteHomepage notes: cut at 1 MB, not HTML, an HTTP error (only /favicon.ico tried), or a scan problem.

How the best icon is picked

Only verified candidates count: the file was fetched and its real format and size were read.

  1. Icon sources only: apple-touch-icon, icon, shortcut icon, manifest and favicon.ico. mask-icon (a one-colour Safari pinned-tab shape) is used only when nothing else was verified. og:image, twitter:image and logo images are never the best icon.
  2. Square beats non-square: both sides must be within 10% of each other.
  3. Size:
    • With Preferred size P: the smallest raster icon at least P px wide. If none is that large, an SVG (it scales); if there is no SVG either, the largest raster icon.
    • Without it: the largest raster icon. An SVG wins only when the largest raster icon is under 64 px.
  4. Ties: PNG before SVG before ICO before WebP before other formats. Then by source: apple-touch-icon, manifest, icon, shortcut icon, favicon.ico. Then page order.

Best logo: among verified logo images, those whose file name or alt text contains the site's name come first (for rust-lang.org, "rust" or "lang"; parts under 3 letters are ignored). Next come those inside the page header, then SVG, then the larger image. A logo image that neither names the site nor sits in the header is listed but never picked: it is usually a partner or sponsor logo. If none is left, the result is null. Logo detection is best-effort: an <img> counts when its class, id, alt text or file name contains "logo", or when it sits inside an element whose class or id contains "logo". Logos drawn as inline <svg> or as CSS backgrounds have no URL and are not found.

Error codes

CodeWhereMeaningCharged
no-iconrowThe site was read, but no icon file could be verified (all missing, blocked, not images …).No
invalid-inputrowNot a host name or http(s) URL.No
platformrow, candidateA social-media, video or Google host (or one of their image CDNs). Never contacted.No
ssrfrow, candidateResolves to a private, loopback, link-local or reserved address, also after a redirect.No
dnsrow, candidateThe host name does not resolve.No
network, tls, timeoutrow, candidateCould not connect, the HTTPS certificate or handshake was not accepted, or no answer in time (15 s per answer; 30 s per site).No
refusedrow, candidate401, 403, 429, 503, 999 or a challenge page. Not retried; no other method tried.No (a blocked homepage gives a free row; a blocked single file is a candidate problem, see "(row)")
host-skippedrow, candidateThe host refused 2 requests in this run and is not asked again.No
robots-blockedcandidaterobots.txt disallows that file for this Actor. When it disallows the homepage, /favicon.ico is still tried if allowed.(row)
robots-unavailablerow, candidaterobots.txt answered 5xx/429 or could not be read (tried twice): nothing on that host is fetched.No
slow-host, wait-budgetrow, candidaterobots.txt asks for a Crawl-delay over 30 s, or the waiting for this site or run would pass its cap. Never shortened.No
httpcandidateThe file answered another HTTP error (for example 404).(row)
not-an-imagecandidateThe file is not an image format this Actor recognises (often an HTML "not found" page served with status 200).(row)
not-checkedcandidateOver the per-site limits (12 files, 3 logo images, 2 og/twitter images, 3 other hosts, or the time ran out).(row)
redirects, invalid-url, headers-too-largerow, candidateMore than 5 redirects, an unusable URL, or response headers over 64 KB.No
internalrowUnexpected error in this Actor (not a problem with the site).No

"(row)": a candidate-level problem; the row is charged only if another icon of the site was verified.

storeError (stored copies only): svg-active-content (the SVG holds a script, event handler, javascript: URL (also when hidden by character references or tabs), entity declaration, foreignObject, XHTML elements, embedded content, an external reference or a non-UTF-8 encoding, so it is never stored), too-large (over 2 MB), changed (the file changed between two requests), or a fetch code from the table. A row is still charged when its icon was verified but could not be stored.

RUN_SUMMARY (key-value store record)

This record holds:

  • charged and free rows, and charged events;
  • iconsVerified and imagesStored;
  • httpRequests, bytesDownloaded and bytesUnpaid (downloaded for free rows);
  • crawlDelayWaitSecs, parseFailures and errors by code;
  • stoppedBy: finished, max-charge, unpaid-work-cap, time-limit, migrating, aborted or error.

Pricing

Pay per event: site-checked = $0.002. It is charged once for each site whose row has at least one verified icon (billable: true). The following are free:

  • sites without a verified icon;
  • invalid, refused or platform inputs;
  • blocked sites and network errors.

Store a copy costs the same, and the charge does not depend on the copy: a site whose icon was verified is charged even when its copy could not be stored (an unsafe SVG, a file over 2 MB, or a file that changed between two requests). The row then shows why in bestIcon.storeError. There is no start fee of our own; Apify's default Actor-start event applies.

Sites with a verified iconPrice
2 (the prefilled example)$0.004
100$0.20
1,000 (the per-run maximum)$2.00
10,000 (10 runs)$20.00

Set a maximum charge per run in the run options. The Actor stops cleanly before the next site it could not pay for; that site is not fetched and not written. To protect you from paying for compute on bad lists, the run stops when free rows reach 100 and outnumber charged rows, or after 100 MB of downloads for free rows.

Use it via API, n8n or Make

Get an API token in Apify Console under Settings, API & Integrations, and keep it in an environment variable (APIFY_TOKEN below). Never paste it into shared code.

cURL (starts a run, waits and returns the rows; the synchronous endpoint waits up to 5 minutes, so use it for lists of up to about 100 sites):

curl -X POST "https://api.apify.com/v2/acts/ataism~favicon-logo-extractor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"domains": ["crawlee.dev", "apify.com"], "preferredSize": 64}'

Python (pip install "apify-client>=3"):

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("ataism/favicon-logo-extractor").call(run_input={
"domains": ["crawlee.dev", "apify.com"],
"downloadImages": True,
})
for row in client.dataset(run.default_dataset_id).iterate_items():
print(row["domain"], row["bestIconSize"], row["bestIconUrl"], row["bestIconStoredUrl"])

(With apify-client versions before 3.0, call() returns a dict: use run["defaultDatasetId"].)

JavaScript (npm install apify-client):

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('ataism/favicon-logo-extractor').call({
domains: ['crawlee.dev', 'apify.com'],
preferredSize: 180,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const row of items) console.log(row.domain, row.status, row.bestIconSize, row.bestIconUrl);

n8n:

  1. Add the Apify node, operation Run an Actor and get dataset, Actor ataism/favicon-logo-extractor, input {"domains": ["your-customer.example"], "preferredSize": 64}.
  2. Map bestIconUrl (or bestIconStoredUrl with downloadImages) to the logo field of your CRM or spreadsheet node.

Make:

  1. Add the Apify module Run an Actor, choose ataism/favicon-logo-extractor, put your domains in the input JSON and set Run synchronously to Yes.
  2. Add the Apify module Get Dataset Items and map the run's default dataset ID (one bundle per site).
  3. Send domain, bestIconUrl and bestLogoUrl to Google Sheets, Airtable or your CRM.

Privacy, trademarks and terms

  • Logos and icons are trademarks or copyrighted works of their owners. This Actor only reports the public URLs that a site itself publishes, plus, if you ask for it, a copy for your own use. You are responsible for having the rights to use any icon or logo: for example, showing a company's logo next to its name in your own CRM is common, while using it in your own product or advertising may need permission. Nothing here is legal advice.
  • Stored copies are saved in your run's key-value store, and their links are readable by anyone who has them (the same as any Apify record URL). Delete the store, or keep the links private, if that matters to you. Only the best icon and logo are stored, never the other candidates.
  • What the output contains: URLs, image formats and sizes, HTTP facts and the page's declared icon attributes. Page titles and alt texts are not output; alt text is only used to rank logo candidates. A personal website's logo or icon can still show a person (a photo used as a favicon, for example): it is reported as published.
  • Check only sites you may check. robots.txt is obeyed, the User-Agent is favicon-logo-extractor-actor/0.1 (https://apify.com/ataism/favicon-logo-extractor) and blocks are reported, never worked around. Social-media, video and Google sites are refused.

Limits and honest caveats

  • No JavaScript: icons inserted by scripts after load (some single-page apps) are not seen. /favicon.ico and the manifest still often cover these sites.
  • Logo detection is best-effort (see the rule above). Inline-SVG and CSS-background logos are not found, and a site without a logo image in its header gets bestLogo: null.
  • Sizes of large JPEGs: the size is read from the first 128 KB. A JPEG whose size marker comes after a very large metadata block gets width: null (still verified).
  • SVG files are never rendered or executed. Only the root <svg> tag is read. A file with active or external content is flagged in svgFlags and never stored.
  • Per site: at most 12 files fetched, 30 candidates listed, 3 other hosts (CDNs) contacted, 1 MB of homepage HTML, a 256 KB manifest, 2 MB per stored copy, 2 stored copies, and 30 s of request time. Per run: 1,000 sites and 60 minutes.
  • Only the homepage is read, not other pages. HTTPS certificates are verified as a browser would: a site with a broken certificate gets tls.

FAQ

Why is a site "no-icon" when my browser shows an icon? The icon may be added by JavaScript, served only to browsers, blocked for automated clients (refused in the candidate list), or disallowed by robots.txt. The candidates list shows what was tried and why each one failed.

Why do declared and real sizes differ? Many sites declare sizes="32x32" for a file that is really 16×16 or 512×512, or serve a PNG named favicon.ico. This Actor reports both, and picks by the real size.

Can I get every icon, not just the best one? Yes, candidates lists them all with real sizes. Only the best icon and logo are stored as copies.

Open-source components

apify SDK 3.7.2 (Apache-2.0). Everything else (HTML scanning, image size reading, robots.txt, the URL guard) is written in this repository without further dependencies.