What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Remove only the canvas your application owns, then append the new one after html2canvas() resolves. The library returns a Promise for an HTMLCanvasElement; it does not decide where that node belongs in your page. Keep a reference to the previous output (or mark generated canvases), check that it is still connected, remove it, and insert the new canvas into a dedicated host. For fast, clean captures without browser setup, ScreenshotNeo can return an image or PDF from one request.

The reliable replacement pattern

A capture is asynchronous. The call to html2canvas(source) starts rendering and resolves later with a canvas. Your code is responsible for both insertion and cleanup. A minimal replacement function is:

const host = document.querySelector('#preview');
let previousCanvas = null;

async function replacePreview(source) {
  const nextCanvas = await html2canvas(source);

  if (previousCanvas?.isConnected) {
    previousCanvas.remove();
  }

  host.append(nextCanvas);
  previousCanvas = nextCanvas;
}

isConnected prevents errors when another part of the application has already removed the old node. The dedicated #preview host ensures that charts, signature pads, game canvases and other unrelated graphics remain untouched.

Replace a node in place

If the host contains exactly one generated canvas and you want the new image to occupy the same position, keep a stable wrapper and replace its child:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
async function replacePreview(source) {
  const nextCanvas = await html2canvas(source);
  const old = host.querySelector('canvas[data-html2canvas-output]');

  nextCanvas.dataset.html2canvasOutput = 'true';
  old?.replaceWith(nextCanvas);
  if (!old) host.append(nextCanvas);
}

replaceWith() removes only the selected output. It does not affect siblings or canvases elsewhere on the page.

Prevent an older capture from winning

Two calls can overlap when a user changes a form quickly or clicks “refresh” repeatedly. Because html2canvas documents a Promise result but not cancellation, an earlier render may finish after a newer request. Without protection, that stale result can overwrite the current preview.

Use a serial (latest-request-wins) guard

const host = document.querySelector('#preview');
let previousCanvas = null;
let renderSerial = 0;

async function replacePreview(source) {
  const serial = ++renderSerial;
  const nextCanvas = await html2canvas(source);

  if (serial !== renderSerial) return; // a newer request already started

  if (previousCanvas?.isConnected) previousCanvas.remove();
  host.append(nextCanvas);
  previousCanvas = nextCanvas;
}

The serial is incremented before each capture. A completion is accepted only if its number still matches the latest request. This avoids displaying stale content while allowing the browser to finish work that html2canvas has already started.

Serialize captures when every result matters

A queue is preferable when captures must be processed in order, such as generating a set of archival images:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option
let captureQueue = Promise.resolve();

function enqueueCapture(source) {
  const job = captureQueue.then(() => html2canvas(source));
  captureQueue = job.catch(() => {}); // keep the queue usable after an error
  return job;
}

async function renderInOrder(source) {
  const nextCanvas = await enqueueCapture(source);
  const old = host.querySelector('canvas[data-html2canvas-output]');
  nextCanvas.dataset.html2canvasOutput = 'true';
  old?.replaceWith(nextCanvas);
  if (!old) host.append(nextCanvas);
}

Choose one policy: latest-request-wins for interactive previews, or serialization when each capture is required. Do not combine both without deciding which result should be visible.

Use a marker instead of a JavaScript reference

A reference is simplest while one component owns the output. A marker is useful when a component can be mounted again, when state is reconstructed, or when several independent previews share a host.

async function replaceMarkedPreview(source, host) {
  const old = host.querySelector('canvas[data-html2canvas-output]');
  old?.remove();

  const next = await html2canvas(source);
  next.dataset.html2canvasOutput = 'true';
  host.append(next);
}

Scope the query to the component’s host. A document-wide selector can delete visualizations that your feature does not own. If multiple outputs are intentional, give each host a distinct identifier or add a key such as data-preview-id.

Reuse an existing canvas when node identity matters

The configuration includes a canvas option: an existing canvas element can be supplied as the drawing base. This keeps the same DOM node, which is useful when other code holds a reference, when layout observers are attached, or when a framework expects stable identity.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const canvas = document.querySelector('#previewCanvas');
await html2canvas(source, { canvas });

With this approach there is no old output node to remove; html2canvas draws into the supplied element. You still control when the canvas is shown and how it is sized. Do not pass a canvas that another feature is drawing into unless sharing that bitmap is deliberate.

What removeContainer actually removes

removeContainer defaults to true. It cleans the temporary cloned DOM that html2canvas creates while rendering. That cleanup container is an internal implementation detail. It is not the canvas your code appended to document.body or to #preview.

const output = await html2canvas(source, {
  removeContainer: true
});
host.append(output); // this node remains until your code removes or replaces it

Setting or relying on removeContainer therefore does not solve “new canvas every time.” Remove the previous output yourself, or reuse an application-owned canvas with the canvas option.

Keep cleanup narrowly scoped

  • Best: append outputs to a dedicated element such as <div id="preview"> and remove only its generated canvas.
  • Also safe: mark outputs with data-html2canvas-output or a class such as html2canvas-output, then query inside the owning component.
  • Avoid: document.querySelectorAll('canvas') followed by removing every result. That can destroy charts, games, signature controls and other application state.

