How to Capture HTML Snippets as Images with a Screenshot API
Render supplied HTML or capture one element from a live page. Choose the right API input, set the viewport and format, and save the image bytes.
To turn an HTML snippet your application already has into an image, use a screenshot endpoint that explicitly accepts raw HTML and send the markup in the documented request body. To capture a particular element from an existing website, send the page URL and a CSS selector to an endpoint that supports selector capture. These are different inputs and workflows; a URL-only screenshot API cannot render markup you send it.
This guide shows both approaches, explains the rendering choices that affect the result, and covers saving the returned image bytes. The provider-specific examples below use Screenshot API for raw HTML and selector capture, based on its documented contract. See its API guide for current authentication, parameters, size limits, and endpoint details.
1. Choose raw HTML or a live-page element
| Your input | What the API does | Use it when |
|---|---|---|
Raw HTML in an html field |
Renders the markup supplied with the request | Your app generates a card, receipt, chart, email preview, or other snippet that is not hosted as a page |
A page url plus a CSS selector |
Navigates to the page and captures the matching element | The content is already rendered on a website and you want only one component |
Screenshot API’s guide documents exactly one of url or html for its screenshot request, and a successful response is raw image bytes. Do not assume that every provider that accepts URLs also accepts HTML. Cloudflare Browser Run documents both HTML and URL inputs, as well as selector capture; its endpoint documentation says, “You must provide either url or html:” (Cloudflare screenshot endpoint).
2. Render a supplied HTML snippet
Screenshot API documents a JSON POST request with an html value, viewport dimensions, and output format. This illustrative request follows its documented shape; it has not been executed. Use the provider’s current endpoint and authentication instructions, and check the current HTML size and viewport limits before sending production requests.
curl -X POST https://screenshotapis.org/v1/screenshot \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"html":"<div style=\"font: 24px sans-serif; padding: 24px\">Hello from HTML</div>","viewport_width":600,"viewport_height":300,"format":"png"}' \
--output snippet.png
The response is binary image data, so save it to a file or stream it to the next step in your application. Do not parse a successful image response as JSON. Keep the API key on a server or in a secret manager; do not put it in public page markup.
Python example
This example uses Python’s standard library to make the documented HTTP request and save the response. Replace the endpoint or authentication only according to the provider’s current instructions.
import json
import urllib.request
api_key = "YOUR_API_KEY"
payload = {
"html": '<div style="font: 24px sans-serif; padding: 24px">Hello from HTML</div>',
"viewport_width": 600,
"viewport_height": 300,
"format": "png",
}
request = urllib.request.Request(
"https://screenshotapis.org/v1/screenshot",
data=json.dumps(payload).encode("utf-8"),
headers={
"X-Api-Key": api_key,
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(request, timeout=90) as response:
image_bytes = response.read()
content_type = response.headers.get("Content-Type", "")
if not content_type.startswith("image/"):
raise RuntimeError(f"Expected image bytes, got {content_type}: {image_bytes[:500]!r}")
with open("snippet.png", "wb") as image_file:
image_file.write(image_bytes)
Node.js example
Node’s built-in fetch can send the JSON request. The response must be treated as bytes, not text.
const payload = {
html: '<div style="font: 24px sans-serif; padding: 24px">Hello from HTML</div>',
viewport_width: 600,
viewport_height: 300,
format: 'png',
};
const res = await fetch('https://screenshotapis.org/v1/screenshot', {
method: 'POST',
headers: {
'X-Api-Key': process.env.SCREENSHOT_API_KEY ?? 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
signal: AbortSignal.timeout(90_000),
});
if (!res.ok) {
throw new Error(`Screenshot request failed: HTTP ${res.status} ${await res.text()}`);
}
const contentType = res.headers.get('content-type') ?? '';
if (!contentType.startsWith('image/')) {
throw new Error(`Expected image bytes, got ${contentType}`);
}
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(({ writeFile }) => writeFile('snippet.png', image));
3. Capture one element from a live page
When the desired HTML is already on a webpage, send that page’s URL and a CSS selector. This navigates to the URL and captures the rendered match; it does not send your raw snippet as HTML. Screenshot API documents selector capture. Confirm the current request field names and behavior in its API reference.
curl -X POST https://screenshotapis.org/v1/screenshot \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/products","selector":".product-card","viewport_width":1200,"viewport_height":900,"format":"png"}' \
--output product-card.png
Use a selector that identifies one visible element after the page has rendered. If the page creates the element with JavaScript, wait for its content before capture. Cloudflare documents gotoOptions.waitUntil and waitForSelector for pages where the default load timing can capture too early (Cloudflare wait options).
4. Set dimensions, format, and rendering expectations
- Viewport: Choose width and height for the intended output composition. A narrow viewport can trigger mobile layouts; a wide viewport can change wrapping and component dimensions. Screenshot API documents viewport width and height parameters. Cloudflare’s documented viewport default is 1920×1080, but defaults differ between providers.
- Format: Choose PNG for crisp text and graphics, JPEG when a lossy photo format is acceptable, or WebP when supported by the consumer. Screenshot API documents PNG, JPEG, and WebP. Its quality parameter applies to JPEG and WebP, not PNG; verify exact current parameter names in its guide.
- CSS and assets: Inline critical CSS for self-contained snippets where practical. External stylesheets, web fonts, and images must be reachable by the renderer, and load timing can affect what appears. Do not assume arbitrary scripts will run successfully or that output will be pixel-identical across browser environments.
- Dynamic content: For a live page with client-side rendering, wait for a meaningful selector or the provider’s supported page-load condition. A fixed delay can help when no selector is available, but it adds latency and may still be too short or longer than needed.
- Selector matching: Check that the selector exists, is visible, and identifies the intended element. Providers may differ in whether a nonmatching selector is an error, a blank capture, or a fallback.
Screenshot API’s guide documents a 5 MB raw HTML limit and viewport ranges. Treat these as provider parameters, not universal screenshot API limits, and confirm their current values before relying on them.
5. Alternative tools and selection criteria
ScreenshotNeo is a website screenshot API and MCP server for developers; it accepts a URL for a screenshot or PDF, and supports capturing an element by CSS selector. For a raw HTML snippet, verify the documented input contract before choosing any URL-based tool. For local browser capture, shot-scraper’s manual documents local HTML-file capture, CSS selector selection, waits, and several output formats; it is a local CLI rather than a hosted API.
Compare tools by whether they accept raw HTML or only a URL, whether they can select an element, what waits and viewport controls they offer, supported formats and dimensions, where rendering runs, authentication requirements, and current usage and security terms. Documentation establishes supported options, not universal rendering success, pixel-perfect output, or comparative performance.
6. Or skip the browser setup
For a live webpage, ScreenshotNeo takes one GET request with a URL and returns a PNG, JPEG, WebP, or PDF. Its API is URL-based; use a browser HTML endpoint such as the raw-HTML workflow above when the input is markup that has not been published at a URL. See the ScreenshotNeo API documentation.
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}`);
ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status. Its MCP server provides 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. All features are on every plan.
Start free with 1,000 screenshots a month and no card.
7. Reliability, performance, and cost
- Keep requests bounded: Set a client timeout appropriate to your workflow. Large markup, slow external assets, and client-rendered pages can all extend capture time; the dossier provides no comparative timing benchmark.
- Handle failures explicitly: Check the HTTP status and content type before writing bytes as an image. Log a request identifier if the provider supplies one, but avoid logging API keys or sensitive HTML.
- Retry selectively: A retry can help with transient network or service errors. Do not retry authentication errors, invalid input, oversized markup, or a selector that never matches without changing the request. Use a retry limit and backoff so an outage does not multiply load or spend.
- Watch payload and assets: Keep raw HTML within the provider’s documented limit. Large embedded data URLs increase request size; remote assets add dependencies and can be slow or unavailable.
- Estimate cost from current terms: The research reviewed for this guide did not establish comparable prices for Screenshot API, Cloudflare Browser Run, or shot-scraper, so check each provider’s current billing model. A local CLI moves browser execution into your own environment; account for the compute and maintenance you operate.
8. Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| HTTP 400 or validation error | Wrong input mode, unsupported parameter, malformed JSON, or viewport outside the accepted range | Send exactly the required input fields, validate JSON, and check the provider’s current parameter names and constraints. |
| HTTP 401 or 403 | Missing, invalid, or unauthorized API key | Use the documented authentication header or credential location; check secret configuration without exposing the key. |
| Output file contains text or JSON | The response is an API error body, not a successful image | Check status and content type before writing the body as an image; inspect a safely redacted error message. |
| Blank or incomplete image | Content had not rendered, assets failed, or the target was hidden | For a live page, wait for a relevant selector or supported load condition; verify asset access and element visibility. |
| Selector capture fails or shows the wrong region | Selector does not match, matches multiple elements, or is evaluated at a different render stage | Use a stable CSS selector and confirm the element exists and is visible at capture time. |
| Text wraps differently than expected | Viewport width, font availability, or CSS differs from the source environment | Set the intended dimensions and ensure required styles and fonts are accessible or embedded. |
| Request times out | Slow navigation, remote assets, or a wait condition that never occurs | Inspect the target and wait rule, reduce unnecessary dependencies, and set a bounded client timeout. Retry only when the failure may be transient. |
| Request rejected for size | Raw HTML exceeds the documented body limit | Check current provider limits; remove unnecessary markup or assets, or use a documented alternative input path. |
9. FAQ
Can I capture HTML that exists only in memory?
Yes, if the chosen endpoint accepts raw HTML in its request. Send the markup according to its documented contract; a URL-only endpoint needs a reachable page instead.
Can I save only a component from an existing site?
Yes, when the provider supports selector capture. Send the page URL and selector, and ensure the target is rendered and visible.
Does an HTML screenshot include CSS?
Only styles available to the renderer affect the result. Include styles inline or provide accessible stylesheets and assets, then allow time for them to load.
Is a screenshot API the same as a local browser CLI?
No. A hosted API runs capture through a service endpoint; a CLI such as shot-scraper runs in an environment you manage. The operational and billing details therefore differ.


