What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
For a server-side HTML string, the most direct npm solution is node-html-to-image. It uses Puppeteer in headless mode, renders your markup in Chromium, and writes a PNG (or JPEG) file or returns an image buffer. You do not need to open a visible browser window. If you already have a DOM element in a browser, use html-to-image instead; for maximum browser control, use Puppeteer or Playwright directly.
Choose the package that matches your input
The key decision is whether your HTML exists as a string on the server or as a live DOM node in a browser.
| Situation | Best fit | Why |
|---|---|---|
| Node.js receives an HTML string and should create a file or buffer | node-html-to-image |
Short API around headless Puppeteer; accepts html and an output path. |
| A page already contains the element you want to export | html-to-image |
Clones a DOM node and returns a PNG data URL, blob, canvas, SVG, or JPEG. |
| You need direct browser, navigation, lifecycle, or element control | Puppeteer | Low-level Chromium API with page and element screenshots. |
| You need browser-engine coverage | Playwright | Screenshot APIs for Chromium, Firefox, and WebKit, including full-page capture. |
There is no independent benchmark establishing that one option is universally faster or more pixel-perfect. Rendering depends on fonts, external assets, browser version, viewport, and page complexity.
Convert an HTML string with node-html-to-image
Install it
npm install node-html-to-image
The package uses Puppeteer, so installation downloads a Chromium build. Its documentation gives approximate download sizes of 170 MB on macOS, 282 MB on Linux, and 280 MB on Windows; these are package notes, not a performance benchmark. In minimal containers, allow disk space and ensure the browser can run with your sandbox policy.
#1 Best Overall
Minimal ES module example
import nodeHtmlToImage from 'node-html-to-image';
await nodeHtmlToImage({
output: './image.png',
html: '<html><body><h1>Hello world!</h1></body></html>'
});
console.log('Wrote image.png');
Save this as convert.mjs and run node convert.mjs. The documented default type is PNG. The output path is created by the package; use a writable directory in production.
Return a buffer instead of writing a file
import fs from 'node:fs/promises';
import nodeHtmlToImage from 'node-html-to-image';
const html = `
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body { margin: 0; font-family: Arial, sans-serif; }
.card { width: 800px; padding: 40px; background: #111827; color: white; }
</style>
</head>
<body><div class="card"><h1>Build report</h1><p>Rendered in Node.js</p></div></body>
</html>`;
const image = await nodeHtmlToImage({ html });
await fs.writeFile('./report.png', image);
console.log(`Saved ${image.length} bytes`);
Returning bytes is useful for an HTTP response, object storage upload, or email attachment. Set your response content type to image/png.
Control what gets rendered
Target one element with selector
const image = await nodeHtmlToImage({
html: `<body>
<div id="page">Ignore this wrapper</div>
<article class="invoice"><h1>Invoice 1042</h1></article>
</body>`,
selector: '.invoice',
type: 'png'
});
The documented default selector is body. Selecting a component avoids capturing unrelated page content. Transparent PNG output is supported when your CSS leaves the target background transparent.
Wait for content and scripts
Use the package’s waitUntil, timeout, and lifecycle hooks when HTML depends on JavaScript or remote assets. beforeRendering runs before rendering and beforeScreenshot runs before the screenshot, allowing you to modify the page or wait for a selector.
Free tools Windows power users keep installed
One-click scans. No signup required.
const image = await nodeHtmlToImage({
html: `<body>
<div id="app">Loading...</div>
<script>setTimeout(() => app.textContent = 'Ready', 300);</script>
</body>`,
selector: '#app',
waitUntil: 'networkidle0',
timeout: 30000,
beforeScreenshot: async (page) => {
await page.waitForSelector('#app');
}
});
Choose a finite timeout even when waiting for network idle: analytics, streaming requests, or advertisements can keep a page active indefinitely.
Rank #2
PNG, JPEG, and output choices
Use type: 'png' for lossless text, transparency, and UI assets. Use type: 'jpeg' where a smaller photographic file matters; JPEG does not preserve transparency. The package can write to output or return image data when no output path is supplied.
Concurrency and repeatable rendering
For batch work, use the documented concurrency controls rather than launching an unlimited number of Chromium pages. Reuse a controlled browser process where your deployment allows it, cap simultaneous jobs, and place a queue in front of conversion. Set explicit viewport dimensions, install the fonts your design needs, and pin your package/browser versions if identical output matters.
Make external fonts, images, and CSS reliable
- Fonts: A missing web font causes fallback metrics and changed line breaks. Bundle the font, preload it, or wait for
document.fonts.readyin a hook. - Images: Use reachable HTTPS URLs or data URLs and wait for the images to complete. Private URLs need credentials or a server-side asset strategy.
- Cross-origin content: Browser security rules still apply. Canvas-based approaches can fail on cross-origin or tainted content; configure CORS or inline the asset.
- Layout: Give the target a deliberate width, height, margin, and background. Responsive designs otherwise use the default viewport and may wrap differently than expected.
- Animation: Disable transitions and animation when deterministic output is required; otherwise the capture can occur at different frames.
Browser-side option: html-to-image
html-to-image is designed for an existing browser DOM node. It clones the node, copies computed styles, embeds fonts and images, serializes through SVG foreignObject, and rasterizes to a canvas.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →import { toPng } from 'html-to-image';
const node = document.querySelector('#card');
const dataUrl = await toPng(node, {
backgroundColor: '#ffffff',
pixelRatio: 2,
cacheBust: true
});
const link = document.createElement('a');
link.download = 'card.png';
link.href = dataUrl;
link.click();
Its options include background color, width and height, canvas dimensions, pixel ratio, cache busting, font embedding, and image placeholders. Very large DOM trees can exceed data-URL limits. Cross-origin images or fonts without appropriate CORS headers may taint the canvas and prevent a successful export. This is a browser-DOM tool, not a replacement for server-side Chromium when your input is only an HTML string.
Use Puppeteer directly when you need browser control
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setViewport({ width: 1200, height: 800, deviceScaleFactor: 2 });
await page.setContent(`<html><body><h1>Hello</h1></body></html>`, {
waitUntil: 'networkidle0'
});
await page.screenshot({ path: 'puppeteer.png', fullPage: true });
} finally {
await browser.close();
}
Puppeteer’s official API supports page screenshots that return a base64 string or Uint8Array, as well as element screenshots. Choose it when you need request interception, authentication flows, custom browser flags, or fine-grained page lifecycle control that a wrapper does not expose.
Rank #3
Use Playwright for multi-engine coverage
import { chromium } from 'playwright';
const browser = await chromium.launch();
try {
const page = await browser.newPage({ viewport: { width: 1200, height: 800 }, deviceScaleFactor: 2 });
await page.setContent('<h1>Playwright</h1>');
await page.screenshot({ path: 'playwright.png', fullPage: true });
} finally {
await browser.close();
}
Playwright’s screenshot API infers PNG from the .png extension and supports full-page, element, quality, viewport, and CSS/device-scale options. Its value is browser-engine choice and a broad automation API; its trade-off is another browser installation and a larger operational surface.
Or skip the browser setup
ScreenshotNeo is a hosted screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report X-Page-Verdict and X-Billed.
Example using cURL (see the ScreenshotNeo documentation for all options):
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Equivalent Node.js and Python calls:
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}`);
ScreenshotNeo also provides full-page and CSS-selector captures, dark mode, device presets and custom viewports, retina scale, PDF controls, custom CSS/JavaScript, clicks, waits, request blocking, headers/cookies/user agents, timezone and geolocation, transparent backgrounds, resizing, selectable-TTL caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to 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 shots; yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account to try it.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting common failures
“Cannot find Chromium” or launch errors
Run the package installation again so Puppeteer’s browser download completes, verify the container has executable shared libraries, and check your sandbox flags and permissions. Do not assume a system Chrome path unless you configure it explicitly.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Rank #4
The image is blank or only partly rendered
Wait for the specific application selector rather than relying only on a short delay. Confirm that scripts are allowed, remote assets resolve from the server, and the selected element actually has dimensions.
Fonts or images differ from the webpage
Inspect network access and CORS, bundle critical assets, wait for font and image completion, and set a fixed viewport. A headless process cannot load assets that require a browser session unless you provide cookies or authorization.
The job times out
Use a finite, appropriate timeout; replace perpetual network-idle waits with a readiness selector; block unnecessary requests; and investigate long-running third-party scripts.
html-to-image throws a security or canvas error
Check for cross-origin images, fonts, or iframes. Serve them with CORS headers, inline them, or move the capture to a server-side browser.
Recommended Free Tools
Batch conversion exhausts memory
Limit concurrency, close pages and browsers in finally blocks, avoid retaining base64 strings, and stream or upload buffers promptly. Large full-page captures consume more memory than viewport shots.
Operational checklist
- Choose server HTML (
node-html-to-image) or an existing DOM (html-to-image). - Set a fixed viewport, target selector, output type, and background.
- Make fonts, images, and authenticated resources available.
- Wait for a real readiness condition and enforce a timeout.
- Cap concurrency and clean up browser resources.
- Test transparent, long, asset-heavy, and failure cases before production.
- Record package and browser versions when reproducibility matters.
Frequently Asked Questions
Can I convert HTML to PNG without opening a visible browser?
Yes. node-html-to-image runs Puppeteer in headless mode, so no visible browser window is required.
Which package should I use for an HTML string in Node.js?
Start with node-html-to-image; it is the shortest documented path from an HTML string to a PNG file or buffer.
Why does my exported image miss web fonts?
The rendering process may finish before fonts load, or the server may not be able to fetch them. Bundle or authorize the fonts and wait for document.fonts.ready.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Is html-to-image suitable for server-side HTML conversion?
It is primarily for an existing browser DOM node. For a server-side string, use node-html-to-image, Puppeteer, or Playwright.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




