If a Base64 image disappears from a Puppeteer PDF header, first prove that the final headerTemplate contains a valid, correctly prefixed data URI. Then reduce the PDF call to one image, record both the Puppeteer package and the Chrome executable versions, and compare browsers. A 2025 Puppeteer report saw a JPEG header work in 24.3.0 and fail from 24.4.0 onward, while a maintainer reproduced the failure in stable Chrome and said it seemed fixed in Canary. No stable Chrome release is identified as containing that fix, so do not assume that upgrading to a particular version will solve every case.
What is actually failing?
Puppeteer prints a header only when displayHeaderFooter is enabled. In the documented PDFOptions interface (page marked version 25.12.0 when accessed), headerTemplate is an HTML string, and the built-in placeholder classes include date, title, url, pageNumber and totalPages. The default for displayHeaderFooter is false.
A header template is a separate, restricted print fragment. Treat it as self-contained HTML: use a literal src, inline styles and enough top margin. Do not assume that page CSS, page JavaScript or the page’s resource context is inherited. A historical issue records a script in a header/footer template not running in its reproduction (issue #2167), and another records a relative image path rendering as a gray outline (issue #2443). Those reports are warnings about isolation, not proof that every relative URL fails or that Base64 always succeeds.
Start by inspecting the generated header
Log the exact final string
Inspect the string after all templating has run, not the source variable that was supposed to become an image. Redact secrets before writing it to a log. Look for an unreplaced token such as {{logo}}, a missing value, a second prefix, a quote inserted into the payload, or a line break in the encoded data.
#1 Best Overall
console.log(headerTemplate.replace(/base64,[^"']+/i, 'base64,[redacted]'));
Check the data-URI contract
- PNG data must begin with
data:image/png;base64,. - JPEG data must begin with
data:image/jpeg;base64,(or the MIME type your encoder actually produced). - Put the MIME prefix exactly once. If
pngBase64already contains a complete data URI, do not prepend another one. - Keep the payload variable to encoded bytes when the template supplies the prefix.
- Do not insert whitespace, a newline, or an unintended quote into the Base64 payload.
These checks identify malformed output; the issue reports do not establish that one particular formatting mistake is the cause in every failure.
Validate the image outside Puppeteer
A Base64-shaped string can still decode to invalid bytes. Decode the payload independently and open the resulting file. This also catches a variable that contains an HTML error page, a truncated read, or a URI prefix that was accidentally included in the bytes.
import fs from 'node:fs';
const dataUri = `data:image/png;base64,${pngBase64}`;
const match = dataUri.match(/^data:([^;]+);base64,(.+)$/s);
if (!match) throw new Error('Not a single, complete Base64 data URI');
fs.writeFileSync('debug-header.png', Buffer.from(match[2], 'base64'));
Open debug-header.png with an image viewer. If it cannot be opened, fix the source bytes before investigating PDF rendering.
Build a minimal PDF reproduction
Remove your application layout, framework CSS and dynamic header generation. Keep one page, one image and the actual data URI. Set a top margin large enough that the header is inside the printable area.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #2
import puppeteer from 'puppeteer';
const pngBase64 = '...'; // valid PNG bytes, Base64 encoded; no data URI prefix
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent('<main>Minimal PDF reproduction</main>', {
waitUntil: 'load'
});
const pdf = await page.pdf({
displayHeaderFooter: true,
headerTemplate: `
<div style="width:100%; margin:0; padding:0;">
<img
src="data:image/png;base64,${pngBase64}"
style="display:block; width:110px; height:auto;"
alt="Company logo"
/>
</div>
`,
footerTemplate: '<span class="pageNumber"></span> / <span class="totalPages"></span>',
margin: { top: '1in', bottom: '0.5in' }
});
await browser.close();
This is a diagnostic pattern, not a guaranteed workaround for the reported regression. Change the MIME type, dimensions and margins to match your asset and document. If this exact image still fails, the small reproduction gives you something that can be compared across browser versions.
Record both versions, not just “Puppeteer”
Puppeteer’s npm version and the Chrome/Chromium executable it launches are different variables. Record both in the failing environment and the working one.
npm list puppeteer
node --version
const browser = await puppeteer.launch();
console.log('browser:', await browser.version());
console.log('executable:', browser.process()?.spawnargs?.[0]);
The report in Puppeteer issue #13726 describes Node 22.14.0, npm 10.9.2 and Windows; its author said the Base64 JPEG worked with Puppeteer 24.3.0 and failed beginning with 24.4.0. That is an individual 2025 report, not a universal compatibility rule.
Compare a controlled browser change
Once the minimal case is valid, run it against another executable while keeping the template, image bytes, options, operating system and runtime unchanged. In the same issue discussion, Puppeteer collaborator OrKoN wrote on 2025-04-04 that they could reproduce “Printing failed” with current stable Chrome and that it “seems to be fixed with canary” (comment). The comment does not name the Canary build or a stable release containing the correction.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Use Canary as an investigative comparison, not as a confirmed production fix. Before changing production, verify the exact executable and rerun the minimal PDF in your deployment environment. The available reports do not establish whether the behavior persists in every current browser build.
Keep header markup self-contained
- Use inline CSS for display, width and height.
- Use a literal image
srcin the final template. - Reserve vertical space with
margin.top; otherwise a valid header can be clipped. - Do not depend on a page stylesheet, a script in the template, or a page-side transformation to create the image.
- Keep the header simple while diagnosing. Add other markup only after the image works.
The API documents the template as HTML and documents placeholder classes, but it does not promise that the template executes JavaScript or inherits the main document’s resource context (Puppeteer PDFOptions).
Use a comparison record to isolate the variable
| Variable | What to record | Why it matters |
|---|---|---|
| Puppeteer | Exact package version, such as 24.3.0 or 24.4.0 | The 2025 report places its change in this comparison. |
| Browser | Actual Chrome/Chromium executable and version | Puppeteer can launch a browser different from the one you expected; the maintainer reproduced a stable-versus-Canary difference. |
| Image | PNG or JPEG, decoded bytes, MIME prefix | Confirms that the same valid asset is used in every run. |
| Template | Exact final HTML after substitution | Separates templating errors from print rendering. |
| Runtime | Node version, operating system and launch arguments | The issue report identifies Windows and Node 22.14.0; do not generalize that result to Linux or macOS. |
| PDF options | displayHeaderFooter, margins and both templates |
A missing flag or insufficient margin can look like a missing image. |
Troubleshooting by symptom
The header is completely absent
Confirm displayHeaderFooter: true and a nonzero top margin. Check that the PDF call actually receives the template you logged; a conditional branch may be passing an empty string.
Text appears, but the image is missing
Decode the payload, verify one MIME prefix, and compare the final src with the standalone file. Then run the minimal reproduction. If the minimal image fails only with one browser executable, treat it as a version/environment investigation rather than a CSS problem.
Recommended Free Tools
Rank #4
A gray outline or broken-image icon appears
Inspect for a relative path such as /public/images/logo.png. A 2018 report recorded that kind of result, but it does not prove that all relative paths fail. Replace it temporarily with a validated literal data URI and compare.
The image is clipped or overlaps the page
Increase margin.top, reduce the image height, and keep the wrapper’s margin and padding explicit. Header space is outside the page body; a valid image can be present but outside the printable region.
It works locally but fails in deployment
Print the executable path and browser version in both environments, save the final template, compare decoded image hashes, and compare Node, operating system and PDF options. Do not compare only the Puppeteer package number.
Changing to a newer stable release did not help
There is no documented stable release in the cited discussion that guarantees a fix. Re-run the minimal case, test a controlled alternate executable, and preserve the failing combination for an issue report. Avoid claiming that Canary or any current stable build is universally corrected.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchBest Value
- Used Book in Good Condition
Performance and reliability considerations
Inlining a small logo avoids a separate resource lookup in the header, but it does not remove the need to validate bytes or leave print space. Keep the diagnostic asset small, create one minimal page, and avoid unrelated network requests while comparing browsers. For production, pin and record the browser executable used by your deployment, retain a representative PDF fixture, and rerun that fixture when upgrading Puppeteer or Chrome. A passing result on one operating system is not evidence for every other platform.
Or skip the browser setup
If you need a clean image of a URL rather than a custom Puppeteer PDF header, ScreenshotNeo provides a website screenshot API and MCP server. It accepts one GET request and returns PNG, JPEG, WebP or PDF. Before capture it accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Bot checks or 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 tools—take_screenshot, get_page_info and capture_pdf—work with Claude, Cursor and other MCP clients.
For a direct request, see the ScreenshotNeo API documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is included on every plan. If that fits your workflow, sign up free.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsWhat to report when opening an issue
- The smallest HTML body and the exact final header template, with the Base64 payload redacted if necessary.
- The image format, MIME prefix and a separately validated sample asset.
- Puppeteer package version, Node version, operating system, executable path and browser version.
- The complete
page.pdf()options, including margins and whether a footer is present. - Which combinations pass or fail, especially the 24.3.0/24.4.0 comparison if it reproduces.
This information lets maintainers distinguish malformed data, template isolation, margin problems and an upstream browser regression without guessing.
Frequently Asked Questions
Do Puppeteer header placeholders work inside an image’s Base64 string?
No. Placeholders such as pageNumber and totalPages are documented HTML classes for print fields; keep the image data URI literal and separate from those elements.
Should I deploy Chrome Canary to fix this?
Not as a blanket recommendation. Canary was reported as apparently fixed in a dated April 2025 reproduction, but no build or corresponding stable release was identified. Validate your exact minimal case first.
Can I use a relative logo URL instead of Base64?
You can test it, but a historical report showed a relative path producing a gray outline. For isolation, use a validated literal data URI and compare the results.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
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.




