ScreenshotNeo

BlogHow-to

Why Images Will Not Load on a Website and How to Fix It

Find the exact reason an image is missing, then fix URLs, server responses, CORS, CSP, mixed content, lazy loading, and responsive sources.

By the ScreenshotNeo team1 October 20267 min read

Start with the browser’s Network panel and Console. Reload the page while DevTools is open, filter requests to images, and inspect the failing URL, status, response, and policy message. A missing request, HTTP error, invalid response, CORS or CSP block, mixed-content warning, and deferred lazy image each require a different fix.

This guide explains how to identify the cause and repair it without guessing. It covers static HTML, responsive images, JavaScript-rendered sources, server responses, security policies, lazy loading, and a repeatable verification checklist.

1. Inspect the failing image request first

  1. Open your browser’s developer tools and select Network.
  2. Enable the image filter, then reload the page.
  3. Select the failed request and record its URL, status, type, initiator, response headers, and Preview or Response content.
  4. Open Console and match any CORS, CSP, mixed-content, decoding, or network error to that request.

DevTools records activity while it is open. Chrome’s Network reference explains the status, type, initiator, filters, and response inspection fields you will use (Chrome DevTools Network features reference).

Evidence Likely cause First action
No image request Empty source, script did not assign it, wrong responsive candidate, or lazy loading never triggered Inspect rendered HTML and the selected source
404 or another HTTP error Wrong path, capitalization, deployment location, origin, or missing file Correct the URL or publish the file at that exact URL
Successful response but broken preview HTML error page, corrupt bytes, or unsupported format returned as the image Inspect the response body and Content-Type
CORS error Cross-origin image request lacks the required server permission Configure the appropriate Access-Control-Allow-Origin response if access is required
CSP blocked img-src or default-src excludes the image origin Allow only the intended origin in the policy
Mixed-content warning or block HTTP image requested by an HTTPS page Use an HTTPS asset URL where available
Request appears after scrolling Intentional lazy loading Check dimensions and intersection; avoid deferring a critical hero

2. Verify the rendered HTML and URL

Inspect the live DOM, not only your template or view source. Confirm that src is nonempty and points to the intended file. Check for accidental values such as null, an empty string, a relative path resolved against the wrong directory, or the current page URL.

<img src="/images/team-photo.webp" alt="Team photo" width="1200" height="800">

Responsive markup can select a different resource from the one you expect:

<picture>
  <source media="(min-width: 900px)" srcset="/images/hero-large.webp">
  <source media="(min-width: 500px)" srcset="/images/hero-medium.webp">
  <img src="/images/hero-small.webp" alt="Product overview" width="800" height="600">
</picture>

Inspect the selected request in Network and verify every srcset candidate and every <source> URL exists. MDN documents empty or null sources, a source equal to the current page URL, corrupt image content, and unsupported formats as image-loading error conditions (MDN: The img element).

3. Open the exact image URL directly

Paste the URL shown in the failing request into a new browser tab. If it fails there too, investigate the file path, deployment, permissions, redirects, origin, and server or CDN response. If it opens directly but fails in the page, return to the Console and request headers: the page may be selecting another responsive candidate or hitting a browser policy.

In Network, inspect the response preview and body. A server can return an HTML error document with a successful-looking transport response, or return image bytes with a misleading Content-Type. Confirm that the body is the actual image and that the format is supported by the target browsers.

4. Fix common URL and deployment mistakes

  • Check capitalization: paths can be case-sensitive on production Linux servers.
  • Resolve relative URLs from the document URL, not from the source file’s directory.
  • Verify the asset was included in the build output and deployed to the same origin or intended CDN.
  • Follow redirects and confirm the final host serves the asset.
  • Check filename encoding when spaces, Unicode, or reserved characters are present.
  • Remove stale service-worker or CDN cache entries after publishing a corrected file.

Keep the URL in the rendered DOM easy to inspect. If JavaScript reads a data attribute and assigns img.src, log the final value and inspect it after hydration.

5. Check HTTPS, CSP, and CORS

Mixed content

If the document is HTTPS, use the HTTPS version of the image URL when the origin supports it. Browsers can upgrade some insecure image requests and block others, depending on the request and browser handling. Read the exact Console message before changing code (MDN: Mixed content).

