How to Detect Font Awesome on Any Website (API Guide)

July 24, 2026 · 11 min read

Font Awesome is the icon toolkit that quietly ended up on a large slice of the web. A developer drops in one stylesheet or one script tag, writes <i class="fas fa-user"></i>, and gets a full icon set without touching an SVG file. That single-line install is exactly why detecting it is useful and exactly why detecting it is trickier than it looks: the install can arrive as CSS, as JavaScript, or as a hosted Kit, and only some of those leave a signal a server-side fetch can read.

This guide covers all of it: what Font Awesome actually is, the four distinct signals it leaves in a page, which of those a scan can and cannot see, how to check a site by hand, and how a single DetectZeStack API call returns Font Awesome alongside the rest of the stack. We will be precise about the false negatives, because with Font Awesome they are common enough to matter.

What Font Awesome Is and Why Detecting It Matters

Font Awesome is a font and icon toolkit based on CSS and Less. It ships thousands of vector icons in two delivery modes: a classic web-font build, where a stylesheet maps class names onto glyphs in a custom font file, and an SVG-with-JS build, where a script replaces <i> placeholders with inline SVG at runtime. Both are in heavy use, and the mode a site picks changes what you can detect.

A confirmed Font Awesome detection is a small but genuinely informative front-end signal:

The same detection pipeline works for any technology DetectZeStack recognizes. We have companion guides for the font-delivery services Adobe Fonts and Typekit; the fingerprint changes, the workflow does not.

The Signals That Reveal Font Awesome in a Page

Font Awesome does not sit in DNS, in response headers, or in a TLS certificate. It is entirely a page-body technology, which means every signal lives in the HTML the server hands back or in the JavaScript that runs afterwards. There are four of them, and they are not equally visible.

CSS link tags (font-awesome.min.css, fontawesome-free, cdnjs and jsDelivr paths)

The classic web-font install is a stylesheet reference. It shows up in the <head> in one of a handful of recognizable shapes:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css">
<link rel="stylesheet" href="/wp-content/themes/acme/assets/css/font-awesome.min.css">

The constant is the string font-awesome or fontawesome in the URL, sometimes under the @fortawesome npm scope. This is the most common install in the wild — and, as we will cover below, it is the one an API scan is most likely to miss, because the fingerprint that matches Font Awesome keys on script sources rather than stylesheet links.

Script sources (kit.fontawesome.com and Kit loader script URLs)

The SVG-with-JS build and the hosted Kit both arrive as a script tag, and this is the strongest machine-readable signal:

<script src="https://kit.fontawesome.com/a1b2c3d4e5.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/js/all.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/js/all.min.js"></script>
<script src="/assets/js/fontawesome-all.js"></script>

The Kit loader is worth calling out separately. A Kit URL is kit.fontawesome.com/<kit-id>.js, where the Kit ID is an opaque identifier tied to an account. The Kit resolves which icon subset and which version to serve on the server side, which means the URL tells you a Kit is in use but deliberately tells you nothing about the version.

JavaScript globals (___FONT_AWESOME___ and FontAwesomeCdnConfig)

Once the SVG-with-JS build has executed, it leaves globals on window. ___FONT_AWESOME___ is the internal registry the library uses for its icon definitions and config; FontAwesomeCdnConfig appears on CDN-delivered builds. Both are reliable confirmations — but only inside a running browser. A server-side HTTP fetch downloads the script tag without executing it, so these globals never materialize in an API scan. Treat them as a DevTools tool, not a scanning one.

Where the version number comes from, and when it is missing

Font Awesome does not announce its version in a header, a meta tag, or a generator comment. Every version signal you can get comes from the asset URL itself:

URL ShapeExampleVersion Readable?
cdnjs path /ajax/libs/font-awesome/6.5.1/css/all.min.css Yes — 6.5.1 in the path
npm-scoped CDN @fortawesome/[email protected]/js/all.min.js Yes — after the @
Kit loader kit.fontawesome.com/a1b2c3d4e5.js No — opaque Kit ID
Self-hosted /assets/css/font-awesome.min.css Usually no

In practice this means the version field on a Font Awesome detection comes back empty far more often than not. If version data is the thing you actually need — for example to separate Font Awesome 4 sites, which use the old fa fa- class prefix, from version 5 and 6 sites — plan on grepping it out of the asset URL yourself rather than relying on the parsed field.

Manual Detection: View Source and DevTools

Because every signal lives in the page, you can confirm Font Awesome yourself with one command. The broadest single check catches both the CSS and the script variants:

$ curl -s https://example.com | grep -oiE '[^"'"'"']*font-?awesome[^"'"'"']*' | sort -u
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css

One match is enough to confirm the page loads Font Awesome, and because the pattern captures the whole URL you get the delivery method and often the version for free. To narrow it to the Kit loader specifically:

$ curl -s https://example.com | grep -o 'kit\.fontawesome\.com/[a-z0-9]*\.js'
kit.fontawesome.com/a1b2c3d4e5.js

For the JavaScript-build case, open DevTools on the page and probe the globals directly in the console:

