ScreenshotNeo

BlogHow-to

How to Convert HTML to PNG or PDF with an API

Convert rendered HTML to PNG or PDF with Playwright or a hosted API. Get runnable examples, rendering options, troubleshooting, and a ScreenshotNeo shortcut.

By the ScreenshotNeo team4 October 20268 min read

To convert HTML to PNG or PDF, render it in a browser and use the browser’s screenshot or PDF operation. With Playwright, page.screenshot() returns image bytes and page.pdf() returns PDF bytes. If you would rather send a request than run a browser, a hosted conversion API can accept HTML and return a rendered file. This guide shows both approaches and how to choose rendering settings.

For local browser control, use Playwright’s Page API. For a hosted screenshot request with ScreenshotNeo, see the ScreenshotNeo API and its API documentation.

1. Choose a rendering path

Path Use it when What you operate
Playwright in your application You need control over navigation, browser context, timing, and the returned file bytes. Your application launches and manages browser processes.
Hosted conversion API You prefer an HTTP request over deploying and operating browser processes. You send the supported input and settings, then handle the response.

Before choosing, check what input the service accepts, which formats and rendering controls it supports, where your HTML and output are processed, and whether it returns bytes or a hosted link. The cited documentation does not establish a measured comparison of speed, fidelity, cost, or reliability.

2. Convert HTML to PNG or PDF with Playwright

The examples below use Node.js and Playwright. They create a page from an HTML string, wait for fonts, and write the resulting bytes to files. PNG is the default screenshot format; PDF is generated separately. Install Playwright and its browser before running:

npm install playwright
npx playwright install chromium

Save this as convert.mjs and run node convert.mjs:

import { chromium } from 'playwright';

const html = `<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <style>
    body { font: 16px sans-serif; margin: 32px; }
    h1 { color: #155eef; }
  </style>
</head>
<body><h1>Hello from HTML</h1><p>Rendered in Chromium.</p></body>
</html>`;

const browser = await chromium.launch({ headless: true });
try {
  const page = await browser.newPage({ viewport: { width: 1200, height: 800 } });
  await page.setContent(html, { waitUntil: 'load' });
  await page.evaluate(() => document.fonts.ready);

  const png = await page.screenshot({ type: 'png', fullPage: true });
  await import('node:fs/promises').then(fs => fs.writeFile('output.png', png));

  const pdf = await page.pdf({ format: 'A4', printBackground: true });
  await import('node:fs/promises').then(fs => fs.writeFile('output.pdf', pdf));
} finally {
  await browser.close();
}

The screenshot and PDF calls are distinct. The screenshot captures pixels; PDF generation lays out a document for printing. Playwright uses print CSS media for PDF by default. To apply screen media rules instead, call await page.emulateMedia({ media: 'screen' }) before page.pdf().

Convert an existing page URL

If your HTML is already served, navigate to it instead of calling setContent:

await page.goto('https://example.com/report', { waitUntil: 'networkidle' });
await page.screenshot({ path: 'page.png', fullPage: true });
await page.pdf({ path: 'page.pdf', format: 'A4', printBackground: true });

Use a URL your server can reach. For authenticated pages, establish the required browser context, cookies, or headers before navigation. Avoid relying on a fixed short delay when you can wait for a known element that signals the page is ready.

Useful screenshot settings

Setting Effect
type Choose PNG, JPEG, or WebP. PNG is the default.
fullPage: true Capture the full scrollable page instead of only the viewport.
scale Choose CSS-pixel or device-pixel output scaling; device-pixel output can be larger.
omitBackground: true Capture with a transparent background where supported by the chosen output.

For a single component, locate it and use the locator’s screenshot operation, for example await page.locator('.invoice').screenshot({ path: 'invoice.png' }). Make sure the selector resolves to the intended element and that it is visible before capture.

Useful PDF settings

Playwright’s page.pdf() supports document-oriented options such as paper format, explicit width and height, margins, landscape orientation, page ranges, and printing background graphics. Check the current Page API reference for exact option names and supported values for your installed version. For example:

await page.pdf({
  path: 'report.pdf',
  format: 'A4',
  landscape: false,
  printBackground: true,
  margin: { top: '12mm', right: '12mm', bottom: '12mm', left: '12mm' }
});

Use CSS print rules such as @page and break-inside when you need to control pagination. Validate long tables, page breaks, and headers or footers with representative documents; a page screenshot and a PDF can differ because they use different layout media and page dimensions.

3. Convert HTML through a hosted API

A hosted endpoint moves the browser operation behind an HTTP request. The html2png.dev reference documents POST https://html2png.dev/api/convert, raw HTML in the request body, and PNG, JPEG, WebP, or PDF output. Its documented settings include viewport width and height, device scale factor, delay, selector, zoom, and transparent background. These details come from that provider’s reference; verify current limits, data handling, and response behavior before production use.

