ScreenshotNeo

BlogHow-to

How to Fix an Image That Is Not Showing in HTML

Fix broken HTML images by checking the element, resolved URL, server response, format, CORS settings, and accessible fallback text.

By the ScreenshotNeo team1 October 20267 min read

An HTML image usually fails for one of five reasons: the src or srcset is empty or wrong, the URL resolves to the wrong location, the deployed server returns an error or non-image response, the file is unsupported or corrupted, or browser security rules block the request. Check those in that order.

The browser resolves a relative URL from the HTML document’s URL. Open that resolved URL directly, then inspect the page request in DevTools. A 404 points to a path or deployment problem; a 403 often means access control; a redirect or HTML response means the URL is not returning the image; a decoding or MIME error points to file data or format; and a CORS message points to cross-origin configuration.

1. Start with valid image markup

The HTML Standard recommends an img element with a src when there is one image resource. MDN describes <img> as the element that embeds an image in the document. WHATWG HTML Standard · MDN img reference

<!-- Image in the same directory as the HTML file -->
<img src="photo.jpg" alt="A mountain lake at sunrise">

<!-- Image in an images/ directory below the HTML file -->
<img src="images/photo.jpg" alt="A mountain lake at sunrise">

<!-- Root-relative path on the same site -->
<img src="/images/photo.jpg" alt="A mountain lake at sunrise">

Keep alt text concise and meaningful. Use alt="" only for decorative images. Alt text is a fallback for users who cannot process images; it does not repair a failed request.

2. Resolve the path from the document URL

Relative paths are based on the document location, not necessarily the project root. If the page is https://example.com/blog/post.html, then images/photo.jpg resolves to https://example.com/blog/images/photo.jpg. A leading slash starts at the site’s root.

Markup Document URL Resolved request
photo.jpg /docs/index.html /docs/photo.jpg
images/photo.jpg /docs/index.html /docs/images/photo.jpg
/images/photo.jpg any page on the same host /images/photo.jpg
  • Match spelling, capitalization, hyphens, underscores, and the extension exactly. Linux hosts commonly treat Photo.jpg and photo.jpg as different files.
  • Count directory levels carefully. From /products/detail/index.html, use ../../images/photo.jpg to reach a root-level images directory.
  • Check a <base href="..."> element. It changes how relative image URLs resolve.
  • Prefer root-relative or absolute URLs when pages are served from many nested routes.

3. Verify the deployed response in DevTools

  1. Copy the URL the browser should request and open it in a new tab.
  2. Open DevTools, select Network, reload the page, and filter by Img.
  3. Inspect status, final URL after redirects, response headers, and response body.
  4. Confirm the response is the image itself, not an HTML error page, login page, or redirect loop.
Evidence Likely cause Fix
404 Wrong path or file not deployed Correct the URL or deploy the asset at that exact path.
403 Permission or access rule Allow the page to fetch the asset or adjust server permissions.
200 with HTML Rewrite, login page, or error handler returned markup Fix routing and make the image path return image bytes.
Redirect to another host Moved asset or authentication flow Use the final public asset URL and verify access.
Decode, MIME, or dimension error Unsupported format or corrupt bytes Replace or convert the file after confirming the request is correct.
CORS error Cross-origin permission missing Configure the image server’s Access-Control-Allow-Origin response or serve from an allowed origin.

4. Check format and file integrity

A successful HTTP status does not guarantee that the browser can decode the body. Confirm that the file is a real image, has not been truncated, and uses a browser-supported format. If the response begins with an HTML document or JSON error, repair the server route. Convert or replace the asset only after the URL and response have been verified.

<!-- Keep the extension and content type consistent -->
<img src="/images/hero.webp" alt="Product dashboard">

When using srcset, make sure every candidate URL exists and that the descriptor syntax is valid:

<img
  src="/images/hero-800.jpg"
  srcset="/images/hero-400.jpg 400w, /images/hero-800.jpg 800w, /images/hero-1600.jpg 1600w"
  sizes="(max-width: 800px) 100vw, 800px"
  alt="Product dashboard">

