Convert JavaScript-rendered pages, dashboards and charts to PDF
Convert a JavaScript-rendered page to PDF only once it has finished drawing. Dashboards plot their charts after the data arrives, and single-page apps render nothing until their bundle runs, so a print fired too early is a PDF of a spinner. Analytics exports, weekly KPI reports and printable views of React, Vue or Angular apps all need the same thing: the PDF API waits for the element you name, then prints.
The PDF prints before the JavaScript-rendered page has drawn
Browsers fire the load event when resources are fetched, not when the framework has rendered or the chart library has finished drawing. A PDF printed at that moment captures skeletons, empty axes and placeholder text.
The reflex fix is a fixed delay, and it fails both ways: three seconds is too short on a slow day and wasted on every fast one. Fetch-based converters never run the JavaScript at all, so for a client-rendered app they print an empty shell. Scripting your own headless browser works, but then you own the waits, the timeouts and the crashes.
With waitForSelector the print waits until a specific element appears in the DOM. waitUntil picks a lifecycle event such as network idle, waitForTimeout adds a fixed delay as a last resort, and click opens the tab or section you need before printing.
How to print a JavaScript-rendered page to PDF once it is ready
Navigate quickly, wait for the exact content, then print. Add interactions when the content sits behind a control. The PDF page preparation guide shows each wait strategy with a live example.
import createClient from 'microlink.io'
const microlink = createClient({
apiKey: process.env.MICROLINK_API_KEY
})
const { url } = await microlink.pdf('https://app.example.com/report', {
waitUntil: 'domcontentloaded',
waitForSelector: '.chart svg',
format: 'A4',
landscape: true
})domcontentloaded moves on as soon as the DOM is parsed, and the print fires once the chart’s SVG exists. Landscape suits wide charts; url points to the hosted PDF.
import createClient from 'microlink.io'
const microlink = createClient({
apiKey: process.env.MICROLINK_API_KEY
})
const { url } = await microlink.pdf('https://app.example.com/report', {
click: ['#expand-all'],
waitForSelector: '.section.expanded',
waitUntil: 'networkidle0'
})click opens collapsed accordions and tabs, and waitForSelector holds the print until the content they reveal is in the DOM. Selectors passed as an array are clicked in order.
curl 'https://api.microlink.io/?url=https%3A%2F%2Fapp.example.com%2Freport&pdf=true&meta=false&waitForSelector=.chart+svg&waitUntil=domcontentloaded'Works on the free endpoint within the 30-second timeout; Pro extends it to 60 seconds. If the report sits behind a login, forward the session as described in PDF invoices from authenticated pages.
- waitForSelector Waits until the CSS selector appears in the page before printing.
- waitUntil auto (default), load, domcontentloaded, networkidle0 or networkidle2; accepts an array.
- waitForTimeout Fixed delay for when no stable selector exists; capped by the request timeout.
- click Opens tabs, expands accordions or dismisses dialogs before printing.
- scroll Scrolls to a selector to bring lazy sections into view so they load.
- javascript Enabled by default; keep it on for client-rendered pages and disable it only for static ones.
CSS animations are disabled by default and prefers-reduced-motion is set accordingly, which chart libraries that honor it use to skip entrance animations. When a page still misbehaves, the PDF troubleshooting guide maps each symptom to a fix.
Why the wait belongs in the PDF request
A PDF is a snapshot of one page state. Declaring that state in the request makes the snapshot reproducible, whoever runs it and whenever.
Combine domcontentloaded with waitForSelector so the request does not sit waiting for fonts and analytics scripts that never affect the content.
For flows that need more than clicks, such as typing into a filter, the browser automation feature and the function parameter give you the full page object.
When not to: if you only need the chart as an image, screenshots of JavaScript-rendered pages are lighter. A report that exists only as data is often better served by a print-ready HTML page you control, printed with the PDF API, than by a dashboard UI that was never meant for paper.
FAQ
Why is my PDF empty or showing a loading spinner?
Can I print a specific tab or an expanded section to PDF?
How long can the PDF API wait for content to render?
Do charts print to PDF with their final values?
Does the PDF API run JavaScript before printing a single-page app?
Solve the next problem with the same API
PDFs in bulk
Clean PDFs without ads or banners
Paper size, margins and orientation
PDF invoices from authenticated pages
Screenshots of JavaScript-rendered pages
Markdown from JavaScript-rendered pages
Ready to print rendered dashboards?
Wait for the chart, then print. Start on the free tier and turn your first single-page report into a PDF today.