Content Security Policy

When Console or Network reports a policy violation, inspect the response’s Content-Security-Policy header. The img-src directive lists permitted image sources. If img-src is absent, default-src can govern image requests. Add only the required origin:

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

Do not solve one broken image by allowing every source. See MDN: Content Security Policy.

Cross-origin images and CORS

CORS is distinct from ordinary image display. If your page uses crossorigin, the image server must opt in with an appropriate Access-Control-Allow-Origin value for your site’s origin. Configure the response on the image origin only when your use case requires cross-origin access, such as reading pixels from a canvas.

<img src="https://cdn.example.com/photo.jpg" crossorigin="anonymous" alt="Example">

Match the server change to the reported error and use case; changing CORS headers cannot repair a 404 or corrupt file.

6. Check lazy loading and layout dimensions

An offscreen image with loading="lazy" is intentionally deferred until it approaches the viewport. Scroll it into view while watching Network. Give it stable dimensions so the browser can calculate layout and intersection:

<img src="/images/article.webp" loading="lazy" width="1200" height="800" alt="Article illustration">

MDN warns that a lazy image with zero dimensions may never load if it does not intersect a visible element. Do not unnecessarily lazy-load an above-the-fold hero; responsive-image guidance also recommends eager loading for important initial content (web.dev image guidance).

7. Repair JavaScript-rendered images

For client-rendered pages, check the sequence that assigns the source:

const image = document.querySelector('#avatar');
const url = user?.avatarUrl;
if (url) {
  image.src = url;
} else {
  image.removeAttribute('src');
}

Watch for code that assigns undefined, an empty string, or a URL before configuration has loaded. Add an error handler during diagnosis:

image.addEventListener('error', event => {
  console.error('Image failed', event.currentTarget.currentSrc || event.currentTarget.src);
});

8. Verification checklist

  • The rendered src or selected srcset URL is nonempty and exact.
  • The URL works directly and returns the intended image bytes.
  • The response has a suitable image Content-Type and supported format.
  • No 4xx/5xx, redirect loop, CORS, CSP, or mixed-content error remains.
  • Lazy images have dimensions and load when scrolled into view.
  • Critical visible images are not unnecessarily deferred.
  • Cache and service-worker layers have been refreshed after deployment.

9. Capture a page while diagnosing it

A screenshot can show whether an image is missing only in a specific viewport, after JavaScript runs, or below a lazy-loading threshold. For repeatable captures, record the URL, viewport, wait condition, and timestamp alongside the image.

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server. One GET request captures a clean PNG, JPEG, WebP, or PDF. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing result.

See the ScreenshotNeo API documentation for all options, including full-page capture with lazy images loaded, CSS-selector element capture, device presets, custom CSS and JavaScript, waits, blocked resources, headers, cookies, user agents, timezone, geolocation, caching, signed links, async jobs, bulk capture, and usage reporting.

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 MCP server includes take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000. Create your free ScreenshotNeo account.

Performance, reliability, and cost notes

  • Give images explicit dimensions to reduce layout shifts and help lazy-loading intersection.
  • Use responsive candidates that match real viewport sizes; a broken high-resolution candidate can affect only some devices.
  • Cache stable assets at the CDN, but purge or version URLs when bytes change.
  • Measure the actual request and decode time in Network before compressing or changing formats.
  • When automating screenshots, wait for a selector, a delay, or network idle so JavaScript and lazy images have completed.
  • ScreenshotNeo lets you choose a cache TTL; cache hits are reported and are not billed.

FAQ

Why does an image work in a new tab but not on my page?

The page may select another srcset candidate, be blocked by CSP or mixed content, or request the image with cross-origin settings. Inspect the exact request from the page.

Does changing the file extension fix a broken image?

No. The response must contain valid image data in a browser-supported format, with a correct server response. Renaming corrupt bytes does not convert them.

Should every image use lazy loading?

No. Lazy loading suits offscreen content. Keep important above-the-fold images available immediately and provide dimensions for deferred images.

Can CORS headers fix a 404?

No. CORS controls permitted cross-origin access. A 404 still requires the requested file and path to be fixed.