5. Check cross-origin and security settings

For a normal visual image, hosting it on the same origin is the simplest setup. If you add crossorigin, the remote server must explicitly allow the requesting origin with Access-Control-Allow-Origin. Read the Console error and inspect response headers before changing markup. Configure the asset server or move the file to an allowed origin.

<!-- Only use crossorigin when the server is configured for it -->
<img src="https://cdn.example.com/photo.jpg"
     crossorigin="anonymous"
     alt="A mountain lake at sunrise">

6. Rule out CSS and loading behavior

  • Inspect the element’s computed styles for display: none, visibility: hidden, zero dimensions, clipping, or an opaque overlay.
  • Remove loading="lazy" temporarily while debugging an image below the fold.
  • Check that a framework component actually emits an img element and a non-empty URL.
  • Look for JavaScript that clears src, replaces the node, or sets a malformed srcset.
  • Test without service-worker or cache interference in DevTools’ disabled-cache mode.

7. A repeatable debugging checklist

  1. Inspect the rendered element, not only the template source.
  2. Confirm src is non-empty, or that srcset contains valid candidates.
  3. Resolve the URL against the page’s actual address.
  4. Open the resolved URL directly.
  5. Inspect the Network request, final URL, status, and response type.
  6. Confirm the bytes are a supported, intact image.
  7. Read Console messages for CORS, decoding, or policy failures.
  8. Check CSS, lazy loading, service workers, and scripts.
  9. Retest the deployed URL, including its capitalization and nested route.

8. Common edge cases

The image works when opened directly but not in the page

Compare the direct URL with the URL in the Network panel. They may differ because of relative-path resolution, a <base> element, redirects, cookies, referrer rules, or cross-origin headers.

Alt text appears instead of the image

The request failed or the image could not be decoded. Keep the alt text, then fix the request or file. Alt text is not an image placeholder that can make broken data render.

It works locally but fails after deployment

Check the deployed directory, case-sensitive names, build output, public/static configuration, and the production URL in Network. A local filesystem path may not exist on the web server.

A CDN image fails intermittently

Inspect the final response for redirects, expired access, inconsistent content, or a non-image error response. Compare a failing request and a working request rather than changing the HTML blindly.

9. Performance and reliability

  • Use appropriately sized files and srcset candidates so the browser does not download a needlessly large asset.
  • Keep important images available at stable, cacheable URLs and avoid changing filenames without updating references.
  • Use lazy loading for below-the-fold images, but remove it temporarily when diagnosing visibility or loading timing.
  • Serve images from the same origin for the simplest security and deployment model. A CDN is an advanced delivery option; verify that it preserves the image response and required headers.
  • Test the production URL from the same page route where users see the failure. A correct development path is not evidence that deployment is correct.

10. Capture a known-good reference image

If you need a rendered reference of a page while investigating a visual issue, ScreenshotNeo can capture a URL as PNG, JPEG, WebP, or PDF. Its request options include full-page capture, waiting for a selector or network idle, custom headers and cookies, and hiding selectors, which can help reproduce the page state you are debugging.

11. Or skip the browser setup

For a screenshot of a deployed page, call ScreenshotNeo’s API directly. See the ScreenshotNeo API documentation for the available options.

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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', buffer));

ScreenshotNeo accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and 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 for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000.

Create a free ScreenshotNeo account and get 1,000 screenshots each month with no card.

12. FAQ

Does alt make a missing image appear?

No. It provides accessible fallback text while you fix the image request or file.

Should I use ./photo.jpg or photo.jpg?

Both normally refer to the current directory. The important point is that the current directory is the HTML document’s URL directory.

Is a 200 status proof that the image is valid?

No. The body can still be HTML, JSON, unsupported data, or corrupted image bytes.

When is CORS relevant?

Check it when the image is cross-origin and you use crossorigin or another operation that requires the server’s permission. Inspect the Console and response headers.

What should I check first in production?

Open the resolved production URL directly, then inspect the page’s Network request and response body. This separates path and deployment faults from markup faults.