ScreenshotNeo

BlogHow-to

Why Are External Images Not Loading? A Complete Debugging Guide

Find out why an external image is missing, read the exact browser error, and fix URLs, HTTPS, CSP, CORS, server, and network problems.

By the ScreenshotNeo team29 September 202610 min read

Why Are External Images Not Loading? A Complete Debugging Guide

An external image can fail because the URL is wrong, the image server is unavailable, an HTTPS page requests an HTTP image, the page’s Content Security Policy (CSP) rejects the image host, or a browser, network, VPN, or security product blocks the connection. Cross-origin restrictions are usually not the reason a normal <img> element stays blank; they matter when JavaScript or a canvas tries to read the image response or its pixels.

The fastest diagnosis is to open the image URL directly, then inspect the browser’s Console and Network panels. The exact signal usually tells you which fix applies: mixed-content warning, CSP violation, CORS error, HTTP status, TLS failure, or connection reset.

1. Establish what is actually failing

Before changing code, determine whether the problem is the image, the page, or your environment.

  1. Open the image URL directly. Copy the value of src into a new tab. A 404, 403, expired link, redirect loop, certificate warning, or blank response points to the image host or URL.
  2. Check the scope. Does one image fail, every image on one site, or images on many sites? A single failed asset suggests its URL or server. One affected site suggests that site’s policy or hosting. Failures across sites suggest a browser, network, VPN, or security tool.
  3. Inspect developer tools. Open DevTools with F12, select Console, reload the page, and then inspect the failed request under Network. Record the request URL, status, redirect chain, response headers, and console message.
  4. Test without extensions and with another network. Temporarily compare a private window, another browser, or a different connection. This helps isolate extensions, VPN filtering, DNS problems, and security software.

2. Read the browser error correctly

Diagnostic signal Likely area Next action
Mixed-content warning or an http:// image on an HTTPS page Transport security Use an HTTPS image URL and verify that the host serves it securely. Browsers can upgrade some image requests and block others, including some IP-address hosts. MDN’s mixed-content guidance explains the distinction.
CSP violation naming the image host Page policy Review the site’s img-src policy and allow only the intended trusted source. See MDN’s CSP documentation.
Image is visible, but canvas or script access fails Cross-origin data access Configure CORS on the remote server for the required origin and use. Embedding and reading image data are different operations. See MDN’s CORS guide.
404, 410, or 403 response URL, permissions, or resource lifetime Correct the path, publish the file, provide permitted access, or generate a current signed URL.
301/302 loops or a redirect to a login page Redirect or authentication Follow the chain in Network, use the final HTTPS asset URL, and provide required credentials only through a design intended for public image delivery.
Certificate, TLS, DNS, or connection-reset error Host or network Check the certificate, DNS, firewall, VPN, proxy, browser version, and security software. Compare another browser or network.
Trace the request from the page to the image host, then use the failing stage to choose a fix.
Trace the request from the page to the image host, then use the failing stage to choose a fix.

3. Fix an incorrect or unavailable image URL

A typo is the most direct failure. Check every part of the URL:

  • Use the correct hostname and path, including capitalization on case-sensitive servers.
  • Encode spaces and special characters. Use encodeURI for a complete URL or encodeURIComponent for a path segment.
  • Check relative paths. images/photo.png resolves relative to the current document URL, while /images/photo.png resolves from the site root.
  • Confirm that the asset still exists and that its content type is an image such as image/png, image/jpeg, or image/webp.
  • Inspect cache-busting query parameters and signed URL expiry times. A URL that worked yesterday may now return 403 or 404.

Use the Network panel’s Response tab. An HTTP 200 does not guarantee a usable image: the body may be an HTML error page, a login form, or truncated binary data. Check the response headers and preview.

4. Resolve HTTPS and mixed-content failures

If the document is loaded over HTTPS and the image URL begins with HTTP, the browser treats it as mixed content. Some image requests are upgraded automatically; others are blocked. The reliable fix is to serve the image over HTTPS and reference that HTTPS URL. Do not silence the warning with a browser setting for a production site.