> typeof window.___FONT_AWESOME___
"object"
> typeof window.FontAwesomeCdnConfig
"object"
> document.querySelectorAll('[class*="fa-"]').length
23

That last line is the pragmatic fallback: counting elements carrying an fa- class tells you Font Awesome icon markup is present even when the asset URL has been renamed or bundled into a generic app.css. It only works in a browser, though — and it is exactly the kind of check that does not scale past one site, which is where an API comes in.

Detecting Font Awesome With the DetectZeStack API

When DetectZeStack fetches a page, it scans the HTML for script sources matching the Font Awesome fingerprint — font-awesome, fontawesome, the @fortawesome npm scope, and the *.fontawesome.com/<id>.js Kit loader. A match returns Font Awesome under the Font scripts category at confidence 100, with source: "http", because the evidence came straight from the HTTP response body.

Trying it without an API key using GET /demo

The public demo endpoint needs no API key. It is IP-rate-limited, so use it for spot checks rather than bulk work:

$ curl -s "https://detectzestack.com/demo?url=example.com" \
  | jq '.technologies[] | select(.name == "Font Awesome")'
{
  "name": "Font Awesome",
  "categories": ["Font scripts"],
  "confidence": 100,
  "description": "Font Awesome is a font and icon toolkit based on CSS and Less.",
  "website": "https://fontawesome.com/",
  "icon": "Font Awesome.svg",
  "source": "http",
  "version": "",
  "cpe": ""
}

Note the empty version and empty cpe. Neither is an error: Font Awesome rarely exposes a parseable version, and it carries no CPE identifier in the fingerprint data, unlike server-side software such as PHP or WordPress. If you are building security workflows around CPE strings, our guide on detecting vulnerable technologies with CPE covers which technologies do carry one.

Full stack scan with GET /analyze

When you want the whole stack for a domain rather than a filtered slice, call /analyze with your API key. A typical WordPress page that loads Font Awesome from cdnjs comes back like this:

$ curl -s "https://detectzestack.p.rapidapi.com/analyze?url=example.com" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com"
{
  "url": "https://example.com",
  "domain": "example.com",
  "technologies": [
    {
      "name": "Font Awesome",
      "categories": ["Font scripts"],
      "confidence": 100,
      "description": "Font Awesome is a font and icon toolkit based on CSS and Less.",
      "website": "https://fontawesome.com/",
      "icon": "Font Awesome.svg",
      "source": "http",
      "version": "",
      "cpe": ""
    },
    {
      "name": "cdnjs",
      "categories": ["CDN"],
      "confidence": 100,
      "description": "cdnjs is a free distributed JS library delivery service.",
      "website": "https://cdnjs.com",
      "icon": "cdnjs.svg",
      "source": "http",
      "version": "",
      "cpe": ""
    },
    {
      "name": "WordPress",
      "categories": ["CMS", "Blogs"],
      "confidence": 100,
      "description": "WordPress is a free and open-source content management system written in PHP and paired with a MySQL or MariaDB database.",
      "website": "https://wordpress.org",
      "icon": "WordPress.svg",
      "source": "http",
      "version": "",
      "cpe": "cpe:2.3:a:wordpress:wordpress:*:*:*:*:*:*:*:*"
    }
  ],
  "categories": {
    "Font scripts": ["Font Awesome"],
    "CDN": ["cdnjs"],
    "CMS": ["WordPress"],
    "Blogs": ["WordPress"]
  },
  "meta": { "status_code": 200, "tech_count": 3, "scan_depth": "full" },
  "cached": false,
  "response_ms": 1842
}

The top-level categories map groups every detection by category, so you can pull every icon and font library with .categories["Font scripts"] without iterating the array. The meta object carries the HTTP status_code, the tech_count, and the scan_depth; response_ms and cached sit at the top level.

Watch meta.scan_depth when you are building lists. A value of "full" means the HTTP fetch succeeded and body detection ran. A value of "partial" means the site blocked or timed out the HTTP request and only the DNS and TLS layers completed — and since Font Awesome lives entirely in the body, an absent detection on a "partial" scan tells you nothing at all. Those domains belong in a retry queue, not your rejects file.

Yes or no answer with GET /check?tech=Font Awesome

If all you need is a boolean, /check answers one question about one domain and returns a much smaller payload. The tech match is case-insensitive, and the response echoes back the canonical name:

$ curl -s -G "https://detectzestack.p.rapidapi.com/check" \
  --data-urlencode "url=example.com" \
  --data-urlencode "tech=Font Awesome" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com"
{
  "domain": "example.com",
  "technology": "Font Awesome",
  "detected": true,
  "confidence": 100,
  "version": "",
  "categories": ["Font scripts"],
  "response_ms": 1210,
  "cached": false
}

Use --data-urlencode rather than pasting the value into the URL — "Font Awesome" contains a space, and an unencoded space will produce a malformed request.

Scanning a list of domains with POST /analyze/batch

