ScreenshotNeo

BlogComparisons

Best Free HTML to Image Converters for Web Developers

Compare free HTML-to-image APIs with browser-side capture. Choose by input type, rendering fidelity, output, quota, and how much infrastructure you want to manage.

By the ScreenshotNeo team4 October 202612 min read

“HTML to image” can mean three different jobs: render HTML and CSS you supply, capture a live URL, or export an element from a page already open in a browser. The best free option depends on which input you have and whether you need a hosted result or a user-triggered export.

For hosted URL screenshots, ScreenshotNeo is the first service to consider: it removes cookie banners, popups, and chat widgets before capture, bills only clean shots, and its paid plans start at $5 for 3,000 shots. For generating an image from your own HTML/CSS, compare HTML/CSS to Image (HCTI) with the workflow and plan limits below. For exporting a selected element within the visitor’s current page, html2canvas avoids a hosted rendering API, with fidelity and cross-origin limitations.

Free-plan figures below were published by the services and observed on October 3, 2026; plans can change. They are not the result of independent testing.

Quick comparison

Option Best fit Published free allowance Key constraints
ScreenshotNeo Hosted screenshots of public URLs, PDFs, and HTML/CSS-to-image workflows 1,000 shots/month, no card API key required; clean captures only are billed. Has an MCP server for AI agents.
HTML/CSS to Image (HCTI) Hosted rendering from supplied HTML/CSS or a URL; reusable templates 50 images/month, no card Free plan allows five templates per organization and no media upload. Keep API credentials secret.
ScreenshotOne Hosted URL screenshots, HTML rendering, and PDF 100 screenshots/month The provider says successful renders not served from cache count toward quota; verify current plan terms and input requirements.
html2canvas Export an element from the currently open page in the user’s browser Open source; no hosted service quota Reconstructs an image from DOM and styles rather than taking a literal browser screenshot. CSS support is incomplete; cross-origin assets need care.

Browserless is another possible direction for teams already running browser automation, but the research reviewed here did not verify its primary documentation, pricing, or screenshot API. Check those details before choosing it.

Choose by the input you have

  • You supply a markup fragment: use a hosted HTML/CSS renderer such as HCTI or ScreenshotNeo’s HTML/CSS-to-image capability. This works well for generated cards, reports, and social graphics.
  • You have a public URL: use a hosted screenshot API. The service opens the page remotely and returns an image or PDF. ScreenshotNeo supports PNG, JPEG, and WebP screenshots, as well as PDF.
  • The page is already open in the user’s browser: use a browser-side library such as html2canvas to export a selected element. The page’s assets and browser environment are already present, but the result may differ from what the browser actually painted.
  • You need recurring or bulk capture: compare quotas, caching rules, concurrency and storage behavior, and whether the provider has an asynchronous or bulk workflow. ScreenshotNeo supports caching with a chosen TTL, asynchronous jobs with signed webhooks, and bulk capture of up to 100 URLs per call.

Hosted rendering versus browser-side capture

A hosted API accepts HTML/CSS or a URL and renders it remotely. HCTI documents either a url or html input (not both), optional CSS, PNG/JPG/WebP/PDF output, and HTTP Basic authentication using an API ID and API key. Its free plan offers 50 images monthly, up to five templates per organization, and no media upload. The vendor lists displayed starting prices of $14/month for Basic, $149/month for Pro, and $749/month for Scale; the pricing page says image volume is selected, so those figures should not be read as an arbitrary included quota. Review its current pricing before adopting.

ScreenshotOne advertises 100 free screenshots per month, including HTML rendering and PDF. It says successful renders that are not served from cache count toward quota. Confirm how your intended input is counted and what happens at the limit.

A client-side tool takes a different approach. html2canvas traverses the current DOM and styles, then paints a canvas representation. Its documentation explicitly cautions that the result may not match the real page because it does not take an actual screenshot. Unsupported CSS and cross-origin content can change or omit parts of the result. It is a browser library, not a Node.js server renderer.

Neither approach should be assumed pixel-perfect. Test the actual fonts, layout, images, browser, and output size that matter to your application.

Use html2canvas to export an element in the browser

This example captures an element with the ID card and downloads a PNG. Add html2canvas to a browser project using your package manager, or load the library through a script tag as shown here.

<div id="card">
  <h1>Monthly report</h1>
  <p>Revenue increased 8%.</p>
</div>
<button id="export">Download PNG</button>
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
<script>
document.getElementById('export').addEventListener('click', async () => {
  const element = document.getElementById('card');
  try {
    const canvas = await html2canvas(element, {
      backgroundColor: '#ffffff',
      scale: window.devicePixelRatio || 1,
      useCORS: true
    });
    const link = document.createElement('a');
    link.download = 'monthly-report.png';
    link.href = canvas.toDataURL('image/png');
    link.click();
  } catch (error) {
    console.error('Could not export the card:', error);
  }
});
</script>

