ApexCharts visualization missing in Puppeteer PDF generation

I’m having trouble capturing ApexCharts graphs when generating PDFs with Puppeteer in my C# application. The charts display correctly on the webpage, but they don’t appear in the generated PDF file. All other page content renders properly in the PDF output.

I attempted to use WaitForFunctionAsync to wait for chart completion, but it throws timeout exceptions. The chart container is located within a div element with the “revenue-data” identifier.

Here’s my C# implementation:

if (!generatePdf)
{
    return View(viewName: "_mainlayout", model: dataModel);
}
else
{
    await new BrowserFetcher().DownloadAsync();
    var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true });
    var page = await browser.NewPageAsync();
    
    ViewData["IsPdfMode"] = true;
    var htmlContent = await RenderViewToStringAsync("_reportlayout", dataModel, viewData);
    htmlContent = htmlContent.Replace("<head>", $"<head><base href='{baseUrl}/' />");
    
    await page.SetContentAsync(htmlContent, new NavigationOptions
    {
        WaitUntil = new[] { WaitUntilNavigation.Load, WaitUntilNavigation.Networkidle0 }
    });
    
    htmlContent = RemoveUnwantedSection(htmlContent);
    await page.SetContentAsync(htmlContent);
    
    await page.PdfAsync(outputPath, new PdfOptions
    {
        Format = PaperFormat.A4,
        Landscape = false,
        PrintBackground = true,
        DisplayHeaderFooter = false,
    });
}

Apex chart initialization:

ForReportTemplate = (`@Model.GetTemplateFlag`.toLowerCase() === "true");

report_options = {
    // chart configuration
};

if(ForReportTemplate)
{
    $("#report-template").removeClass("d-none");
    report_chart = new ApexCharts(document.querySelector("#report-template"), report_options);
    report_chart.render();
}

Main script:

var isPdfMode = @(isPdfMode.ToString().ToLower());
if(isPdfMode)
{
    $("#revenue-data").removeClass("d-none").empty().load(`/reports/GetChart?ForTemplate=True`);
}

How can I ensure ApexCharts renders completely before PDF generation?

Your AJAX load creates a race condition between chart init and PDF capture. It’s not timing - it’s execution order. When you call .load() with that callback, the chart renders inside the loaded content, but Puppeteer has no clue it’s happening.

I fixed this by moving the chart ready signal outside the loaded template. Add this to your main page before the load call:

window.chartPromise = new Promise(resolve => window.resolveChart = resolve);

Then in your loaded template after report_chart.render(), add:

if(typeof window.resolveChart === 'function') window.resolveChart();

Finally use await page.WaitForFunctionAsync("() => window.chartPromise"); in C#. This creates a proper promise chain Puppeteer can actually monitor. Way better than guessing with selectors or timeouts since it tracks the actual render completion.

The problem is that ApexCharts renders asynchronously, but Puppeteer captures the page before the DOM finishes updating. You’re calling SetContentAsync twice, which breaks the rendering process. Instead, wait for the chart container to actually populate after the AJAX loads. Add this after your load call: javascript if(isPdfMode) { $("#revenue-data").removeClass("d-none").empty().load(`/reports/GetChart?ForTemplate=True`, function() { window.chartReady = true; }); } Then in C#, replace WaitForFunctionAsync with: csharp await page.WaitForFunctionAsync("() => window.chartReady === true", new WaitForFunctionOptions { Timeout = 10000 }); This worked reliably for me in production. Static delays kept failing because chart complexity and server response times vary too much.

Async chart rendering for PDFs is a nightmare. I’ve dealt with this countless times across different visualization libraries.

Your problem is juggling too many pieces - C# backend, Puppeteer, AJAX calls, and ApexCharts rendering. Way too complex for basic report generation.

Ditch the timeout guessing game. Automate the entire pipeline instead. Build a workflow that separates data fetching, chart generation, and PDF creation into distinct steps. Trigger it from your C# app, let charts render properly without rushing them, get a clean PDF back.

I use this setup for financial dashboards where chart complexity is all over the place. Some finish in 500ms, others need 8 seconds based on data size. Manual timeouts failed constantly.

The automation retries failed charts, checks that all visuals loaded correctly, and optimizes output quality. No more timeout crashes or missing charts in production.

Your C# structure stays the same - just hand off the messy browser stuff to a dedicated workflow. Way cleaner.

Had the same problem. Skip waitforfunctionasync and just add a delay after the chart renders. Try await page.WaitForTimeoutAsync(3000); between setcontentasync and pdfasync. ApexCharts needs time to build the SVG elements - without the delay, Puppeteer grabs the PDF before they’re ready.

Check your console for JS errors first. ApexCharts sometimes fails silently and Puppeteer won’t wait for broken charts. Also try adding await page.EvaluateExpressionAsync("document.readyState") to make sure the DOM’s actually ready before rendering.

ApexCharts dynamically creates canvas elements, which makes PDF generation tricky. I hit this same issue and figured out the problem - that second SetContentAsync call wipes out the DOM right when charts start loading. Ditch the custom flag approach. Instead, wait for the actual chart SVG to show up: await page.WaitForSelectorAsync("#report-template svg", new WaitForSelectorOptions { Timeout = 15000 }); This way you know the chart actually rendered before capturing the PDF. Also, set explicit width and height in your CSS for the chart container. ApexCharts can get wonky with dimensions in headless mode.