A blank Chart.js PDF usually has one of two causes: the chart was captured before it finished drawing, or the PDF’s print-media layout hides or displaces content. An extra blank page is usually a pagination problem, not proof that Chart.js failed. Diagnose those paths separately: expose a chart-specific readiness signal, verify the canvas has dimensions, then inspect print CSS, page size, margins, overflow and page breaks.
Start by separating the two failures
Chart.js renders to a canvas, and animations are enabled by default. Puppeteer’s page.goto(..., {waitUntil: 'networkidle2'}) reports a network condition; it does not know that Chart.js finished its animation, that an asynchronous data update completed, or that a later chart.update() has settled. Conversely, page.pdf() uses the print CSS media type by default, so a chart that looks correct on screen can be hidden, resized to zero, or moved by print rules.
Treat these as separate questions:
- Missing chart or blank chart area: did the page create a canvas with non-zero dimensions and finish drawing before PDF capture?
- Entire blank page or extra trailing page: do physical dimensions, margins, overflow, or print page-break rules produce an additional page?
A screenshot taken immediately before PDF generation is a useful dividing line. If the screenshot is already blank, fix readiness or chart/layout code. If the screenshot is correct but the PDF is wrong, concentrate on print media and pagination.
Use a chart-specific readiness signal
Signal completion from Chart.js
Initialize a page-level flag before constructing charts, and set it from Chart.js’s documented animation.onComplete callback. For several charts, count completions or expose a function that marks readiness only after every required chart has completed.
#1 Best Overall
- BEST FOR SMALL BUSINESSES – Engineered for extraordinary productivity, the Brother DCP-L2640DW Monochrome (Black & White) 3-in-1 combines laser printer, scanner, copier in one compact footprint and delivers high-quality black & white prints
- FAST PRINTER WITH EFFICIENT SCANNING – Produces documents quickly with print speeds up to 36 ppm(2) and scan speeds up to 23.6/7.9 ipm(3) (black/color). A 50-page auto document feeder(4) allows for convenient, time saving multi-page scanning and copying
- FLEXIBLE CONNECTION OPTIONS – Easily navigate the changing demands of your business with secure multi-device connectivity via built-in dual-band wireless (2.4GHz / 5GHz) and Ethernet. Or connect locally to a single computer via USB interface
- BROTHER MOBILE CONNECT APP – Print, scan, and manage your wireless printer anytime, from almost anywhere from your mobile device. Order Brother Genuine Supplies, track toner usage, and complete more work on-the-go(5)
- CHOOSE BROTHER GENUINE TONER – When it’s time to replace your toner, be sure to choose Brother Genuine TN830 or TN830XL replacement toner. And with Refresh EZ Print Subscription Service, you’ll never worry about running out of toner again and you’ll enjoy savings of up to 50%(6) on Brother Genuine Toner. Get started with Refresh today with a Free Trial(1)
<script>
window.__chartsReady = false;
const chartOptions = {
animation: {
onComplete() {
window.__chartOneReady = true;
if (window.__chartTwoReady) window.__chartsReady = true;
}
}
};
window.__chartOneReady = false;
window.__chartTwoReady = false;
// Construct chart one with chartOptions, then chart two with its callback.
</script>
The exact integration depends on your application. If data arrives later, set the flag after the data-driven chart is created. If code subsequently changes data or calls an animated update, signal readiness after that update as well; the first animation callback must not be treated as permanent readiness.
Wait for the flag in Puppeteer
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/report', {
waitUntil: 'networkidle2'
});
await page.waitForFunction(() => window.__chartsReady === true);
await page.pdf({
path: 'report.pdf',
format: 'A4',
printBackground: true,
waitForFonts: true
});
await browser.close();
})();
Page.pdf() waits for fonts by default in current Puppeteer documentation, but font readiness is not a JavaScript or Chart.js completion guarantee. Keep the explicit chart wait.
Wait for multiple charts robustly
For a known number of charts, increment a counter in each completion callback and set window.__chartsReady when the counter reaches that number. For dynamic dashboards, expose an application-level promise or readiness function that includes data loading, chart construction and the final update. A selector wait such as page.waitForSelector('canvas') proves only that an element exists; it does not prove that it has been painted with the intended data.
When disabling animation is the better PDF path
For a PDF-only rendering mode, disable animation in Chart.js:
Recommended Free Tools
Rank #2
- BEST FOR HOMES & HOME OFFICES – Engineered for consistent, premium print quality, the Brother HL-L2405W Monochrome (Black & White) Laser Printer delivers sharp, crisp prints at an affordable price. Prints one-sided documents at speeds up to 30ppm(2)
- COMPACT, CONNECTED PRINTER – Flexible connection options make this an ideal printer for home use and at-home offices. Securely connect to multiple devices with built-in dual-band wireless (2.4GHz/5GHz) or locally to a single computer via USB interface
- BROTHER MOBILE CONNECT APP – Manage your printer remotely and print from your mobile device anytime, from almost anywhere. Order Brother Genuine Supplies, track toner usage, and complete more work on-the-go(3)
- VERSATILE PAPER HANDLING – Enjoy seamless, reliable everyday printing with the 250-sheet paper tray(4) and a manual feed slot that enables printing on envelopes and specialty pape
- BROTHER IS AT YOUR SIDE – Backed by Brother with a 1-year limited warranty and free online, call, or live chat support for the life of your printer
const options = {
animation: false
};
This removes animation timing as a source of nondeterminism and is also recommended by Chart.js documentation for long render times. It does not remove the need to wait for asynchronous data, chart construction, image loading or a final update. If your application replaces data after the initial page load, wait for that operation explicitly.
| Approach | Reliability | Visual result | Implementation effort |
|---|---|---|---|
| Completion callback | Tracks the actual animation/update lifecycle; must be wired for every chart and later update. | Preserves the configured animation, though the PDF is captured at completion. | Moderate |
| Animation disabled for PDF | Removes animation races, but still requires data and construction readiness. | Immediate final state; no animated transition. | Low to moderate |
| Fixed sleep | Brittle: network latency, data size and chart complexity change the required delay. | Unpredictable. | Low initially, costly to maintain. |
Do not make an arbitrary timeout your primary synchronization mechanism. It can mask a race on a fast machine and still fail in production.
Verify the canvas before creating the PDF
- Open a diagnostic screenshot after your data and chart-ready wait.
- Evaluate the canvas dimensions and its container:
const state = await page.evaluate(() => {
const canvas = document.querySelector('canvas');
const box = canvas?.getBoundingClientRect();
return {
exists: !!canvas,
canvasWidth: canvas?.width || 0,
canvasHeight: canvas?.height || 0,
cssWidth: box?.width || 0,
cssHeight: box?.height || 0
};
});
console.log(state);
All relevant width and height values should be non-zero. A zero-sized parent, a hidden ancestor, an unconstrained responsive canvas, or a print rule that changes dimensions can produce a blank result even though JavaScript ran.
Inspect the intermediate screenshot
await page.screenshot({ path: 'before-pdf.png', fullPage: true });
Compare this image under the same viewport and media settings used for the PDF. It tells you whether the failure begins before conversion and helps distinguish a missing chart from a pagination defect.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
- FAST PRINT SPEEDS: Print up to 19 pages per minute.
- COMPACT DESIGN: Space-saving, compact design fits anywhere in your home, school or small office.
- WIRELESS CONNECTIVITY: Print from almost anywhere in your workspace using your compatible mobile device.
- PAPER CAPACITY: Up to 150 sheets.
- SUSTAINABILITY: Uses less than 2 watts in Energy Saver mode.
Print CSS changes what page.pdf() captures
Check print-only visibility and dimensions
Because PDF generation uses print media, inspect @media print rules for display: none, visibility: hidden, collapsed heights, changed flex/grid behavior and page-break declarations. Ensure the canvas and its container remain visible and have usable physical dimensions.
@media print {
.chart-container {
display: block;
width: 100%;
min-height: 260px;
break-inside: avoid;
}
.chart-container canvas {
display: block;
width: 100% !important;
height: auto !important;
}
}
Use dimensions appropriate to your design; the important diagnostic is that print layout gives the chart a real box rather than assuming screen styles will carry over.
Use screen media deliberately
If the intended PDF should use screen styling, call emulateMediaType('screen') before page.pdf():
await page.emulateMediaType('screen');
await page.pdf({
path: 'screen-styled.pdf',
format: 'A4',
printBackground: true
});
This is a deliberate design choice, not a universal fix. If print styles are required for paper output, keep print media and correct those rules instead.
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 matchRank #4
- BEST FOR HOME OFFICES & SMALL TEAMS – Engineered for consistent, premium print quality, the Brother HL-L2460DW Monochrome (Black & White) Laser Printer produces documents that are clear, crisp, and easy to review and share, all at an affordable price
- COMPACT, CONNECTED, EXCEPTIONALLY EFFICIENT– Connect with built-in dual-band wireless (2.4GHz/5GHz), Ethernet, or to a single computer via USB interface. Prints at speeds up to 36ppm(2), plus automatic duplex printing saves time and reduces paper waste
- BROTHER MOBILE CONNECT APP – Manage your wireless printer remotely and print from your mobile device anytime, from almost anywhere. Order Brother Genuine Supplies, track toner usage, and complete more work on-the-go(3)
- VERSATILE PAPER HANDLING – Tackle high-volume black & white printing with the 250-sheet capacity paper tray.(4) The manual feed slot enables printing on envelopes and specialty paper
- BROTHER IS AT YOUR SIDE – Backed by Brother with a 1-year limited warranty and free online, call, or live chat support for the life of your printer
Backgrounds and color adjustment
printBackground defaults to false. Set it to true when chart backgrounds, colored bands or other background graphics are needed:
await page.pdf({
path: 'report.pdf',
format: 'A4',
printBackground: true
});
This setting cannot render a chart that never completed. Browsers also adjust colors for print by default; use -webkit-print-color-adjust: exact when exact colors are a deliberate requirement, while understanding that printer and browser behavior can still differ.
Fix an extra or wholly blank PDF page
Once the chart itself is confirmed, debug pagination independently. Check:
- the requested paper format or explicit width and height;
- CSS width, height and box-sizing on the document and major containers;
- PDF margins versus CSS margins;
- vertical overflow, min-height and absolutely positioned elements;
break-before,break-after,break-insideand olderpage-break-*rules;- large shadows, transforms or positioned elements extending beyond the page.
Reduce the document to a minimal reproduction containing the chart and surrounding layout. Change one variable at a time: remove a page-break rule, constrain a container, or set an explicit page size. Do not begin by adding arbitrary negative margins or deleting the last PDF page; those workarounds can hide a real overflow defect and break other reports.
Best Value
- FROM AMERICA'S MOST TRUSTED PRINTER BRAND – Perfect for small teams printing professional-quality black & white documents and reports. Perfect for 1-3 people
- WORLD'S SMALLEST LASER IN ITS CLASS – Precision laser printing that fits anywhere
- FAST PRINT SPEEDS – Up to 21 black-and-white pages per minute single-sided
- WIRELESS WITH SELF-RESET – Helps you stay connected
- PRINT FROM ANY DEVICE – Wireless printing from any mobile device, PC or tablet. Works with Microsoft, Mac, AirPrint, Android, Chromebook and more
Historical reports illustrate that pagination can differ in particular layouts and versions: see Puppeteer issue #6704 and pagination discussion in #9228. They are examples, not evidence of one universal current bug or fix.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.A reproducible debugging sequence
- Record Puppeteer, bundled Chrome or Chromium, Chart.js, operating-system and Node.js versions.
- Navigate with
networkidle2or another suitable network condition. - Wait for application data and a chart-specific completion signal.
- Evaluate canvas and container dimensions.
- Capture an intermediate screenshot.
- Compare
printandscreenmedia intentionally. - Set
printBackground: trueonly when backgrounds are part of the design. - For extra pages, inspect physical dimensions, margins, overflow and break rules without changing chart synchronization.
- Retest after every change and keep the smallest reproduction that still fails.
This sequence prevents a blank canvas diagnosis from being confused with an extra-page diagnosis.
Common symptoms, causes and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Canvas exists but is white | PDF captured during animation or before data update. | Use animation.onComplete and wait for the flag, or disable animation while still waiting for data and construction. |
| Canvas width or height is zero | Collapsed parent, hidden print rule or missing layout constraint. | Inspect computed styles and print CSS; give the container usable dimensions. |
| Chart appears in screenshot but not PDF | Print media hides or relocates it. | Correct @media print or deliberately call emulateMediaType('screen'). |
| Colors or background bands disappear | printBackground remains false or print color adjustment changes appearance. |
Enable printBackground; use exact color adjustment only when required. |
| One blank trailing page | Overflow, dimensions, margins or page-break rules. | Inspect the physical layout and create a minimal reproduction; do not delete pages blindly. |
| Intermittent failures | Fixed delay, late network data or a later animated update. | Replace sleeps with readiness signals tied to the real lifecycle. |
Or skip the browser setup
For a direct screenshot or PDF capture without maintaining Puppeteer, ScreenshotNeo provides a GET API and an MCP server. It accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info and capture_pdf—work with Claude, Cursor and other MCP clients. One thousand screenshots per month are free with no card; paid plans start at $5 for 3,000 shots.
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, selector capture, waiting for a selector or network idle, custom CSS and JavaScript, PDF page ranges, signed webhooks and bulk jobs. Create a free ScreenshotNeo account to get 1,000 screenshots each month without a card.
Frequently Asked Questions
Does networkidle2 guarantee that a Chart.js chart is ready?
No. It describes network activity. Use a Chart.js completion callback or an application readiness signal that also covers data and updates.
Should I always disable Chart.js animation for PDFs?
No. It is a practical PDF-only option, but a completion callback preserves the configured visual behavior. Either way, wait for asynchronous data and chart construction.
Can waitForFonts fix a blank chart?
No. Puppeteer’s font wait helps typography, not JavaScript execution, canvas painting or Chart.js animation completion.
Is an extra blank page evidence of a Chart.js bug?
No. Verify the chart separately, then inspect print dimensions, overflow, margins and page-break rules.
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.




