ScreenshotNeo

BlogHow-to

How to Embed HTML as an Image

HTML is a document, not an image. Learn how to render a page or element into PNG, JPEG, or WebP, with browser, JavaScript, SVG, and API methods.

By the ScreenshotNeo team29 September 202611 min read

How to Embed HTML as an Image

HTML is a document format, not an image format. To turn HTML into a PNG, JPEG, or WebP, render it in a browser and capture the pixels, convert a DOM element with a client-side library, or package HTML in SVG with foreignObject and render that SVG. The right choice depends on whether you need a whole live webpage, one element in an existing app, or a portable graphic.

If you meant showing an image inside a web page, use the normal HTML <img> element; that is different from converting HTML into an image. This guide covers conversion methods, runnable examples, their limits, and when a hosted renderer is useful.

1. Choose the right method

Need Good starting point Watch for
Show an existing image on a page HTML <img> Alternative text, responsive sizing, and image availability
Export one element from a running web app A DOM-to-image library such as html-to-image Fonts, cross-origin assets, canvas tainting, and output size
Capture a live page or URL on a server Browser automation or a hosted screenshot API Script timing, authentication, viewport, and operational limits
Bundle a simple HTML fragment into SVG SVG foreignObject Image-context restrictions and browser support in the target use

A browser screenshot records what a browser rendered. A DOM-to-image library instead clones a selected node, reconstructs styles and assets, and renders the result. These approaches can produce different output; neither guarantees pixel-perfect results for every page and asset combination.

A screenshot captures the pixels produced after a browser renders HTML, CSS, and assets.
A screenshot captures the pixels produced after a browser renders HTML, CSS, and assets.

2. Convert a DOM element in a web app

For a card, chart, receipt, or other element already present in a browser app, a DOM-to-image library avoids capturing the surrounding page. The html-to-image package documents a workflow that clones the node, copies computed styles, recreates pseudo-elements, embeds fonts and image URLs, and serializes the clone into SVG with foreignObject. For PNG output, it draws the serialized SVG to a canvas.

Runnable browser example

Install the package in your application:

npm install html-to-image

Give the target element an ID, then call toBlob after the page has rendered:

import * as htmlToImage from 'html-to-image';

const node = document.querySelector('#export-card');
if (!(node instanceof HTMLElement)) {
  throw new Error('Could not find #export-card');
}

const blob = await htmlToImage.toBlob(node, {
  pixelRatio: 2,
  backgroundColor: '#ffffff'
});
if (!blob) throw new Error('Image conversion returned no data');

const link = document.createElement('a');
link.download = 'card.png';
link.href = URL.createObjectURL(blob);
link.click();
URL.revokeObjectURL(link.href);

Example markup and styling:

<article id="export-card">
  <h1>Monthly report</h1>
  <p>Revenue: $12,400</p>
</article>
#export-card {
  width: 640px;
  padding: 32px;
  color: #172033;
  background: white;
  font: 16px/1.5 system-ui, sans-serif;
}

The library also provides data URL and pixel-data output methods. A blob is usually practical for a downloadable file because it avoids placing a large base64 string directly in a URL. Confirm the installed package version’s options in its package documentation.

Make the captured node deterministic

  1. Wait until the component has rendered its final content.
  2. Wait for required web fonts with await document.fonts.ready.
  3. Ensure images have loaded; an image can be checked with img.complete and img.naturalWidth.
  4. Choose a fixed width and background color if the output must be consistent.
  5. Use a moderate pixel ratio. A ratio of 2 doubles each dimension and therefore multiplies pixel count by four.
  6. Inspect the saved file at its actual destination size, including on the browsers you support.

Cross-origin images may not be readable by the conversion path unless the remote server allows cross-origin access and the image is requested appropriately. Canvases drawn from disallowed cross-origin content become tainted; the package documentation calls out tainted canvas elements as a failure case. Very large DOMs may also exceed data URI size limits. Reduce the captured region, resize assets, or move the capture to a browser screenshot workflow if reconstruction is not viable.

3. Capture a whole webpage with a browser

For a live URL, a browser screenshot is often the most direct way to convert the rendered page. With Playwright, install its package and browser:

npm install playwright
npx playwright install chromium

