Images not showing in an HTML file
On your machine the report is fine. Sent to someone else — attached to an email, dropped in Slack, uploaded to a server — every chart is a broken-image icon and the alt text is showing where the pictures were.
The HTML is intact. The images just never came with it.
Find the cause in 30 seconds
Open the page where it is broken, right-click a broken image and choose Open image in new tab (or check DevTools → Network, filter Img). The URL it tried tells you which of these it is:
| The failed URL looks like | Cause |
|---|---|
file:///…/Downloads/img/chart.png |
Relative file that was never sent |
file:///C:/Users/you/project/… |
Absolute path to your disk |
file:///images/logo.png |
Root-relative path opened from disk |
https://site/img/Chart.PNG → 404 |
Case mismatch on a Linux server |
https://bucket.s3…?X-Amz-Expires=… → 403 |
Signed URL that has expired |
http://… on an https:// page, blocked |
Mixed content |
http://localhost:… |
Only exists on the machine that made it |
1. The images are separate files, and only the HTML travelled
By far the most common. Notebook exports, test reporters, coverage tools and coding agents write the page and a folder of images:
report/
index.html ← you sent this
img/
latency.png ← not this
errors.png ← or this
<img src="img/latency.png"> is a pointer to a neighbour. The
recipient's copy has no neighbours.
Fixes, from quickest to sturdiest:
- Embed the images in the file. Drop the whole folder into the
HTML inliner and download one
.htmlwith every image, stylesheet and font inside it. For a single picture, the image to Base64 converter gives you thedata:URI to paste in. - Send the folder as a zip. Works, but the recipient has to unzip
it, keep the structure intact, and open the right file — and mail
filters often strip zips containing
.html. - Send a link instead of a file. Publish the folder and every relative path keeps resolving, because the assets are hosted next to the page.
2. An absolute path to your own disk
<img src="C:\Users\dana\project\out\chart.png" />
<img src="file:///Users/dana/project/out/chart.png" />
Some tools and copy-pastes write the full local path. It works for
exactly one person. Replace it with a path relative to the HTML file
(out/chart.png), then apply fix #1. Backslashes are a Windows-ism —
use forward slashes in src, even on Windows.
3. A root-relative path, opened from disk
<img src="/static/logo.png" />
The leading / means the root of the site. Behind a web server that
works. Double-clicked from a folder, the page is on file://, and the
root is your drive — so the browser looks for /static/logo.png on
the filesystem. Drop the leading slash, or open the folder through a
local server rather than by double-clicking.
4. Letter case on a Linux server
Chart.PNG and chart.png are the same file on Windows and on macOS's
default filesystem. On Linux, on S3 and on most static hosts they are
two different names, and only one exists. Everything works locally,
then 404s on deploy. Rename the files or the src so the case matches
exactly — extension included.
5. An expired or private URL
The image is hosted, but behind a pre-signed link (X-Amz-Expires,
se= on Azure, Expires= on GCS) that was valid for an hour when the
report was generated. A week later it returns 403. The same happens
with images in a private bucket, a logged-in dashboard, or a Google
Drive "anyone with the link" file that isn't actually an image URL.
Either embed the image so it never depends on that URL again, or host it somewhere public and stable.
6. http:// images on an https:// page
Browsers upgrade or block plain-HTTP images on secure pages — see
mixed content blocked. And
anything on localhost was only ever reachable from the machine that
generated it; see the localhost link doesn't work for
others.
Embed or host?
| Embed (data URI) | Host next to the page | |
|---|---|---|
| Works as an attachment | Yes | No — needs a link |
| File size | ~33% bigger per image | Unchanged |
| Caching | Re-downloaded every visit | Each image cached separately |
| Good for | Charts, icons, a logo | Photos, many large images |
For a report with a handful of charts, embedding is the right call — the file stops being fragile. Past a few megabytes of images, a link is kinder to everyone's inbox; see HTML file too big to email.
Or send a link, not a file
Publish the report folder to Comma and send one URL. The images, stylesheets and scripts are uploaded alongside the page, so nothing goes missing; readers comment on the exact chart they mean; and a re-run replaces it as a new revision at the same link. Lock it to a password, an invite list or your email domain when it isn't public.
Try it
Related
- HTML inliner — pack a page and its CSS, JS, images and fonts into one file
- Image to Base64 — one image to a data URI
- HTML report lost its CSS
- Share an HTML folder
- The HTML file is too big to email
- All report troubleshooting