Features Full Page Screenshot Wait for Selector & Delay Block Cookie Banners Custom Viewport & Device Website to PDF HTML to Image Dark Mode Image Format & Quality MCP Server Webhook Pricing Docs Blog Log In Sign Up

html2canvas Alternative

Vitalii Holben Vitalii Holben

Searching for an html2canvas alternative usually means one of two things: CSS rendering broke, or you need screenshots on the server. html2canvas cannot do server-side, and its CSS support stopped improving in 2022. Below are six replacements, split into client-side libraries and server-side solutions, with trade-offs for each.

What html2canvas actually does (and why it breaks)

html2canvas is not a screenshot tool in the traditional sense. It reads your page element by element, figures out the styles, and redraws everything onto a <canvas> using its own JavaScript code. Think of it as a second, simpler browser running inside your browser and trying to copy what the real one already rendered.

Back in 2013 when CSS was simpler, that approach worked well enough. Today the gap keeps growing. The library has to support each CSS property individually, and any property the maintainer never added just shows up blank or broken. The last release was January 2022, and there are over 1,400 open issues on GitHub.

These CSS features do not render in html2canvas:

CSS property html2canvas status Chromium status
backdrop-filter Not supported Full support
clip-path Not supported Full support
mix-blend-mode Not supported Full support
box-shadow Broken rendering Full support
CSS filters Partial Full support
3D transforms Not supported Full support
writing-mode Not supported Full support
Custom fonts (@font-face) Unreliable Full support

Then there is the CORS problem. When html2canvas draws a cross-origin image onto canvas, the canvas becomes "tainted" and you can no longer export it. Calling toDataURL() or toBlob() throws a SecurityError. The useCORS: true option helps sometimes, but it depends on every image server sending the right headers. CDNs with redirect chains, S3 buckets without CORS config, SVGs with embedded references, all of these silently kill the export. GitHub issue #3020 has been open for years with no fix.

The library also cannot render iframes, does not support Shadow DOM, and the maintainer has moved on.

Client-side alternatives worth considering

Before jumping to a server-side solution, there are a few client-side libraries that improved on html2canvas since its last release.

html-to-image is the most popular replacement with roughly 3.9 million weekly npm downloads. Instead of painting onto canvas directly, it clones the DOM, inlines all styles, wraps the result in an SVG foreignObject, and draws that SVG to canvas. The output is often more accurate, the API is promise-based and TypeScript-native, and the library is actively maintained. Still client-side though, and still limited by canvas taint rules.

modern-screenshot (about 2 million weekly downloads) is a fork of html-to-image with performance improvements and better support for newer CSS features. Worth trying if html-to-image chokes on your layout.

SnapDOM is the newest option, already pulling around 1 million weekly downloads. It handles Shadow DOM, pseudo-elements, and modern CSS that trips up the older libraries. If you absolutely need to stay client-side, SnapDOM is probably the strongest pick right now.

html2canvas-pro is a community fork of html2canvas itself. It adds clip-path, mix-blend-mode, backdrop-filter, and modern color functions like oklch. Around 1.3 million weekly downloads. A reasonable choice if you have existing html2canvas code and just want to patch the CSS gaps without rewriting everything.

All four share the same wall: they run in the browser. No server-side rendering, no CI/CD pipelines, no background jobs, no batch processing. And cross-origin image restrictions hit all of them equally.

Server-side options: from DIY to managed API

Developers searching for html2canvas server side hit a dead end because the library needs a browser DOM to work. There is no Node.js version, no CLI, no way to run it in a backend process.

On the server, the problems that make html2canvas painful simply go away. A headless Chromium instance loads the page like a normal browser, fetches all resources directly (no CORS), renders all CSS natively, and takes a screenshot. No canvas, no taint errors, no JavaScript re-rendering of CSS properties.

Server-side also opens use cases that client-side capture cannot touch:

  • Generating OG images for social media crawlers (they need server-rendered URLs)
  • Producing website thumbnails in batch for a directory or gallery
  • Capturing pages behind authentication using custom cookies and headers
  • Exporting dashboards and reports to PNG or PDF on a schedule
  • Running captures in CI/CD for visual regression testing

Puppeteer and Playwright are the self-hosted options. Both give you page.screenshot() backed by real Chromium, full CSS support, no CORS issues. The catch is operational: each Chromium instance eats a few hundred megabytes of memory, Docker images balloon past a gigabyte, and you end up managing browser lifecycle, crashes, leaked processes, and retry logic. I ran into this exact setup on a project that generated social cards, and the infrastructure code ended up longer than the actual feature code. For a deeper look at this trade-off, see the Puppeteer vs screenshot API and Playwright vs screenshot API breakdowns.

A managed screenshot API gives you the same Chromium rendering without the infrastructure. You send an HTTP request with a URL or raw HTML, you get back an image or PDF. ScreenshotRun's HTML to image feature is the direct replacement for what html2canvas tries to do: send HTML in, get an image back. Every CSS property, every web font, every JS framework renders exactly like it would in Chrome.

The pain points that push developers away from html2canvas map directly to API capabilities:

html2canvas problem API solution ScreenshotRun parameter
CORS errors with external images Server fetches resources directly Default behavior, no param needed
CSS not rendering (backdrop-filter, clip-path) Real Chromium renders all CSS Default behavior
Can't capture full page Full page scroll capture full_page=true
Can't run server-side HTTP API, any language GET/POST request
No PDF output PDF with page format control format=pdf
No retina support Consistent 2x rendering retina=true
iframes not captured Chromium loads iframes normally Default behavior
Canvas tainted by third-party images No canvas involved Default behavior

Code and feature comparison

A typical html2canvas setup with CORS workarounds:

import html2canvas from 'html2canvas';

const element = document.getElementById('capture-target');

const canvas = await html2canvas(element, {
    useCORS: true,
    allowTaint: false,
    scale: 2,
    logging: false,
    proxy: '/api/cors-proxy', // your own proxy to fix CORS
});

// This throws SecurityError if any image tainted the canvas
const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
const url = URL.createObjectURL(blob);

The same result with a server-side API call in Node.js:

const params = new URLSearchParams({
    html: '<div id="capture-target">...your HTML...</div>',
    format: 'png',
    retina: 'true',
    width: '800',
    height: '600'
});

const response = await fetch(
    `https://api.screenshotrun.com/v1/screenshots/capture?${params}`,
    { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
);

const buffer = Buffer.from(await response.arrayBuffer());

For Python backends generating images from HTML templates:

import requests

response = requests.get(
    'https://api.screenshotrun.com/v1/screenshots/capture',
    params={
        'html': '<div>...your HTML template...</div>',
        'format': 'png',
        'retina': 'true',
        'width': '800',
        'height': '600'
    },
    headers={'Authorization': 'Bearer YOUR_API_KEY'}
)

with open('capture.png', 'wb') as f:
    f.write(response.content)

No CORS proxy, no canvas taint errors, no toBlob workaround. Honestly, the number of hours I have watched developers lose to canvas taint debugging makes this one feel personal. The HTML goes in, a pixel-perfect PNG comes back.

Here is how the two approaches compare across the board:

Capability html2canvas ScreenshotRun API
Rendering approach JavaScript DOM reconstruction Real Chromium engine
CSS support Partial (each property coded manually) Complete (native Chromium)
CORS handling Canvas taint, proxy required No CORS issues (server-side fetch)
Runs server-side No (requires browser DOM) Yes (HTTP API)
iframes Not rendered Full support
Shadow DOM Not supported Full support
Output formats Canvas blob (PNG/JPEG) PNG, JPEG, WebP, AVIF, TIFF, PDF
Full page capture Manual scroll + stitch full_page=true
Device emulation No device=mobile, custom viewport
Maintenance Abandoned (last release Jan 2022) Active, updated Chromium
Cost Free Free tier (200/month), paid plans after

When html2canvas is still the right choice

Worth being upfront about this: not every project needs server-side rendering. html2canvas works fine in specific situations and using an API there would be overkill.

If you are building a real-time preview where the user sees their design captured instantly in the browser, client-side capture avoids the 1 to 3 second network round-trip of an API call. Interactive tools like card builders or badge generators benefit from that immediacy.

Privacy-sensitive applications in healthcare or finance may require that data never leaves the browser. With html2canvas, the capture stays client-side. An API means sending HTML content to a third-party server, which might not pass compliance review.

Offline applications and static sites without a backend cannot securely make API calls (the API key would be exposed in client-side code). html2canvas or one of its client-side alternatives is the only option here.

For everything else, if your CSS is complex, your images come from CDNs, you need server-side generation, or you are tired of debugging canvas taint errors, server-side rendering is the more reliable path. Start with ScreenshotRun's free tier and compare the output to what html2canvas produces on the same page. The difference on anything using modern CSS is hard to miss. For the full API parameter reference, check the best screenshot API comparison.

Frequently asked questions

No. html2canvas requires a browser DOM to function. There is no Node.js version or CLI. For server-side HTML-to-image conversion, use Puppeteer or Playwright (self-hosted) or a managed screenshot API like ScreenshotRun.
Common causes include cross-origin images tainting the canvas (CORS), unsupported CSS properties like backdrop-filter and clip-path, images not fully loaded before capture, and canvas elements within the DOM. The library re-renders your page using its own JavaScript code, so anything it has not implemented shows up blank.
Set useCORS: true in the html2canvas options and make sure each image server sends Access-Control-Allow-Origin headers. If you cannot control the image server, you need a CORS proxy on your own backend. Alternatively, a server-side screenshot API fetches all resources directly and avoids CORS entirely.
Unsupported or broken properties include backdrop-filter, clip-path, mix-blend-mode, box-shadow (broken rendering), CSS filters (partial), 3D transforms, writing-mode, and custom fonts via @font-face (unreliable). The html2canvas-pro fork adds some of these, but the core library has not been updated since January 2022.
html-to-image has roughly 3.9 million weekly npm downloads and is more actively maintained. It uses a different rendering approach (SVG foreignObject) that is often more accurate. However, it shares the same client-side limitations: no server-side support, CORS restrictions on cross-origin images, and no real browser rendering engine. For production workloads that need reliability and full CSS support, a server-side API is more robust than any client-side library.