Chart.js not rendering in PDF created with Puppeteer

I have an issue where I’m creating a PDF document using Puppeteer and trying to include a Chart.js visualization. The problem is that while the chart displays correctly when I view the HTML template in a browser, it shows up as empty space in the generated PDF.

Here’s my current approach:

async function createReport() {
  const chartData = { numbers: "sampleData" };
  
  try {
    const htmlTemplate = await loadTemplate();
    const compiler = handlebars.compile(htmlTemplate, { strict: true });
    const compiledHtml = compiler(chartData);
    
    const browserInstance = await puppeteer.launch({ args: ["--no-sandbox"] });
    const newPage = await browserInstance.newPage();
    
    await newPage.setContent(compiledHtml);
    
    await newPage.pdf({
      path: "report.pdf",
      format: "A4",
      displayHeaderFooter: true,
      margin: {
        top: "3cm",
        right: "3cm",
        bottom: "3cm",
        left: "3cm"
      },
      headerTemplate: "<div></div>",
      footerTemplate: '<div style="width: 100%; font-size: 12px; margin-left: 3cm; margin-right: 3cm;"><span>REPORT</span></div>'
    });
    
    await browserInstance.close();
    console.log("Report created successfully");
  } catch (error) {
    console.error(error);
  }
}

createReport();

Any ideas why the chart isn’t showing up in the PDF output?

you might need to wait for chart.js to finish rendering. try adding await newPage.waitForTimeout(2000) after setting the content but before the pdf generation. also, ensure your chart canvas has explicit width/height in css to avoid rendering issues.

Check if your chart canvas dimensions are being properly set in the HTML template. I had a similar situation where the canvas element was getting zero height during PDF generation even though it worked fine in the browser. What solved it for me was explicitly setting the canvas container dimensions in CSS and adding printBackground: true to the PDF options since some chart backgrounds don’t render by default in print mode. Also consider using waitForSelector to wait for the specific canvas element rather than generic timeouts, something like await newPage.waitForSelector('canvas') before generating the PDF. The headless browser environment sometimes behaves differently with dynamic content compared to regular browsers.

I encountered this exact problem last month. The issue is that Chart.js uses JavaScript to render the canvas element, but Puppeteer captures the page before the chart has fully loaded. Instead of using arbitrary timeouts, I recommend waiting for a specific selector or network idle state. Add await newPage.waitForLoadState('networkidle') or better yet, use await newPage.waitForFunction(() => window.Chart && document.querySelector('canvas')) to ensure the chart library has loaded and the canvas exists. Also make sure your HTML template includes the Chart.js script tag with proper async loading. This approach is more reliable than fixed delays since rendering time can vary based on chart complexity.