Website-to-PDF APIs: Use Cases for Developers
Learn how website-to-PDF APIs render JavaScript, CSS, fonts and print layouts for invoices, reports, downloads and automated documents.

Website-to-PDF APIs turn a URL, HTML string or template into a downloadable PDF over HTTP. They are useful when your application must generate invoices, receipts, reports, certificates, contracts or visitor-facing page downloads without asking users to install a browser or manage print settings.
The important implementation choice is the rendering engine. A browser-based service such as Chromium can execute JavaScript, load web fonts, apply CSS3, print background colors, honor page sizes and margins, and wait for client-rendered data before producing the file. A basic HTML-to-PDF converter may fail on single-page applications, delayed charts, custom fonts or print-specific layouts.
What a website-to-PDF API does
Most services expose one or more of these input modes:

- URL mode: the service opens a public web address and prints the rendered page.
- HTML mode: you send an HTML document, often with inline or hosted CSS.
- Template mode: your application sends structured data that is merged into a provider-managed template.
- Asset mode: you upload a ZIP or other package containing HTML, stylesheets, fonts and images.
The response is normally a PDF body, a temporary download URL, or an asynchronous job identifier. Before selecting a provider, confirm authentication, request limits, timeout behavior, storage duration, webhook support and the languages covered by official SDKs.
Core use cases
Invoices, receipts and quotes
HTML and CSS are often easier for a product team to maintain than a PDF drawing library. Your billing service can insert customer data, line items, tax details and payment status into a deterministic print template, then call the conversion API. Define print CSS for page size, margins, tables and page breaks so totals do not split from their labels.
Reports and dashboards
Analytics pages frequently load data after the initial HTML response. A browser renderer must wait for a selector, network-idle state or application-specific signal before printing. Capture a stable report route rather than a dashboard that changes while the request is running.
Certificates, contracts and legal documents
Certificates and contracts benefit from controlled fonts, fixed page dimensions, headers, footers and explicit page breaks. Embed or preload the fonts you are licensed to use, and keep a document version or template identifier in your own database so a later regeneration is traceable.
Visitor-facing downloads
A “Download PDF” button can send the current page URL to an API and return a file. This pattern is useful for knowledge bases, product documentation, customer portals and WordPress content. Protect private pages with short-lived authentication and never expose a provider API key in browser JavaScript.
Workflow automation
PDF generation can run after an event in Zapier or Make: an order is paid, a form is approved, or a support case is closed. Use asynchronous jobs and webhooks when the workflow can tolerate a delayed delivery, and make the webhook handler idempotent so retries do not send duplicate documents.
Rendering features that affect fidelity
| Requirement | Why it matters | What to verify |
|---|---|---|
| JavaScript | Required for React, Vue, charts and client-side data. | Does the renderer execute scripts, and can you wait for completion? |
| CSS and print media | Controls layout, colors, visibility and page breaks. | Are CSS3 features and @media print supported? |
| Fonts | Wrong metrics change line wrapping and pagination. | Can remote or uploaded web fonts load before capture? |
| Backgrounds | Brand colors and chart fills may disappear otherwise. | Is print-background rendering enabled? |
| Paper and margins | Determines physical output and printable area. | Can you set paper size, orientation and margins? |
| Wait conditions | Prevents blank charts or loading skeletons in the PDF. | Are selector, delay and network-idle waits available? |
| Headers and footers | Adds page numbers, dates or document metadata. | Does the API support templates or HTML for both areas? |
DIY conversion with a headless browser
If you need complete control, run Chromium yourself. The following Node.js example uses Playwright. It waits for a report element, enables background graphics and writes a PDF. Install it with npm install playwright and ensure the Playwright browser is available in your deployment image.
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1
});
try {
await page.goto('https://example.com/report/123', {
waitUntil: 'networkidle',
timeout: 60000
});
await page.waitForSelector('[data-report-ready="true"]', {
timeout: 30000
});
await page.emulateMedia({ media: 'print' });
await page.pdf({
path: 'report.pdf',
format: 'A4',
landscape: false,
printBackground: true,
margin: { top: '18mm', right: '14mm', bottom: '18mm', left: '14mm' },
displayHeaderFooter: true,
headerTemplate: '',
footerTemplate: ' / '
});
} finally {
await browser.close();
}
Preparing HTML for reliable printing
@page {
size: A4;
margin: 18mm 14mm;
}
@media print {
.no-print { display: none !important; }
.invoice-table { break-inside: auto; }
.invoice-row { break-inside: avoid; }
h1, h2 { break-after: avoid; }
}
.chart, img, svg {
max-width: 100%;
break-inside: avoid;
}
Use absolute URLs for images and stylesheets when the renderer runs outside your network. For private resources, pass a short-lived token through a server-side request or configure the provider’s header and cookie support. Avoid relying on hover states, local storage created by a previous browser session or a user-specific viewport unless you set those values explicitly.
API request patterns
A synchronous endpoint is simplest for a user-initiated download: the request remains open until the PDF is ready. For long reports, high concurrency or batch processing, submit an asynchronous job and receive a webhook. Store the job ID, source URL, template version and request parameters with your own record.
For any provider, send only the data required to render the document. Keep API keys on your server, validate destination URLs, and set an application timeout shorter than your reverse proxy timeout so failures return a useful error instead of a dropped connection.
Or skip the browser setup
ScreenshotNeo provides a website screenshot and PDF API at https://api.screenshotneo.com/v1/shot. It accepts one GET request and can return a PDF, PNG, JPEG or WebP. Before capture it accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.