Save this as capture.mjs and run node capture.mjs https://example.com:

import { chromium } from 'playwright';

const url = process.argv[2];
if (!url) throw new Error('Usage: node capture.mjs <url>');

const browser = await chromium.launch({ headless: true });
try {
  const page = await browser.newPage({
    viewport: { width: 1440, height: 1000 },
    deviceScaleFactor: 1
  });
  await page.goto(url, { waitUntil: 'networkidle', timeout: 60000 });
  await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
  await browser.close();
}

This is a starting point, not a universal wait strategy. Some sites keep connections open, poll in the background, or load content only after scrolling. If network idle never occurs, wait for a specific selector or use a short delay after navigation. If content appears only as the page scrolls, scroll through the relevant area before capture. For a single region, locate an element and use an element screenshot instead of fullPage.

Authentication and controlled rendering

For a page that needs a login, create a browser context with the required cookies or use an authenticated test account. Avoid putting secrets in a URL that might be logged. Set viewport and device scale explicitly; otherwise layout changes with the default viewport and environment. A full-page image can be very tall, so consider whether a viewport capture, selected element, or PDF is a better output for the intended reader.

4. Use SVG foreignObject for a small HTML fragment

SVG 2 provides foreignObject to include content from another namespace, such as an HTML fragment, within SVG. This can be useful when you want to construct a self-contained graphic, but an SVG wrapper is not the same as a fully interactive web page.

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="240">
  <foreignObject x="0" y="0" width="600" height="240">
    <div xmlns="http://www.w3.org/1999/xhtml"
         style="box-sizing:border-box;width:600px;height:240px;padding:24px;background:#f2f5fa;font:20px sans-serif">
      <h1>A graphic made from HTML</h1>
      <p>Render this SVG in a supported browser context.</p>
    </div>
  </foreignObject>
</svg>

To save a PNG, serialize the SVG, create a blob URL, load it into an Image, draw it to a canvas, then export the canvas with toBlob. This conversion can fail if referenced resources cannot load or if the drawing taints the canvas. SVG used in an image context has additional restrictions: JavaScript may be disabled and external resources such as images or stylesheets may not load. Inline required assets when appropriate and test in the actual embedding context. See the W3C SVG embedded content section, MDN’s SVG as an image guide, and MDN’s foreignObject reference.

5. Display an already-created image in HTML

If you have a PNG or other image file and only want it in a page, use the HTML image element. Give it useful alternative text when the image carries information, and an empty alt value when it is decorative.

<img src="/images/report.png" alt="Monthly revenue report" width="640" height="360">

For responsive display, constrain its width with CSS:

img { max-width: 100%; height: auto; }

This embeds a reference to an image file in the page; it does not convert HTML markup into pixels. For technical details on SVG image references, see the SVG 2 embedded content specification and MDN’s SVG image element reference.

6. Select a hosted renderer for repeatable server captures

A hosted renderer is useful when captures must run on a server, a scheduled job, or a system without a browser installation. Check whether the service accepts a URL or raw markup, whether page scripts execute, how it waits for dynamic content, what formats and dimensions it supports, and how authentication and failures are handled. Endpoints can differ even within one service: the html2img documentation, for example, describes different JavaScript behavior for its URL screenshot and HTML endpoints. Consult its current JavaScript support documentation and getting started guide for its vendor-specific details.

A clean capture removes common overlays before saving the rendered page.
A clean capture removes common overlays before saving the rendered page.

For a list or recommendation of screenshot services, ScreenshotNeo is the first service to consider here: cookie banners, popups, and chat widgets are removed before capture, and only clean shots are billed.

7. Or skip the browser setup

ScreenshotNeo accepts a URL in one GET request and returns a clean PNG, JPEG, WebP, or PDF. Its API documentation describes the available parameters. Here is the supplied cURL call; replace the URL and API key:

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

The response file extension and requested output format should match the format you choose in the API options. Equivalent Python and Node.js calls:

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)
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 Bun.write('shot.webp', res);

Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed; response headers identify the page verdict and billing status. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for the free plan.

8. Relevant options and output choices

