ScreenshotNeo

BlogHow-to

How to Convert HTML Code to a Picture

Render HTML in a browser, then capture the viewport, full page, or an element as PNG, JPEG, or WebP with Playwright, Puppeteer, or ScreenshotNeo.

By the ScreenshotNeo team1 October 20268 min read

To convert HTML code to a picture, render it in a browser and capture the rendered result. HTML source is not itself an image. A browser resolves CSS, fonts, images, JavaScript, and layout; a screenshot records what the browser displays.

For a one-off conversion, open the HTML in a browser and use its screenshot capability. For repeatable work, use Playwright or Puppeteer. Both can capture the current viewport, the complete scrollable page, or one selected element as PNG, JPEG, or WebP.

1. Choose the capture you actually need

Goal Capture Typical use
What is visible on screen Viewport screenshot App previews, browser-like images
The entire document Full-page screenshot Long articles, invoices, landing pages
One component Element screenshot Cards, charts, receipts, widgets
A raw HTML string Set page content, then capture Generated reports and templates
Paginated output PDF Documents intended for printing or download

Use a raster screenshot when you need a picture. PDF is a separate output format with pagination and print CSS; it is not a direct replacement for PNG, JPEG, or WebP.

2. Convert an HTML string with Playwright

Playwright documents page.setContent(), viewport and full-page screenshots, element screenshots, PNG/JPEG/WebP output, scale, quality, clipping, and transparent backgrounds in its Page API and screenshot guide.

Install Playwright

npm init -y
npm install playwright
npx playwright install chromium

Complete Node.js example

const { chromium } = require('playwright');

(async () => {
  const html = `<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      * { box-sizing: border-box; }
      body { margin: 0; font-family: system-ui, sans-serif; background: #f4f6fb; }
      .card { width: 900px; margin: 40px auto; padding: 48px; border-radius: 24px;
              background: white; color: #172033; box-shadow: 0 20px 60px #17203322; }
      h1 { margin-top: 0; font-size: 48px; }
      p { font-size: 20px; line-height: 1.6; }
    </style>
  </head>
  <body>
    <main class="card">
      <h1>HTML rendered as an image</h1>
      <p>The browser lays out this document before Playwright captures it.</p>
    </main>
  </body>
</html>`;

  const browser = await chromium.launch();
  const page = await browser.newPage({
    viewport: { width: 1200, height: 800 },
    deviceScaleFactor: 1
  });

  await page.setContent(html, { waitUntil: 'load' });
  await page.screenshot({ path: 'viewport.png', type: 'png' });
  await page.screenshot({ path: 'full-page.webp', type: 'webp', quality: 90, fullPage: true });
  await page.locator('.card').screenshot({ path: 'card.jpeg', type: 'jpeg', quality: 85 });

  await browser.close();
})();

The first capture is the viewport. The second includes the full scrollable page. The third captures only the element matching .card.

Capture a URL instead of an HTML string

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
  await page.goto('https://example.com', { waitUntil: 'networkidle' });
  await page.screenshot({ path: 'example.png', fullPage: true });
  await browser.close();
})();

Use waitUntil: 'load' for normal documents. Use a specific selector wait or a deliberate delay when client-side rendering, fonts, charts, or lazy images finish after the initial load event.

3. Playwright screenshot options

Option What it controls Notes
path Output file Use a matching extension for clarity.
type png, jpeg, or webp PNG is lossless; JPEG and WebP support compression.
fullPage Entire scrollable page Omit or set false for the viewport only.
quality JPEG/WebP quality Does not apply to PNG.
scale CSS pixel or device pixel output Choose based on display and file-size needs.
clip Rectangle to capture Useful for a fixed region.
omitBackground Transparent background Useful with PNG; JPEG cannot be transparent.
animations Animation handling Disable or wait for motion when deterministic output matters.

Set the viewport before rendering. A responsive page can produce a completely different picture at 375px and 1440px. Set deviceScaleFactor when you need retina-density output.

4. Wait for fonts, images, and dynamic content

A screenshot taken too early may contain fallback fonts, empty image boxes, unfinished charts, or skeleton loaders. Prefer an observable readiness condition over a large arbitrary delay.

await page.goto('https://example.com/report', { waitUntil: 'domcontentloaded' });
await page.waitForLoadState('networkidle');
await page.evaluate(() => document.fonts.ready);
await page.locator('[data-report-ready="true"]').waitFor();
await page.screenshot({ path: 'report.png', fullPage: true });

For images that are already in the DOM, you can wait until they report complete:

await page.waitForFunction(() => Array.from(document.images)
  .every(img => img.complete && img.naturalWidth > 0));

Infinite-scroll pages require a custom scroll-and-load routine. A full-page screenshot cannot include content that the page has not yet rendered.

5. Convert HTML with Puppeteer

Puppeteer provides the same core workflow: launch a browser, create a page, navigate or set content, and call page.screenshot(). Its guide documents page screenshots and ElementHandle.screenshot(); see the Puppeteer screenshot guide and Page.screenshot API.

