Hotlinked images: pictures loaded from another site's server
An image loaded straight from a server you do not control breaks when that site moves it or blocks foreign referrers. squirrel groups them by host.
What hotlinking is
Hotlinking is loading an image from another site’s server instead of your own: a logo from upload.wikimedia.org, a picture copied by URL from a supplier’s or a news site’s CDN. It looks like it works until it does not.
- Reliability. The image breaks when the other site moves it, renames it, rate-limits it or blocks foreign referrers, which many sites do with a placeholder or a 403.
- Performance. A page that loads nothing else from that host pays a DNS lookup, a TLS handshake and a connection for one picture, with no control over caching or format.
- Licensing. It uses someone else’s bandwidth and, often, their copyrighted image.
What squirrel checks
The rule runs on every crawled page and makes no network request: it reads the image URLs already in the markup. It looks at <img> (src, a lazy-loader’s data-src or data-lazy-src, and srcset), <picture> <source> elements and background declarations in inline style attributes, and ignores anything inside <noscript>.
An image host is not a hotlink when it is:
- first-party: the page’s host, a subdomain of it, or any host on the same registrable domain, so
cdn.example.comis fine forexample.com; - on the built-in list of image CDNs, site-builder CDNs and object or app storage, matched on the host or its subdomains: Cloudinary, Imgix, Cloudflare Images, CloudFront, ImageKit,
cdn.shopify.com, WordPress.com’s image hosts (wp.com), Squarespace and Wix CDNs, Contentful and Sanity asset hosts, Storyblok, Prismic, Webflow’s asset host (website-files.com), Bunny, KeyCDN, Fastly, Akamai, Azure and Amazon S3 storage, Google Cloud Storage, Cloudflare R2, DigitalOcean Spaces, Supabase, Vercel, Heroku, Render, Railway, Convex, Framer, jsDelivr, Unsplash, Pexels,gstatic.com,raw.githubusercontent.comand the large social and Google image hosts. The list names CDNs, not whole platforms: another tenant’s site onwebflow.io,wordpress.com,myshopify.comorsquarespace.comis a hotlink; - a launch directory, review or award site that hands out embeddable badges (Product Hunt, Trendshift, DMCA.com, Capterra and similar), or any image whose path or
altnames a badge, widget, seal, “featured” or “launch” badge. Those are served live by the other site by design; - a host the page also loads a script or stylesheet from, or preconnects, dns-prefetches or preloads (an exact host match, read from the whole document,
<noscript>included). This is a signal that the page connects to the host, not a test that the site owns it; - listed in the
allowed_hostsoption.
Skipped altogether: tracking pixels (an image declared 1x1 or smaller, one hidden with display:none, a known analytics or advertising host, or a platform’s pixel path such as facebook.com/tr or pinterest.com/ct), avatar services (Gravatar, Libravatar, ui-avatars.com, avatars.githubusercontent.com, Unavatar, icon.horse), data: and blob: URLs, and any page served from localhost or a loopback address. A relative URL belongs to the page’s own host, or resolves against <base href> when the page sets one. A lazy-loaded image is read from data-src before its placeholder src.
It emits these checks, all info: the rule never lowers the score.
hotlinked-imagesis info when a content image’s host is none of the above. Message:Content image(s) load from other sites' servers. There is one item per host, such asupload.wikimedia.org, labelled with how many images on the page load from it, up to ten hosts with a count of the rest. The message carries no host or count, so the same defect has one identity on every page, and a report can group the pages affected by each host. It passes withNo content images are loaded from other sites' serverswhen the page has content images and none is hotlinked, and is info withNo content images foundwhen it has none.hotlinked-share-imageis info when theog:imageortwitter:imageis on a host that would be reported above. Social platforms fetch those, so a hotlinked share image that breaks fails silently. Turn it off withcheck_social_images = false.
Why info: on a sample of stored crawls, most pages a warning would have flagged loaded a launch or directory badge, or an image from the site’s own infrastructure host that no list could know. The lists and the badge test remove the common ones; the rest is a prompt to look, not a defect.
How to fix it
If it is a picture you are licensed to use, download it and serve it from your own domain or image CDN:
<!-- before -->
<img src="https://upload.wikimedia.org/wikipedia/commons/a/ab/Logo.png" alt="Acme logo">
<!-- after -->
<img src="/images/acme-logo.png" alt="Acme logo" width="120" height="40">If it is a badge, widget or seal the other site keeps up to date (a launch-directory badge, a review score), embedding it from their server is how it is meant to work: leave it. If the host is your own CDN, or a partner you control the arrangement with, add it to allowed_hosts.
| Rule ID | images/hotlinked |
| Category | Images |
| Scope | Per-page |
| Severity | info |
| Weight | 4/10 |
Options
| Option | Type | Default | Description |
|---|---|---|---|
allowed_hosts | array of strings | [] | Hosts whose images are not hotlinks (your own CDN or a partner). An entry matches the host itself and its subdomains, e.g. images.partner.example; a scheme, a path, a port or a leading *. is ignored |
check_social_images | boolean | true | Also report an og:image or twitter:image hosted on another site (info) |
Configuration example
[rule_options."images/hotlinked"]
allowed_hosts = ["media.partner.example", "assets.mycdn.example"]
check_social_images = trueEnable / disable
Disable this rule
[rules]
disable = ["images/hotlinked"]Disable all Images rules
[rules]
disable = ["images/*"]Enable only this rule
[rules]
enable = ["images/hotlinked"]enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.
Related rules
- images/optimized: which image CDNs the site uses and which formats it serves.
- images/responsive-size: small images that serve large files (it skips third-party hosts).
- images/broken-images: image URLs that are empty or placeholders.
- social/og-image-size: the share image’s size.
Images findings ship in every audit next to the SEO, performance and agent experience rules. See Fix SEO issues with AI for how an agent works through a report.
References
Check your site
Run squirrel audit https://example.com and open the Images section of the report. Each hotlinked host is listed with the pages that load from it. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.