The reference does not establish the exact authentication mechanism or response schema in the research available for this article. Consult the provider’s API reference for a current request example rather than guessing headers or assuming whether it returns file bytes or a URL.

For any hosted HTML conversion API, treat the request and response as a normal file-processing flow:

  1. Send the HTML and supported render options using the documented content type and authentication.
  2. Check the HTTP status and content type before saving the response.
  3. Write binary response bytes to a file or stream them to the next step in your application.
  4. Set a request timeout, and handle provider errors separately from valid image or PDF bytes.

If your input is a public URL rather than HTML, confirm that the endpoint supports URL capture. Raw-HTML support alone does not imply URL support.

4. Or skip the browser setup

For a URL capture, ScreenshotNeo accepts one GET request and returns an image or PDF. It also accepts HTML/CSS for image output. The following examples save a PNG capture of Stripe; see the ScreenshotNeo API docs for options and response handling.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(async fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Sign up for ScreenshotNeo’s free plan and capture up to 1,000 screenshots a month without a card.

5. Rendering details that affect the result

Fonts and assets

Wait for the page’s fonts and required images before capturing. Remote assets must be reachable from the browser or conversion service. A page can finish its initial load while a client-side chart, image, or font is still pending. Prefer a readiness condition tied to the content you need; add a bounded delay only when the page has no reliable signal.

Viewport, scale, and page size

The viewport affects responsive breakpoints and therefore layout. A larger device scale factor increases image pixel dimensions and can increase file size and memory use. Full-page images of very tall documents may consume substantial memory. For PDFs, select a paper size and margins that match the intended use, and enable background printing when colored backgrounds matter.

Dynamic or personalized HTML

Render with the same locale, timezone, authentication, and data state that should appear in the output. Avoid embedding secrets in HTML that will be sent to a third-party service unless its handling is appropriate for your content. Sanitize untrusted HTML and restrict resource access in systems that render user-supplied markup.

6. Performance, reliability, and cost

  • Browser operation: local Playwright requires browser installation and capacity management. Reuse browser processes sensibly, but isolate pages or contexts when jobs must not share cookies or state.
  • Bound work: set navigation and job timeouts, cap concurrent renders, and limit input size and page dimensions to protect memory.
  • Retry carefully: retry transient transport or service failures with a bounded policy. Do not retry invalid HTML or unsupported settings unchanged.
  • Hosted service: review current price, rate limits, retention, privacy, and output delivery with the provider. The cited hosted API reference does not settle these questions.
  • File handling: write to temporary files or stream output when documents are large, and check disk or object-storage capacity.

No benchmark or comparative reliability data is established by the cited documentation. Measure your own representative documents, including large pages and pages with delayed assets, before setting production timeouts or capacity.

7. Troubleshooting

Symptom Likely cause Fix
Screenshot is blank or missing content Capture happened before client rendering, font load, or image load completed. Wait for a content-specific selector or readiness signal; verify remote resources are reachable.
PDF colors or backgrounds are missing Background printing is disabled or print CSS changes the design. Enable printBackground; inspect print styles, or emulate screen media if screen styling is intended.
PDF layout differs from screenshot PDF uses print media and paper pagination, while screenshot uses viewport layout. Set the intended media, paper size, margins, and print CSS explicitly.
Text wraps differently Viewport width, fonts, or device scale differ from the expected rendering environment. Set the viewport deliberately and wait for fonts; ensure required fonts are installed or loadable.
Hosted request returns an error Request format, authentication, limits, or option names may not match provider requirements. Check the provider’s current reference, inspect status and error body, and avoid treating error content as an image.
Render times out Page keeps network connections open or depends on slow resources. Use an appropriate readiness condition, block unnecessary requests where supported, and set a bounded timeout.
Very large output or memory pressure Full-page capture, high device scale, or long documents create large buffers. Reduce scale or dimensions, capture a specific element, split long content, or stream/manage files carefully.

8. FAQ

Can one conversion produce both a PNG and a PDF?

With Playwright, call the screenshot and PDF operations separately. They use different output paths and may apply different layout rules.

Does PNG preserve transparency?

Playwright documents a transparent-background option for screenshots. Confirm the selected format and downstream image handling preserve alpha if transparency is required.

Is a hosted API always simpler?

It removes browser installation and operation from your application, but you still need to check supported input, settings, service limits, privacy, and returned-file handling.

Should I use HTML input or a URL?

Use HTML when the content is already available to your application and the API accepts raw markup. Use a URL only when the service explicitly documents URL capture and can access the page in its expected network environment.

Sources