HTML to Image JavaScript SDK
The official JavaScript SDK wraps the HTML to Image REST API in a small, fully typed client so you don’t have to hand-roll fetch or axios calls. It covers the HTML, screenshot and template endpoints, returns a typed response object, and throws specific error classes for validation, authentication, rate-limit and credit errors.
Best for: Node-based backends, serverless functions on Vercel/Netlify/Cloudflare, and any build script that wants a maintained client with typed options and no runtime dependencies. If you would rather call the API directly, see the raw JavaScript guide.
The SDK is published on npm as @html2img/client and is open source on GitHub: html2img/html2img-js.
Requirements
- Node.js 18 or newer (for the built-in global
fetch). Bun, Deno and edge runtimes work too. - An API key (see the quick start if you don’t have one yet)
Keep your API key on the server. The SDK is designed for server-side use: scripts, API routes, background jobs and serverless functions. Shipping your key in browser code would let anyone spend your credits.
Installation
Install the package from npm (pnpm, yarn and bun work too):
npm install @html2img/client
The package has zero runtime dependencies, ships dual ESM and CommonJS builds, and bundles its own TypeScript declarations, so there is no extra @types package to install.
Creating a client
Instantiate Html2img with your API key:
import { Html2img } from '@html2img/client';
const client = new Html2img(process.env.HTML2IMG_API_KEY);
CommonJS works too:
const { Html2img } = require('@html2img/client');
Pass an options object instead of a string when you need to override the base URL, timeout, or supply your own fetch implementation (for proxies, retries or logging middleware):
const client = new Html2img({
apiKey: process.env.HTML2IMG_API_KEY,
baseUrl: 'https://app.html2img.com', // default
timeout: 35_000, // milliseconds, default
fetch: (url, init) => myInstrumentedFetch(url, init), // optional
});
Store your API key in an environment variable rather than hard-coding it. The SDK sends it as the X-API-Key header on every request; see the authentication guide.
Converting HTML to an image
Pass an options object to html(). The method resolves to a RenderResponse whose url property holds the CDN URL of the generated image:
const response = await client.html({
html: '<!doctype html><html><body><h1>Hello</h1></body></html>',
width: 1200,
height: 630,
css: 'body { background: #0f172a; }',
fullpage: true,
dpi: 2,
});
console.log(response.url); // CDN URL
Option names are camelCase in JavaScript (msDelay, waitForSelector, webhookUrl) and sent to the API in snake_case. Out-of-range values fail fast with a native TypeError or RangeError before any request is sent, mirroring the server-side validation rules. The parameters reference covers every option.
Taking a screenshot
Use screenshot() to capture a live URL. You can target a specific element with selector and inject CSS to hide elements such as cookie banners:
const response = await client.screenshot({
url: 'https://example.com',
width: 1200,
height: 630,
selector: '#hero',
css: '.cookie-banner { display: none !important; }',
dpi: 2,
});
console.log(response.url);
Rendering a template
Skip the HTML step entirely with a named template. Pass the template slug and a data object to template():
const response = await client.template('invoice', {
number: 1042,
amount: '$240.00',
due_date: '2026-07-01',
});
console.log(response.url);
Rendering a PDF instead
Set format to 'pdf' on either render method and the response url points at an A4 document instead of a PNG:
const response = await client.html({
html: '<h1>Invoice #1042</h1><p>Due within 30 days.</p>',
format: 'pdf',
});
console.log(response.url); // ends in .pdf
The PDF is vector output with selectable text and automatic pagination, and it costs the same single credit as an image. Sizing options such as width, height and dpi are ignored in PDF mode. See the format parameter docs for the full behaviour and the HTML to PDF API page for the overview.
Asynchronous delivery
Synchronous requests have a 30 second budget. For captures likely to exceed it, pass a webhookUrl. The API responds immediately with status: "processing" and a null url, then POSTs the final image URL to your endpoint once rendering finishes:
const response = await client.screenshot({
url: 'https://example.com/long-report',
fullpage: true,
webhookUrl: 'https://your-app.example.com/hooks/html2img',
});
if (response.isProcessing()) {
// The final URL will arrive at your webhook, not on this response.
}
See the webhook_url parameter docs for the payload shape.
The response object
Every method resolves to a RenderResponse with the following properties and helpers:
| Member | Type | Description |
|---|---|---|
success | boolean | Whether the request succeeded |
id | string | null | The render ID |
url | string | null | CDN URL of the generated image |
creditsRemaining | number | null | Credits left on your account |
status | string | null | Render status, "processing" for async jobs |
message | string | null | Error or status message |
template | string | null | Template slug, when a template was rendered |
isProcessing() | boolean | true while an async job is still pending |
raw | object | The full JSON payload |
Error handling
Every failed request rejects with an Html2imgError. Catch that single class to handle any error, or check for a specific subclass. No raw fetch error escapes the client:
import {
Html2imgError,
ValidationError,
AuthenticationError,
InsufficientCreditsError,
RateLimitError,
} from '@html2img/client';
try {
const response = await client.html({ html: document });
} catch (error) {
if (error instanceof ValidationError) {
// 400 or 422: inspect the per-field messages in error.details
} else if (error instanceof AuthenticationError) {
// 401: bad or missing API key
} else if (error instanceof InsufficientCreditsError) {
// 402: out of credits, error.creditsRemaining tells you what is left
} else if (error instanceof RateLimitError) {
// 429: rate limit exceeded
} else if (error instanceof Html2imgError) {
// anything else: statusCode, errorCode and payload carry the details
}
}
The full hierarchy also includes NotSubscribedError, NotFoundError, TimeoutError, ServerError and ConnectionError, all extending Html2imgError.
Related guides and resources
- @html2img/client on npm: releases and install stats
- html2img/html2img-js on GitHub: source, releases and issues
- HTML to Image in JavaScript and Node.js: the raw fetch and axios guide
- HTML to Image in React: server-side and client-triggered rendering in React
- HTML to Image in Vue: Vue and Nuxt patterns
- PHP SDK: the same client family for PHP
- Browse all templates
- Getting started with the API
- Pricing