<!-- Prefer this -->
<img src="https://cdn.example.com/photos/cat.webp" alt="Cat">

<!-- This can be blocked on an HTTPS page -->
<img src="http://cdn.example.com/photos/cat.webp" alt="Cat">

Check every redirect as well. An HTTPS URL that redirects to HTTP can still produce a mixed-content failure. Configure the image host and CDN to retain HTTPS through the final response, and renew certificates before they expire.

5. Check Content Security Policy (CSP)

A CSP can restrict the origins permitted in image requests. The response header might contain a policy such as:

Content-Security-Policy: default-src 'self'; img-src 'self' https://images.example.com data:;

In this example, an image from https://other.example is rejected. The console identifies the blocked URL and directive. A site owner should add the required, trusted image origin to img-src, preferably in a narrow policy:

Content-Security-Policy: default-src 'self'; img-src 'self' https://images.example.com;

Do not add a wildcard merely to make one error disappear. Review whether the host is controlled, whether it uses HTTPS, and whether allowing it creates an unwanted data-exfiltration path. If you do not control the page, only its owner can change the CSP.

6. Separate display problems from CORS problems

A browser can generally display a cross-origin image in an <img> element without granting your JavaScript access to the response body. CORS becomes relevant when code fetches the image, draws it to a canvas and calls getImageData, or otherwise reads pixels or response data.

const image = new Image();
image.crossOrigin = "anonymous";
image.onload = () => {
  const canvas = document.createElement("canvas");
  canvas.width = image.naturalWidth;
  canvas.height = image.naturalHeight;
  canvas.getContext("2d").drawImage(image, 0, 0);
  // This requires the image server to grant CORS permission.
  const pixels = canvas.getContext("2d").getImageData(0, 0, 1, 1);
};
image.onerror = () => console.error("The image could not be loaded");
image.src = "https://images.example.com/photo.jpg";

The remote server must return an appropriate header, for example Access-Control-Allow-Origin: https://your-site.example (or a carefully chosen policy for your use). Adding a header in your own page or disabling browser security locally does not grant permission on the remote server. If the image only needs to be shown, remove unnecessary fetch or canvas access instead of adding CORS complexity.

Some image hosts require a Referer, a cookie, an authorization header, or a short-lived signature. Others deliberately reject requests from different sites through hotlink protection. A browser request from an <img> tag cannot safely carry a secret API key in page source.

  • Use a public, cacheable image endpoint for public images.
  • For private images, issue a short-lived signed URL or proxy the request through your server after authenticating the user.
  • Check whether the server returns 403 only when the request has a particular referrer or user agent.
  • Ensure the server sends a correct Content-Type and complete response. Avoid returning an HTML error document with status 200.

For a command-line check, inspect headers without downloading the whole file:

curl -I -L "https://images.example.com/photo.jpg"

# Download and identify the response
curl -L "https://images.example.com/photo.jpg" -o /tmp/photo.bin
file /tmp/photo.bin

8. Account for lazy loading, JavaScript, and layout conditions

An image may not be requested yet. Lazy-loading libraries often keep the real URL in data-src until the element enters the viewport. Inspect the rendered element and scroll it into view. Check whether JavaScript replaces or removes the element after an error.

Use a valid src, meaningful dimensions, and an error handler while debugging:

<img
  src="https://images.example.com/photo.webp"
  width="800"
  height="450"
  loading="lazy"
  alt="Product preview"
  onerror="this.dataset.failed='true'">

CSS can also make a loaded image appear missing. Inspect computed styles for display:none, zero width or height, opacity:0, clipping, a covering element, or a broken object-fit rule. The Network panel confirms whether the request happened; the Elements and Computed panels confirm whether it is visible.

9. Diagnose network and local security interference

A connection reset, timeout, DNS failure, or TLS error can originate outside the page. Compare:

  1. The same URL in another browser.
  2. The same browser with extensions disabled or in a private window.
  3. A different network, such as a mobile hotspot.
  4. A request with and without the VPN or corporate proxy.

