Skip to content
PDF API · Use case

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 problem

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 it works

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.

1 · Wait for the chart to draw
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.

2 · Expand sections before printing
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.

3 · The same request as a URL
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.

Parameters used
  • 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 it works

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.

01 · Condition, not duration
The print happens when the element exists.
Waiting for a selector returns as soon as the chart is drawn and still handles the slow case. A fixed delay is either too short on a bad day or too slow on every other day.

Combine domcontentloaded with waitForSelector so the request does not sit waiting for fonts and analytics scripts that never affect the content.

02 · Interactions included
click and scroll put the page in the right state.
Collapsed accordions, hidden tabs and lazy-loaded sections are UI state. Open them, scroll to them, then wait for what they reveal, all inside one request and without a script of your own.

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.

03 · Same recipe as screenshots
One page-state model across outputs.
The wait, click and scroll options behave the same for PDFs and screenshots, so the recipe that captures a dashboard as an image also prints it as a document.

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?

The print fired before the app rendered. Add waitForSelector for an element that only exists once the data has loaded, or set waitUntil to networkidle0 when the page keeps fetching. A reliable pattern is waitUntil: domcontentloaded plus a selector wait.

Can I print a specific tab or an expanded section to PDF?

Yes. Use click with the selector of the tab or the expand control, then waitForSelector for the content it reveals, and the PDF includes it. Pass an array to click several controls in order.

How long can the PDF API wait for content to render?

Up to the request timeout: 30 seconds on the free endpoint and 60 seconds on Pro plans. A waitForTimeout larger than that is ignored. Keep your waits well inside that budget, because the print itself also needs time.

Do charts print to PDF with their final values?

Chart libraries that honor prefers-reduced-motion skip entrance animations because the API disables animations by default. For libraries that animate regardless, wait for a selector the library adds when drawing completes, or add a short waitForTimeout.

Does the PDF API run JavaScript before printing a single-page app?

Yes. Every PDF is rendered in a headless browser with JavaScript enabled by default, so React, Vue, Angular and other client-rendered apps build their DOM before the print. You only need to tell the API what to wait for. Wide dashboards usually also want the landscape and scale options.
Related use cases

Solve the next problem with the same API

PDFs in bulk

Render thousands of documents from URLs in one job: parallel requests, server-side retries and per-document caching.

Clean PDFs without ads or banners

Get a document, not a browser tab: ads and consent popups blocked by default, sticky chrome removed with one CSS rule.

Paper size, margins and orientation

Print any URL on A4, Letter or custom paper, with per-side margins, landscape, scale and page ranges.

PDF invoices from authenticated pages

Print the invoice page your app already renders: forward the session, hide the chrome, name the file.

Screenshots of JavaScript-rendered pages

Wait for a selector, a lifecycle event or a delay so single-page apps and lazy sections finish rendering before capture.

Markdown from JavaScript-rendered pages

Render single-page apps in a real browser, wait for the content, then convert the finished DOM to Markdown.

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.