The versioned CDN URL makes the example reproducible, but production applications should pin and manage the dependency according to their own supply-chain policy. The useCORS option asks the library to attempt CORS-enabled image loading; it cannot override a remote server’s access policy. Review the html2canvas configuration and supported features for the options and CSS properties relevant to your page.

Options and edge cases

  • scale controls output resolution. A larger scale makes a sharper image, while increasing memory use and output size.
  • backgroundColor sets the canvas background; use null when a transparent background is required and supported by the target output.
  • useCORS attempts to load images using cross-origin requests. The asset server must return suitable CORS headers. A browser security restriction cannot be bypassed from JavaScript.
  • allowTaint permits drawing cross-origin images that taint the canvas, but a tainted canvas cannot be read back through APIs such as toDataURL. For a downloadable image, this is usually not a fix for missing CORS permission.
  • ignoreElements can omit unwanted DOM nodes, and onclone can adjust the cloned document before rendering. Use these for export-only styling or to hide controls.
  • Wait for fonts and images to load before capture. Lazy-loaded content may not exist until it enters a loaded region; scroll or otherwise trigger it before rendering if it must appear.
  • Long elements and high scale values can exceed browser canvas or memory limits. Capture a smaller element, reduce scale, or use a hosted full-page renderer for long pages.

Use a hosted HTML/CSS renderer with cURL, Python, and Node.js

For HCTI, create an account and obtain an API ID and key. Keep both on a server or in a secret manager; do not put them in frontend JavaScript or a public repository. Its documented API accepts HTML or a URL, plus optional CSS, and uses HTTP Basic authentication. The following is a minimal request pattern; check the current HCTI endpoint and exact request field names in its API documentation before using it.

curl -u "$HCTI_API_ID:$HCTI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html":"<div style=\"padding:24px;font:24px sans-serif\">Hello image</div>","css":"body { margin: 0; }"}' \
  "https://hcti.io/v1/image"

The provider’s response includes a generated image reference; inspect the response, then download the returned image URL if your workflow needs a local file. Do not assume an API response URL is permanent: confirm retention and storage terms.

Equivalent Python request pattern using HTTP Basic authentication:

import os
import requests

api_id = os.environ["HCTI_API_ID"]
api_key = os.environ["HCTI_API_KEY"]
payload = {
    "html": '<div style="padding:24px;font:24px sans-serif">Hello image</div>',
    "css": "body { margin: 0; }",
}
r = requests.post(
    "https://hcti.io/v1/image",
    json=payload,
    auth=(api_id, api_key),
    timeout=60,
)
r.raise_for_status()
print(r.json())

And Node.js using built-in fetch:

const id = process.env.HCTI_API_ID;
const key = process.env.HCTI_API_KEY;
const credentials = Buffer.from(`${id}:${key}`).toString('base64');
const response = await fetch('https://hcti.io/v1/image', {
  method: 'POST',
  headers: {
    'Authorization': `Basic ${credentials}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    html: '<div style="padding:24px;font:24px sans-serif">Hello image</div>',
    css: 'body { margin: 0; }'
  })
});
if (!response.ok) throw new Error(`Render failed: ${response.status} ${await response.text()}`);
console.log(await response.json());

HCTI’s FAQ distinguishes plan image credits from limits on management operations. An HTTP 429 can indicate exhausted image credits or a management-operation throttle; inspect the response and current FAQ rather than treating every 429 as the same condition.

Decision guide by use case

Generated cards, badges, and social images

If your backend produces a known HTML fragment, a hosted renderer gives you a remote rendering workflow without asking each visitor’s browser to reproduce the capture. Compare how the service handles fonts, images, templates, output formats, and retained URLs. HCTI’s free allowance is 50 images monthly with five templates per organization and no media upload. ScreenshotNeo supports HTML/CSS to image and its published free plan includes 1,000 shots monthly, but use the docs to confirm the request fields for your exact markup workflow.

Screenshot a public page

Use a URL screenshot API when the source is a page on the web rather than markup you control. Check viewport versus full-page behavior, lazy images, waits, consent overlays, bot checks, output format, and cache accounting. A browser-side DOM library only sees the current page and does not provide a remote URL-capture service.

Let a user export part of an app

Use html2canvas when users should export content already rendered in their own browser and you can validate the supported CSS and assets. Keep the captured area bounded and test on the browsers your app supports. A hosted API may be a better fit if browser differences, credentials, or remote scheduling belong on the server.

Automated or higher-volume workflows

Estimate monthly renders, retries, and expected cache hits before selecting a free tier. ScreenshotOne’s stated quota accounting excludes cache-served renders from its count. ScreenshotNeo says cache hits cost nothing and supports a TTL you choose, async jobs with signed webhooks, and bulk capture of 100 URLs per call. For HCTI, the observed pricing page displayed starting plan prices of $14, $149, and $749 monthly with volume selection; check current terms for the quota you need.

Or skip the browser setup

For a URL screenshot, one GET request returns the image. This cURL example saves a WebP screenshot:

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)
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 failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

See the ScreenshotNeo documentation for API options. Cookie banners, popups, and chat widgets are removed 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 free.

Performance, reliability, and cost

  • Browser-side memory: canvas size grows with both dimensions and scale. Prefer a bounded element, moderate scale, and a download format suited to the content. Huge canvases may fail even when the page itself renders correctly.
  • Hosted latency: a remote render includes network and browser work. Avoid making a user-facing request wait indefinitely; use timeouts, queue or async workflows for bulk jobs, and cache stable inputs where appropriate.
  • Retries: retry transient network failures with a small bounded backoff. Avoid retrying invalid input or authentication failures. Check whether a retry consumes quota under the provider’s current policy.
  • Repeatability: fonts, remote assets, animation, dynamic content, viewport, timezone, and timing affect output. Set deterministic inputs where supported, wait for fonts/data, and disable or freeze animation in export styles.
  • Cost: count expected successful renders, not just page views. Include regenerated variants, retries, and cache misses. Free allowances and billing definitions are vendor-published and can change; verify them before launch.
  • Credentials: never expose hosted API secrets to the browser. Put calls behind your server when credentials are required, and apply your own access controls to prevent a public endpoint from being abused.

Troubleshooting

Symptom Likely cause What to do
External image is missing in html2canvas Remote host does not permit CORS, or image has not loaded Use assets that return compatible CORS headers, wait for image loading, or use a server-side renderer that can fetch the asset. A browser library cannot bypass the remote host’s policy.
Canvas export throws a security error A cross-origin image tainted the canvas Ensure CORS is correctly configured and use useCORS; avoid reading a tainted canvas. Do not treat allowTaint as a way to make a tainted canvas downloadable.
Shadows, gradients, or layout differ The library does not implement a CSS feature, or the page uses browser-specific rendering Check html2canvas’s supported feature list, simplify export-only styles, or choose a real browser screenshot workflow and validate the target page.
Text uses a fallback font Web font has not loaded before capture, or the hosted renderer cannot reach it Wait for document.fonts.ready before client capture; for remote rendering, verify font URL access and render timing.
Images or content are blank in a full-page capture Lazy loading or application data has not completed Trigger lazy content, wait for a stable selector or network state when the service supports it, and check the final page height.
Hosted API returns 401 or 403 Missing, incorrect, or improperly encoded credentials Check API ID/key pairing and auth format; keep secrets on the server and consult the provider’s current auth docs.
Hosted API returns 429 Free or paid quota exhausted, or a separate management throttle Read the response body and current plan/FAQ. For HCTI, image-credit exhaustion and management-operation throttling are distinct possibilities.
Hosted render returns an error or blank page URL is inaccessible, blocked by a bot check, redirects unexpectedly, or page load timed out Check the URL from a remote environment, authentication and redirects, then configure waits or headers if supported. Inspect verdict/billing headers where available.
Output is too large or capture fails on a long page Canvas or renderer memory/dimension limit Reduce scale, resize output, capture a smaller region, or split the page. Use a full-page service for long documents when suitable.

Pre-adoption checklist

  1. Confirm the input mode: supplied HTML, public URL, or current-page element.
  2. Render representative pages with your real fonts, external images, and CSS; inspect the output manually.
  3. Test viewport and full-page behavior, lazy content, transparency, and the target output format.
  4. Estimate monthly volume including cache misses and retries, then verify current quota and overage behavior.
  5. Decide where output files live and confirm link retention, privacy, and deletion terms with the provider.
  6. Keep API keys server-side and restrict any endpoint that can initiate paid renders.

FAQ

Can I convert HTML to PNG without a paid API?

Yes. A browser-side library can export an element from the page without a hosted render quota, and hosted APIs publish free monthly allowances. Check current terms and validate fidelity before relying on either path.

Is html2canvas a screenshot tool?

It creates a canvas representation from DOM and style information; it does not take a literal screenshot of the browser’s rendered pixels. That difference explains why CSS and cross-origin support matter.

Can I use html2canvas in Node.js?

It is designed for a browser DOM, so it is not the choice for server-side Node rendering. Use a hosted renderer or a browser automation setup for server workflows.

Which option has the largest listed free allowance here?

ScreenshotNeo lists 1,000 shots per month without a card, but a larger allowance does not make it the right tool for every input model. Choose based on whether you need markup rendering, URL capture, or an in-browser element export.

Are the free plans permanent?

No plan terms should be assumed permanent. Recheck provider pricing and quota pages when selecting a service and before deploying a workflow.