For list building, POST /analyze/batch accepts up to 10 URLs per request and analyzes them concurrently. Each entry carries either a full analysis result, identical in shape to a single /analyze response, or an error for domains that could not be fetched:

$ curl -s -X POST "https://detectzestack.p.rapidapi.com/analyze/batch" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["example.com", "getbootstrap.com", "wordpress.org"]}'

Because each result matches the single-domain shape, the filtering logic is identical whether you scan one domain or a thousand. Here is a complete pipeline using nothing but bash, curl, and jq. It reads domains.txt one domain per line, sends batches of 10, and appends every Font Awesome hit to a CSV along with the tech count and the scan depth:

#!/usr/bin/env bash
# find-font-awesome.sh — filter a domain list down to Font Awesome sites
KEY="YOUR_KEY"
HOST="detectzestack.p.rapidapi.com"

echo "domain,tech_count,scan_depth" > fontawesome_leads.csv

# Process domains.txt in batches of 10 (the /analyze/batch maximum)
xargs -n 10 < domains.txt | while read -r batch; do
  urls=$(printf '%s\n' $batch | jq -R . | jq -s '{urls: .}')
  curl -s -X POST "https://$HOST/analyze/batch" \
    -H "X-RapidAPI-Key: $KEY" \
    -H "X-RapidAPI-Host: $HOST" \
    -H "Content-Type: application/json" \
    -d "$urls" |
  jq -r '.results[]
    | select(.result != null)
    | .result as $r
    | select([$r.technologies[].name] | index("Font Awesome"))
    | [$r.domain, ($r.meta.tech_count | tostring), $r.meta.scan_depth]
    | @csv' >> fontawesome_leads.csv
done

wc -l fontawesome_leads.csv

A 1,000-domain list becomes 100 batch calls. The index("Font Awesome") guard keeps a domain whenever Font Awesome appears in its technology list, and select(.result != null) skips domains that failed to resolve. For a deeper treatment of throughput, retries, and a production Python scanner, see how to batch scan 1,000 websites.

What Font Awesome Tells You About the Rest of the Stack

Font Awesome almost never travels alone, and the technologies it appears next to are usually more commercially interesting than the icon set itself. Three pairings come up constantly:

Common Detection Pitfalls and False Negatives

Font Awesome produces more false negatives than most technologies, and it is worth being blunt about why.

The honest limitation: the fingerprint DetectZeStack matches for Font Awesome keys on the script source. A site that loads Font Awesome purely as a stylesheet — <link rel="stylesheet" href="/css/font-awesome.min.css"> with no accompanying script — is a real Font Awesome install that can still come back with no detection. That is the classic web-font build, and it is common. If CSS-only installs matter for your use case, pair the API scan with a grep over the fetched HTML for the string font-awesome.

Beyond that, four more causes account for most misses:

The practical rule: a Font Awesome detection is strong evidence of presence, and an absent detection is an unknown rather than proof of absence. Build your filters so positives drive action and negatives drive a second look.

Practical Use Cases: Agency Prospecting, Front-End Audits, Performance Reviews

Agency prospecting. Font Awesome plus WordPress plus a page builder is a reliable signature for a site that was assembled from a template. That is a qualified lead for design refresh, migration, or ongoing maintenance work — and the whole triple comes back in one /analyze call, so you can score a domain list in a single pass. Our guide to competitor website technology analysis covers building that scoring layer.

Front-end audits. When you inherit a codebase, "which icon system is actually loading, and how many are loading at once" is a real question. It is not unusual to find Font Awesome and a second icon set both shipping because two different theme layers each pulled one in. A scan across every page template surfaces that in minutes.

Performance reviews. The classic web-font build blocks rendering on a CSS file plus font files. Detecting Font Awesome, then checking whether the site uses the full build or a subset, turns a vague "your fonts are slow" into a specific, quantified finding you can put in a proposal.

Get Your API Key and Start Detecting Font Awesome

The free tier includes 100 requests per month with no credit card — enough to validate the pipeline on a sample of your domain list before scaling up. Sign-up is instant through RapidAPI:

  1. Get a key at rapidapi.com/mlugoapx/api/detectzestack.
  2. Spot-check a domain you know: curl -s "https://detectzestack.com/demo?url=yourdomain.com" | jq '.technologies[].name'
  3. Run the batch script above against your first 100 domains.

Conclusion

Detecting Font Awesome comes down to knowing which of its four signals you can actually reach. The script source is the one an API scan reads, and it returns Font Awesome under the Font scripts category at confidence 100 with source: "http". The stylesheet link is the most common install but the easiest to miss, so pair the scan with a grep when CSS-only sites matter. The JavaScript globals are a DevTools confirmation, not a scanning one. And the version, when it exists at all, lives in the asset URL rather than the parsed version field. Get those four straight and a single /analyze call answers the one-domain question, while /analyze/batch turns a raw domain list into a qualified one.

Related Reading

Try DetectZeStack Free

100 requests per month, no credit card required. Header, DNS, and TLS detection included on every plan.

Get Your Free API Key

Get API updates and tech detection tips

Join the mailing list. No spam, unsubscribe anytime.