Chrome’s connection troubleshooting guidance lists unstable connections, VPNs, outdated browsers, and security software as possible causes. These tests identify scope; they do not prove which product is responsible. If only one network fails, contact its administrator with the exact hostname and error. If every environment fails, investigate the image host, DNS, certificate, or firewall.

10. A repeatable debugging checklist

  • Copy the final image URL from the rendered page.
  • Open it directly and record the HTTP status and content type.
  • Inspect Console and Network messages after a hard reload.
  • Check HTTPS on the document, every redirect, and the image.
  • Check CSP img-src for the image origin.
  • Decide whether you only display the image or need JavaScript/canvas access.
  • For CORS use, configure the remote server’s response headers.
  • Check authentication, signed URL expiry, hotlink rules, and cookies.
  • Check lazy-loading attributes and computed CSS dimensions.
  • Compare browser, extension, VPN, security software, and network conditions.
  • Retest with a known-good image from the same page and the same browser.

11. Or skip the browser setup

If your goal is to capture a page for documentation, monitoring, testing, or an AI workflow, ScreenshotNeo can return a clean screenshot or PDF from one GET request. It accepts the cookie or consent banner like a visitor, removes more than 60 known consent platforms, newsletter popups, and chat widgets, and lets you turn each step off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing; the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

A capture service can remove obstructive overlays before producing the image.
A capture service can remove obstructive overlays before producing the image.

See the ScreenshotNeo API documentation for all options. A minimal request is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The API also supports full-page capture with lazy images loaded, CSS element capture, device presets or custom viewports, dark mode, retina scale, PDF paper and page-range settings, custom CSS and JavaScript, clicks, selector or network-idle waits, blocked requests and resource types, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage data, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which simplifies migration.

There are 1,000 free screenshots each month with no card. Paid plans start at $5 for 3,000 screenshots; yearly billing gives two months free, and every feature is included on every plan. Create your free ScreenshotNeo account.

12. Performance, reliability, and cost considerations

Browser-side loading

Every external image adds a DNS lookup, connection, TLS negotiation, transfer, and possible redirect. Use a nearby HTTPS CDN, modern formats, explicit dimensions, and responsive sources. Lazy-load below-the-fold images, but make the primary content available without waiting for unnecessary scripts. Cache immutable assets with versioned filenames.

Reliable diagnostics

Log the final URL, status, content type, and console error in development. Monitor image hosts separately from application code. A retry can help a transient connection failure, but repeated retries do not fix a 404, CSP violation, expired signature, or deliberate 403. Keep an accessible fallback and meaningful alt text.

Capture cost

If you use a screenshot service, avoid recapturing unchanged pages: choose a cache TTL, use asynchronous jobs for slow pages, and batch independent URLs where supported. ScreenshotNeo bills only clean shots and reports billing and page verdict headers, so your application can distinguish a usable capture from a failed or unbillable result before storing it.

FAQ

Does CORS block a normal image tag?

Usually no. CORS matters when script or canvas code needs to read the cross-origin response or pixels. A blank image should first be checked for URL, HTTP, mixed-content, CSP, and network errors.

Why does the image work when I paste its URL into a tab?

The direct navigation may use a different referrer, cookies, policy context, or redirect path. Compare the failing request’s headers and response in Network rather than relying on the direct-tab result.

Can I fix a CSP or CORS error from frontend JavaScript?

No. CSP is controlled by the page owner, and CORS permission is returned by the resource server. Change the relevant server configuration or use an architecture designed to proxy the resource.

Why is the Network panel empty?

The image may be lazy-loaded, generated by JavaScript later, served from cache, or hidden by CSS. Preserve the log, disable cache while DevTools is open, scroll the element into view, and reload.

What should I do when the cause is still unclear?

Capture the exact URL, browser version, document scheme, Console message, request status, redirect chain, and response headers. That evidence narrows the problem far faster than changing several settings at once.