Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsIf images appear in your browser but vanish from the PDF, the converter is usually rendering a different CSS media mode, failing to fetch the image, blocking local files, or printing before dynamic content is ready. Start by identifying whether the missing visual is an <img>, SVG, or CSS background, then inspect the renderer’s logs and resolved URLs. The fix depends on the engine and version—not on adding an arbitrary delay.
First identify what kind of image is missing
Do not troubleshoot every visual as an image request. These cases follow different paths:
- Raster or SVG in
<img src="…">: the renderer must resolve the URL, make the request, and decode the response. - Inline SVG: CSS, fonts, external references, and renderer SVG support can affect output.
- CSS background: the image is part of painted styling, so a PDF option that suppresses backgrounds can remove it even when the URL loaded successfully.
- JavaScript-created or lazy-loaded image: the final
srcmay not exist when printing begins.
Ask which converter and version you use, whether the item is an image element or background, and what warning, request failure, or HTTP status appears in the converter output.
Why the browser view and PDF differ
Print CSS may hide the image
Puppeteer’s Page.pdf() uses the print media type by default. An @media print rule can set an image or its parent to display:none, change visibility, replace content, or alter dimensions. Inspect computed styles while emulating print media. If the PDF should match the screen layout, explicitly select screen media before printing:
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →#1 Best Overall
await page.emulateMediaType('screen');
await page.pdf({path: 'output.pdf', printBackground: true});
Use this deliberately: print layouts often remove navigation, resize columns, and change colors for paper.
Backgrounds are disabled separately
Puppeteer’s printBackground option defaults to false. Enable it for CSS background graphics:
await page.pdf({path: 'output.pdf', printBackground: true});
This does not repair a failed <img src> request. If an image element is broken, investigate its URL, credentials, response, and load state instead.
A renderer-specific diagnostic workflow
- Record the engine and version. Document whether you use Puppeteer/Chromium, wkhtmltopdf, WeasyPrint, or another converter. Options and defaults vary.
- Save the exact HTML sent to the converter. Open that artifact, not your development template, and check every image’s final
src,srcset, inline style, and base URL. - Inspect print-media CSS. Search for
@media print,display:none,visibility:hidden, zero dimensions, clipping, and rules that remove backgrounds. - Resolve every URL from the converter’s environment. A relative URL depends on the document base. A path that exists on your laptop may not exist in a container or job runner. Test the URL from the same process, network, user, proxy, and certificate context.
- Check access requirements. Private images may require cookies, authorization headers, a referer, or a permitted outbound route. Local files require readable paths and renderer-specific permissions.
- Wait for the application’s completion condition. For dynamic pages, wait until the final
srcvalues are assigned and images reportcomplete(and, where relevant, a nonzero natural width). Then print. - Read renderer diagnostics. Capture request failures, HTTP statuses, console errors, warnings, and media-load errors. Validate the resulting PDF rather than assuming that navigation completed successfully.
Puppeteer: a complete, safer baseline
Puppeteer’s PDF guide demonstrates navigation with waitUntil: 'networkidle2'; its PDF options also wait for fonts by default. Network idle is not proof that lazy images or application work is complete, so add an application-specific condition.
Rank #2
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
page.on('requestfailed', r => console.error('request failed', r.url(), r.failure()));
page.on('response', r => {
if (r.status() >= 400) console.error('HTTP', r.status(), r.url());
});
await page.goto('https://example.com/report', {waitUntil: 'networkidle2'});
await page.waitForFunction(() => [...document.images].every(img => img.complete));
await page.emulateMediaType('screen'); // omit when print CSS is intended
await page.pdf({
path: 'report.pdf',
format: 'A4',
printBackground: true,
preferCSSPageSize: true
});
await browser.close();
For authenticated pages, set cookies or headers before navigation. For a local HTML file, use a deliberate base URL or absolute file:// paths and confirm the process can read them. Do not enable broad filesystem access merely to make one asset work.
wkhtmltopdf: verify flags and local-file policy
wkhtmltopdf documents image loading as enabled by default and provides --no-images to disable it. Confirm that your wrapper has not added that flag. JavaScript can be disabled, and JavaScript-driven pages can require a configured --javascript-delay; use a delay as a diagnostic renderer setting, not as evidence that resources loaded. The tool also exposes media-load error handling.
wkhtmltopdf
--enable-javascript
--javascript-delay 1000
--load-media-error-handling skip
input.html output.pdf
Local-file access is separately controlled. The usage documentation describes local-file restrictions and flags for enabling or disabling access; verify the exact behavior of your installed version before changing it. Prefer narrowly scoped, readable asset directories. Broad local access can expose files when HTML or CSS is untrusted.
WeasyPrint: URL fetchers and warnings matter
WeasyPrint fetches external images and stylesheets through a URL fetcher. Its documentation describes custom fetchers for framework static or media files, authentication, and other integrations. Many fetch errors are caught and emitted as warnings, so a PDF that opens successfully can still be missing images.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #3
- hole punched
- high quality card stock
- 4 pages
- made in USA
- keyboard shortcuts
from weasyprint import HTML
def fetch_url(url):
# Implement your application’s controlled authentication and allow-list here.
# Return a WeasyPrint-compatible response for approved URLs.
raise NotImplementedError
HTML('https://example.com/report').write_pdf('report.pdf')
In production, configure logging, inspect warnings, and ensure the fetcher returns the correct MIME type and bytes. WeasyPrint’s stable API documentation (version 70.0) covers supported raster and SVG image elements, local files, and URL-fetcher behavior. Restrict filesystem access when processing untrusted HTML/CSS.
Common symptoms and targeted fixes
| Symptom | Likely branch to test | Fix or evidence |
|---|---|---|
| Only PDF is missing images | Print CSS or background suppression | Inspect print computed styles; choose screen emulation or enable background printing. |
| Works locally, fails in a container | URL base, DNS, proxy, certificate, credentials, or file permissions | Fetch the exact resolved URL from the converter process and compare status and bytes. |
| Only private images fail | Missing cookies, authorization, or referer | Pass controlled credentials or use an authenticated fetcher; avoid embedding secrets in public HTML. |
| Intermittent JavaScript images | Printing before final DOM state | Wait for the app’s completion signal and inspect each image’s complete, naturalWidth, and error state. |
| Background disappears, foreground image remains | Background printing disabled | Set the renderer’s background option; do not rewrite working <img> tags. |
| PDF has a broken-image icon or blank box | Decode failure, unsupported format, or non-2xx response | Log response headers and bytes; test a known-good PNG/JPEG and check SVG support. |
Reliability, performance, and security
- Prefer absolute, stable URLs or a documented base URL for generated documents.
- Use a resource allow-list, bounded timeouts, and request logging. Never grant unrestricted local-file access to untrusted HTML.
- Cache immutable images where appropriate, but invalidate cached failures and include versioned asset URLs.
- Keep image dimensions explicit to reduce layout shifts; still wait for actual resources before printing.
- Validate PDFs in automated jobs by checking page count and expected image presence, not just process exit status.
- Choose an error policy deliberately: fail the job when a required image is absent, or record a warning when it is optional.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One request returns a PNG, JPEG, WebP, or PDF, while it accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
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)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the ScreenshotNeo documentation for options such as full-page capture, CSS selectors, dark mode, device presets, retina scale, PDF paper and page ranges, custom CSS/JavaScript, waits, request blocking, headers, cookies, geolocation, caching, signed links, asynchronous webhooks, bulk capture, and usage reporting. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Will adding a longer delay fix missing images?
Not necessarily. A delay cannot repair a 404, blocked request, wrong base URL, or denied file. Use logs and an explicit readiness condition first.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Should I convert every image to base64?
Only when your security and document-size constraints justify it. Base64 can bypass URL fetching, but it increases HTML size and does not solve print CSS or unsupported formats.
Rank #4
Which renderer is universally best?
None is established by the documented behavior alone. Compare print-media rules, background defaults, resource access, and visibility of load failures for your workload.
Frequently Asked Questions
How can I tell whether a missing visual is a CSS background?
Inspect the element’s computed styles and markup. If the URL is in background-image rather than an img or SVG element, test background-printing settings separately.
Why does a PDF open normally even though an image is absent?
Several renderers tolerate resource failures and continue. Warnings, request logs, and response statuses are more reliable than the PDF process exit code.
The Bottom Line
Fix missing HTML-to-PDF images by tracing the renderer’s actual inputs: print CSS, image type, resolved URL, access permissions, readiness state, and warnings. Apply the engine-specific setting only after that diagnosis.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