npm init -y
npm install puppeteer
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.setViewport({ width: 1200, height: 800, deviceScaleFactor: 1 });

  const html = `<style>body{font-family:Arial;padding:40px}.panel{padding:30px;background:#eef}</style>
    <section class="panel"><h1>Generated HTML</h1><p>Captured by Puppeteer.</p></section>`;
  await page.setContent(html, { waitUntil: 'load' });

  await page.screenshot({ path: 'page.png', fullPage: true });
  const panel = await page.$('.panel');
  await panel.screenshot({ path: 'panel.webp', type: 'webp', quality: 90 });

  await browser.close();
})();

6. Images, CSS, and security edge cases

  • Relative assets: An HTML string with <img src="images/logo.png"> needs a usable base URL or absolute asset URLs. Otherwise the browser cannot resolve the file.
  • Cross-origin resources: Fonts, images, and API calls can fail because of network policy or missing CORS headers. Check browser console errors and serve assets from reachable origins.
  • Authentication: Log in through the automation flow or provide the required cookies and headers before capture. Never place secrets in the HTML sent to an untrusted service.
  • Animations: Freeze animations with CSS or wait for a stable state to avoid different pixels on each run.
  • Large pages: Full-page captures can create very large dimensions and memory use. Capture a target element or split the document when possible.
  • Lazy loading: Scroll through the page or trigger the page’s loading logic before taking a full-page image.
  • Canvas and WebGL: Ensure the browser has the required rendering support and wait until drawing is complete.
  • Print output: Use page.pdf() when pagination is the requirement. Puppeteer documents PDF generation with print media by default; emulate screen media when your CSS depends on screen rules.

7. Format, dimensions, and quality decisions

Format Choose it when Trade-off
PNG Text, diagrams, transparency, lossless output Larger files for photographic content
JPEG Photos or smaller opaque images Lossy and no transparent background
WebP Modern web delivery with good compression Confirm every consumer supports it

CSS dimensions determine layout; scale determines how many output pixels represent those dimensions. Increase scale for high-density displays, but expect larger files and more memory use. Use quality controls only for JPEG and WebP.

8. Troubleshooting

Symptom Cause Fix
Blank or white image Capture ran before content rendered Wait for a selector, fonts, images, or network idle.
Missing images Broken relative URLs or blocked requests Use absolute URLs, a base URL, and inspect network errors.
Wrong mobile layout Default viewport is different from the target Set width, height, and device scale explicitly.
Only part of a long page appears Viewport capture was used Set fullPage: true or capture the required element.
Text changes between runs Fonts or animations are not stable Wait for document.fonts.ready and disable motion.
Element selector fails Selector is wrong or element is created later Use a stable data attribute and wait for it.
JPEG has a solid background JPEG cannot represent transparency Use PNG or WebP with an omitted background.
Browser will not launch in CI Missing browser binary or system dependency Install the framework’s browser and required CI dependencies.

9. Performance, reliability, and cost

  • Reuse one browser process and create pages per job instead of launching a new browser for every image.
  • Set a navigation timeout and an overall job timeout so a stalled origin does not consume workers indefinitely.
  • Prefer element captures when you do not need the whole document; they reduce image dimensions and processing.
  • Cache identical inputs when the source and rendering conditions are unchanged.
  • For reliable output, pin browser versions, set deterministic viewport and timezone settings, wait on explicit readiness signals, and record the URL, options, and capture timestamp.
  • Self-hosted browser automation costs compute, storage, and operational time. A hosted API can be simpler for recurring or bulk conversions, especially when you need retries, caching, signed delivery, or request-level status.

10. Or skip the browser setup

ScreenshotNeo renders a URL and returns a clean PNG, JPEG, WebP, or PDF from one GET request. It can load full pages, capture one CSS-selected element, set a viewport or device preset, apply custom CSS and JavaScript, click before capture, wait for a selector, delay, or network idle, and control cookies, headers, user agents, timezone, geolocation, blocked requests, caching, and more. See the ScreenshotNeo documentation for the complete option set.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Cookie and consent banners are accepted and removed before the shot, along with more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup 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. ScreenshotNeo also provides 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 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account.

11. FAQ

Can HTML be converted to an image without a browser?

Not reliably for general HTML and CSS. The browser is what resolves layout, fonts, scripts, and assets. A browser-based renderer or screenshot API is the direct approach.

Should I use a screenshot or PDF?

Use PNG, JPEG, or WebP for a picture. Use PDF when pagination, paper size, margins, or print CSS matter.

How do I capture only a card or chart?

Use an element locator in Playwright or an element handle in Puppeteer, then call its screenshot method.

Why does my screenshot differ across machines?

Rendering can vary with browser version, fonts, viewport, device scale, timezone, available resources, and animation timing. Pin those inputs and wait for a deterministic ready state.

Can I turn a private page into a picture?

Yes, when your automation session has permission to access it. Supply authentication through a controlled browser context or approved headers and cookies, and keep credentials out of generated HTML.