For any capture workflow, decide these settings before automating it:

  • Area: viewport, full page, or one element. Full pages may be long; element capture avoids unrelated content.
  • Dimensions: viewport width and height affect responsive layout. Device scale affects sharpness and memory.
  • Format: PNG preserves sharp edges and transparency; JPEG is often smaller for photographs but has lossy compression; WebP supports modern compressed image workflows. Confirm your destination supports the chosen type.
  • Background: set a solid background for predictable output, or use transparency only when the target format and renderer support it.
  • Timing: wait for navigation, a selector, fonts, images, or app data. Network idle is not always a reliable signal for sites with ongoing traffic.
  • Privacy: captures can contain account data, personal information, or secret page content. Restrict access to files and avoid logging credentials or sensitive query parameters.

ScreenshotNeo supports full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF page settings, custom CSS and JavaScript, click-before-capture, selector hiding, selector/delay/network-idle waits, request and resource blocking, headers, cookies, user agent, authorization, timezone and geolocation, transparent background, resizing, configurable cache TTL, signed public image links, asynchronous jobs with signed webhooks, bulk capture up to 100 URLs per call, usage API, and an OpenAPI spec. Its parameter names also accept names used by other screenshot APIs, making migration simpler. Review the docs for exact current parameter syntax.

9. Troubleshooting common failures

Symptom Likely cause What to try
Fonts or spacing differ Fonts or styles were not loaded or reproduced Wait for document.fonts.ready; verify font URLs and computed styles; fix capture dimensions.
Images are missing Cross-origin request denied, image not loaded, or SVG image-context restrictions Check the image request and CORS headers; wait for image completion; inline resources where appropriate.
Canvas export throws a security error A canvas contains cross-origin pixels and is tainted Use assets with permitted CORS, omit the tainted canvas, or capture with browser automation instead.
Capture is blank or clipped Wrong selector, zero-sized element, early capture, or dimensions too small Check the selected node’s bounds, wait for content, and set the intended viewport or element size.
Page never reaches network idle Polling, streaming, analytics, or persistent connections Wait for a meaningful selector or use a bounded delay instead of network idle.
SVG works inline but fails as an image Image contexts can restrict scripts and external resources Inline required styles and assets, remove script dependencies, and test the final embedding context.
Conversion runs out of memory or data URL limits Huge DOM, high pixel ratio, or large embedded assets Capture a smaller node, reduce output scale, compress source images, or use a file/blob workflow.

10. Performance, reliability, and cost

Client-side conversion uses the visitor’s browser and machine. It avoids sending the DOM to a rendering server, but the user’s browser must have enough memory for the cloned content, images, SVG, and output canvas. A high pixel ratio increases pixel count quadratically. Keep capture regions bounded and avoid regenerating an image on every small UI update.

Browser automation shifts rendering to infrastructure you operate. You control browser versions, concurrency, timeouts, and retries, but must provision and maintain browser processes. Reuse a browser process for batches where practical while isolating pages and contexts. Set hard timeouts and close resources in a finally block. Retry transient navigation failures selectively; repeated retries do not fix blocked assets, bad selectors, or deterministic script errors.

A hosted API avoids managing browser binaries and lets a team call a consistent endpoint, but service plans and capture semantics determine the cost and behavior. Check billing treatment for failed pages, caching, limits, output types, and concurrency. ScreenshotNeo states that bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and returns X-Page-Verdict and X-Billed headers. Its listed monthly plans are Free: 1,000 shots; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan. Recheck the product page before budgeting because prices and service details can change.

Frequently asked questions

Can I make an image from HTML without a browser?

Not in the general case. HTML needs a rendering engine to compute layout, fonts, and styles. SVG foreignObject can carry an HTML fragment, but it still depends on a renderer and has image-context restrictions.

Can a PNG remain interactive?

No. A raster image contains pixels, not live HTML controls or links. Keep the original page for interaction and use an image as a snapshot or preview.

Should I capture HTML or a URL?

Use raw markup when you own the content and want to render a known fragment. Use a URL when the browser must load the actual site, its scripts, and its styles. Confirm the chosen renderer’s behavior for both modes.

What should I use for a printable multi-page result?

Use PDF output when pagination, paper size, margins, or page ranges matter. A tall screenshot is a single raster surface and is often awkward to print or read.