See the ScreenshotNeo API documentation for the complete option list. Relevant PDF controls include paper size, margins, landscape mode and page ranges. You can also set custom CSS and JavaScript, click an element, wait for a selector, delay or network idle, send headers and cookies, choose a timezone or geolocation, block resources, cache with a TTL, run asynchronous jobs with signed webhooks, and capture up to 100 URLs in one bulk call.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-d format=pdf \
-o page.pdf
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={
"access_key": "YOUR_API_KEY",
"url": "https://stripe.com",
"format": "pdf"
},
timeout=90
)
r.raise_for_status()
open("page.pdf", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com',
format: 'pdf'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const pdf = Buffer.from(await res.arrayBuffer());
await Bun.write('page.pdf', pdf);
ScreenshotNeo includes an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Every feature is available on every plan. Create a free ScreenshotNeo account.
Options and configuration checklist
- Input: URL, raw HTML, template data or uploaded assets.
- Authentication: API key or Bearer token on the server side; cookies and custom headers for the target page.
- Viewport: choose a desktop or mobile width before print layout is evaluated.
- Wait: selector, fixed delay, network idle or an application-ready flag.
- Output: paper size, orientation, margins, page range, background graphics and header/footer behavior.
- Security: block private network access, validate URLs and scrub sensitive query parameters from logs.
- Delivery: synchronous bytes for short requests; asynchronous job plus signed webhook for long or batch work.
- Retention: decide where your system stores the PDF and how long temporary provider links remain valid.
Troubleshooting common failures
The PDF is blank
Cause: the page is client-rendered, blocked by authentication, or captured before data arrives. Fix: authenticate the request, wait for a ready selector, increase the timeout within the provider limit, and confirm the URL returns the expected content from the capture environment.
Fonts or icons are missing
Cause: cross-origin restrictions, a blocked font request or a font that loads after capture. Fix: allow the renderer to fetch the font, use a permitted hosted or embedded font, and wait for document.fonts.ready before printing.
Tables split badly
Cause: the browser has no page-break rule for rows or headings. Fix: apply break-inside: avoid to rows and cards, repeat table headers, and test unusually long descriptions and multi-page totals.
Images are absent
Cause: lazy loading, relative URLs or hotlink protection. Fix: scroll or trigger lazy loading, use absolute URLs, pass required headers, and wait until images report complete.
The request times out
Cause: slow third-party scripts, an infinite network request or a page waiting for user interaction. Fix: block unnecessary resource types, remove analytics from the print route, use a deterministic ready signal and retry only idempotent jobs with backoff.
Private pages return a login screen
Cause: the capture browser has no session. Fix: provide a short-lived cookie or Authorization header, or expose a single-use server endpoint that generates the document after your own authorization check.
Performance, reliability and cost
Browser conversion time is dominated by page load, JavaScript execution, fonts, images and third-party requests. Keep a print-specific route lightweight, cache immutable assets and disable trackers. Reuse a browser process in self-hosted infrastructure, but isolate jobs so one runaway page cannot exhaust memory.
Reliability improves when you record the input, renderer options, provider response headers and final status. Retry transient network failures with exponential backoff; do not blindly retry validation errors, authentication failures or a consistently blocked destination. For asynchronous systems, verify webhook signatures, make processing idempotent and provide a reconciliation job for missed callbacks.
Estimate cost from completed documents, not only HTTP requests. Quotas, concurrency limits, storage and webhook retention can change the effective price. ScreenshotNeo bills only clean shots; bot checks, blank pages, failed loads, timeouts and cache hits are free. Its plans are Free: 1,000 shots/month, Starter: $5 for 3,000, Growth: $15 for 15,000, Pro: $39 for 60,000, Scale: $99 for 250,000 and Business: $249 for 1,000,000. Yearly billing provides two months free.
Testing before production
- Capture a page with long and short content, missing optional fields and multiple table pages.
- Verify JavaScript data, fonts, images, backgrounds and print colors.
- Test private authentication, expired credentials and a blocked destination.
- Check page ranges, landscape output, margins, headers, footers and page numbers.
- Exercise timeout, retry, webhook replay and duplicate-delivery paths.
- Compare generated PDFs byte-for-byte only when metadata is normalized; otherwise use visual regression or extracted text checks.
FAQ
Can an API convert a page that requires JavaScript?
Yes, when it uses a browser renderer and waits until the application has finished loading. Confirm JavaScript support and available wait controls.
Should I send HTML or a URL?
Send HTML when your server owns the template and assets. Use a URL when the page already exists and can be securely reached by the renderer.
When should conversion be asynchronous?
Use asynchronous jobs for long reports, batches, unpredictable third-party pages or workflows that can wait for a webhook.
How do I keep credentials safe?
Call the PDF provider from your backend, store keys in a secret manager and issue your users a download authorization from your own application.
Can the same system generate screenshots and PDFs?
Yes. A browser-based API can share URL, authentication, wait, CSS and blocking controls while selecting PDF or image output for each request.