If a preview is unmounted, remove its host or its marked canvas in the component’s teardown. A disconnected reference can remain in JavaScript memory until released, so set previousCanvas = null when the owner is destroyed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

Rendering and bitmap-readability caveats

html2canvas reconstructs a page from the DOM and styles in the browser; it is not a pixel-perfect native screenshot engine. Unsupported CSS, fonts that have not loaded, animations and dynamic content can make the result differ from what a user sees.

Cross-origin images and tainted canvases

An image loaded from another origin can taint the bitmap. The canvas may display correctly but throw a security error when code tries to call toDataURL(), toBlob() or read pixels. The documented controls are:

  • useCORS: true when the image server sends an appropriate CORS header.
  • proxy when your server provides a same-origin proxy for remote assets.
  • allowTaint: true when you accept a tainted canvas and do not need to read or export its pixels.
const output = await html2canvas(source, {
  useCORS: true,
  // proxy: '/image-proxy',
  allowTaint: false
});

These options do not repair missing CORS headers. Fix the asset server or proxy configuration, then capture again.

Wait for content before capturing

Call the function after the source is visible and its images and fonts have loaded. For a user-triggered button, this usually means the page is already rendered. For programmatic startup, wait for document.fonts.ready and relevant image promises before invoking html2canvas.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common failures and precise fixes

Symptom Likely cause Fix
A new canvas appears on every click The returned canvas is appended without removing the previous output. Keep a reference or marker and call remove()/replaceWith() in the dedicated host before appending.
Charts or signature pads disappear Cleanup uses a broad selector such as querySelectorAll('canvas'). Scope the selector to the preview host or a generated-output marker.
removeContainer seems ineffective It removes temporary clones, not your appended result canvas. Perform application-level output cleanup or pass an existing canvas.
An older image replaces newer content Overlapping asynchronous captures complete out of order. Use a serial guard for latest-request-wins or queue captures for strict ordering.
toDataURL() or toBlob() throws a security error A cross-origin image tainted the canvas. Use CORS-enabled assets with useCORS, a proxy, or avoid reading the bitmap with allowTaint.
The output is blank or incomplete Capture ran before content, fonts or images were ready, or the page uses unsupported styling. Wait for resources, make dynamic state deterministic, and treat html2canvas as DOM reconstruction rather than a native screenshot.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance and lifecycle decisions

  • Do not capture on every keystroke unless necessary. Debounce input and use the serial guard so work from superseded requests is ignored.
  • Reuse a canvas when stable node identity and fewer DOM mutations matter; replace nodes when a simple immutable preview is easier to reason about.
  • Keep the host mounted while a capture is running. If it is removed, check isConnected before cleanup and decide whether to discard the result.
  • Release discarded results by not appending stale canvases and by dropping references after a component unmounts.
  • Measure memory for large pages. A high-resolution canvas consumes more memory than its CSS dimensions suggest, especially when device-pixel scaling is involved.

Or skip the browser setup

When you need a URL screenshot rather than a canvas reconstructed inside your page, ScreenshotNeo provides an HTTP screenshot API and an MCP server for AI agents. It accepts cookie and consent banners before capture, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and bills only clean shots: bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed. Each response reports the page verdict and billing status in X-Page-Verdict and X-Billed headers.

One request returns a PNG, JPEG, WebP or PDF. The API supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper settings, custom CSS and JavaScript, clicks, waits, blocking rules, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. Its parameter names are compatible with those used by many screenshot APIs.

cURL

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}`);

See the ScreenshotNeo API documentation for authentication, output controls and response headers. The MCP server exposes take_screenshot, get_page_info and capture_pdf 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 shots; every feature is available on every plan, and yearly billing provides two months free. Create a free ScreenshotNeo account to try it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choosing between replacement, reuse and an API

Need Best fit Reason
Interactive preview inside the current page Reference or marker replacement You control exactly which output node is removed and displayed.
Stable DOM identity for other code Existing canvas option html2canvas draws into an application-owned node.
Several rapid requests where only the newest matters Serial guard Stale Promise completions cannot overwrite current content.
Ordered archival captures Serialized queue Each render completes in the requested sequence.
Server-side URL images, PDFs or AI-agent workflows ScreenshotNeo Clean shots, only clean shots billed, and a $5 paid entry plan.

FAQ

Can I remove the previous canvas before starting the next capture?

Yes, if a temporary blank preview is acceptable. Otherwise capture first and replace only after the Promise resolves, so the current image remains visible during rendering.

How can I tell whether a canvas is still in the document?

Use the DOM property canvas.isConnected. It is true when the node is connected to a document and false after removal or before insertion.

Does supplying canvas clear its old pixels automatically?

The option designates an existing canvas as the drawing base; if stale pixels matter, clear or size the canvas according to your rendering flow before reuse.

Why does a screenshot differ from the browser’s native screenshot?

html2canvas rebuilds the scene from accessible DOM and styles, so unsupported CSS, resource timing and cross-origin restrictions can produce differences even when replacement logic is correct.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.