ScreenshotNeo

BlogHow-to

How to Convert More Than 100 Divs to Images Reliably

Capture hundreds of divs without blank canvases, memory failures, or cross-origin surprises. This guide covers batching, sizing, CORS, and browser alternatives.

By the ScreenshotNeo team1 October 20269 min read

Direct answer: More than 100 divs is not a documented html2canvas limit. Reliability depends on the size of each generated bitmap, CSS features used by the page, cross-origin resources, device memory, and how you schedule captures. Capture one element at a time (or in a small, profiled queue), keep canvas dimensions deliberate, release each result before continuing, and verify every output. If you need pixels from the actual browser rather than a DOM reconstruction, use a real-browser workflow such as Puppeteer or Playwright.

html2canvas walks the DOM and supported styles, then builds a canvas. It does not take a native screenshot, so unsupported CSS can differ from what the browser displays. The project describes the result as based on the DOM and not necessarily 100% accurate to the real page (html2canvas documentation).

1. Decide what “reliable” means

Before changing batch sizes, define the output contract:

  • One image per div: each target gets its own canvas and file.
  • One image containing all divs: one large canvas is simpler but reaches pixel and memory limits sooner.
  • DOM approximation: html2canvas is suitable when its supported CSS and same-origin rules match your page.
  • Actual browser pixels: use browser screenshot APIs or server-side browser automation when fidelity matters more than running inside the page.

There is no source-backed reason to treat 100 as a threshold. A page with 150 small cards may work while a single very tall element fails because the bitmap is too large.

2. Capture each div with html2canvas

Install the library or load it from the distribution method used by your application. The following example captures every element with .capture-target, waits for each operation, checks the canvas dimensions, downloads the PNG, and releases references before moving on.

<script src="https://cdn.jsdelivr.net/npm/html2canvas@latest/dist/html2canvas.min.js"></script>
<script>
async function captureDivs() {
  const targets = [...document.querySelectorAll('.capture-target')];
  const output = [];

  for (let index = 0; index < targets.length; index += 1) {
    const element = targets[index];
    const canvas = await html2canvas(element, {
      scale: Math.min(window.devicePixelRatio || 1, 2),
      useCORS: true,
      clearImageCache: true
    });

    if (canvas.width === 0 || canvas.height === 0) {
      throw new Error(`Capture ${index} produced an empty canvas`);
    }

    const blob = await new Promise((resolve, reject) => {
      canvas.toBlob(blobValue => blobValue ? resolve(blobValue) : reject(new Error('toBlob returned null')), 'image/png');
    });

    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = `div-${String(index + 1).padStart(3, '0')}.png`;
    link.click();
    URL.revokeObjectURL(url);

    output.push({ index, width: canvas.width, height: canvas.height });

    // Drop references before the next capture so canvases can be collected.
    canvas.width = 0;
    canvas.height = 0;
  }

  return output;
}

captureDivs().then(console.log).catch(console.error);
</script>

Run the loop sequentially first. Parallel captures multiply canvas memory and image decoding work; increase concurrency only after profiling representative devices.

Capture a known list instead of a selector

const targets = [
  document.querySelector('#invoice-1'),
  document.querySelector('#invoice-2'),
  document.querySelector('#invoice-3')
].filter(Boolean);

Filtering missing elements prevents a null reference from stopping the entire job. For production jobs, record the element identifier, dimensions, and error for every item so one failure does not hide later results.

3. Control scale, dimensions, and memory

The bitmap, rather than the number of elements, is the main size risk. html2canvas uses device pixel ratio by default. A high-DPI screen can therefore produce a canvas several times larger than the CSS box. Set a deliberate scale:

const canvas = await html2canvas(element, {
  scale: 1,          // smallest memory footprint
  width: element.scrollWidth,
  height: element.scrollHeight,
  clearImageCache: true
});

Use scale: 1 when predictable memory matters more than retina sharpness. Use 2 when output resolution requires it and the target dimensions are modest. Check canvas.width * canvas.height before encoding; this is the number of pixels, independent of how many divs are on the page.

For a very large target, split it at meaningful boundaries and capture separate sections. A single tall canvas can exceed platform limits even when each section would be safe.

4. Understand browser canvas limits

The html2canvas FAQ gives rough, browser-dependent guides rather than guarantees: about 32,767 pixels for a maximum dimension in Chrome/Chromium, Firefox, and desktop Safari; approximate maximum areas of 268 million pixels for Chrome and 473 million for Firefox. The FAQ says these values vary by browser and platform and can produce blank or partial output when exceeded. Treat them as warnings, especially on iOS where available canvas size depends on device memory (html2canvas FAQ, accessed September 29, 2026).

Do not use those figures as a promise that a particular phone can allocate the same bitmap. Measure your actual target width, height, device pixel ratio, and memory behavior.

5. Handle images, fonts, and cross-origin content

Images loaded from another origin can taint the canvas, making it unreadable for export. The documented approaches are:

  • Serve the image with the required CORS headers and enable CORS loading where appropriate.
  • Use a proxy that retrieves the image and serves it from an origin your page can read.
  • Replace or omit assets that cannot be made CORS-accessible.

useCORS requests CORS loading; it does not bypass browser policy. A remote server must allow the request. Cross-origin iframes are different: the page cannot access their document, so html2canvas cannot render their contents. Capture those pages in a browser context with the needed access instead.

const canvas = await html2canvas(element, {
  useCORS: true,
  proxy: '/image-proxy',
  scale: 1,
  clearImageCache: true
});

Wait for assets that affect layout before starting the queue. A capture taken while images or fonts are still loading can have different dimensions from the final page.

6. Build a resumable capture queue

A queue lets you retry failures, stop before memory pressure becomes fatal, and preserve progress. This example returns a result for every target instead of rejecting the entire batch.

async function captureQueue(elements, options = {}) {
  const results = [];

  for (let index = 0; index < elements.length; index += 1) {
    const element = elements[index];
    try {
      const canvas = await html2canvas(element, {
        scale: options.scale ?? 1,
        width: options.width,
        height: options.height,
        useCORS: options.useCORS ?? true,
        proxy: options.proxy,
        clearImageCache: true
      });

      if (!canvas.width || !canvas.height) {
        throw new Error('zero-sized canvas');
      }

      const dataUrl = canvas.toDataURL('image/png');
      results.push({ index, ok: true, width: canvas.width, height: canvas.height, dataUrl });
      canvas.width = 0;
      canvas.height = 0;
    } catch (error) {
      results.push({ index, ok: false, message: String(error) });
    }
  }

  return results;
}

const results = await captureQueue(
  [...document.querySelectorAll('.capture-target')],
  { scale: 1, useCORS: true }
);
console.table(results.map(({ index, ok, width, height, message }) => ({ index, ok, width, height, message })));

For long-lived applications, clearImageCache is specifically documented as useful when capturing many screenshots because it releases loaded-image memory. Still release your own canvas, blob, and data URL references as soon as each result is consumed.

7. Verify every output

  • Reject zero-width or zero-height canvases.
  • Check that the encoded blob is non-null and has the expected MIME type.
  • Store the source element ID and canvas dimensions with the output.
  • Sample images visually when CSS fidelity matters; successful encoding does not prove the pixels match the browser.
  • Retry transient resource failures once, then record the item for review.

Blank or partially rendered output can occur without a useful JavaScript exception when a canvas limit is exceeded. Dimension checks and per-item records make that failure visible.

8. When html2canvas is the wrong tool

Requirement Better fit Reason
Pixel-faithful browser output on a server Puppeteer or Playwright They render in an automated browser instead of reconstructing the DOM on a canvas.
Cross-origin iframe contents Capture inside an authorized browser context Same-origin rules prevent html2canvas from reading another origin’s document.
Browser extension tab capture Native tab screenshot APIs The html2canvas FAQ points to native APIs that avoid canvas size limits.
Many independent cards in a web page Sequential html2canvas queue Each bitmap stays smaller and memory can be released between items.

9. Troubleshooting

Symptom Likely cause Fix
Only the first few images work Memory pressure from retained canvases or image data Process sequentially, use a lower scale, enable clearImageCache, and release blobs, data URLs, and canvas references.
Blank or partially rendered canvas Canvas width, height, or area is beyond the browser/device limit Reduce scale, split the element, reduce dimensions, or use a native/browser screenshot workflow.
SecurityError when exporting A cross-origin image tainted the canvas Serve the image with CORS headers, configure a permitted proxy, or remove the asset. useCORS cannot override policy.
Remote iframe is missing Cross-origin iframe isolation Capture the iframe in its own authorized browser context; html2canvas cannot read its document.
Styles differ from the page Unsupported CSS or DOM reconstruction differences Check the library’s supported features, simplify the target styles, or switch to an actual browser screenshot.
Images are clipped Explicit dimensions do not include the full scroll size Use the element’s scrollWidth and scrollHeight where appropriate, then verify the resulting canvas.
Output is blurry Scale is too low for the intended display size Increase scale only after checking pixel dimensions and memory on target devices.
Later captures have stale or missing images Resources are still loading or cache is retained Wait for required assets, capture after layout settles, and use clearImageCache in repeated workflows.

10. Performance, reliability, and cost planning

Performance

Runtime grows with the number of DOM nodes, styles, images, and pixels rendered. Lowering scale reduces pixel work quadratically: halving both canvas dimensions creates roughly one quarter as many pixels. Avoid capturing hidden or offscreen content unless it is intentionally part of the output. Keep concurrency at one until profiling shows that a small queue is safe.

Reliability

Run the same queue on representative desktop and mobile devices. Record dimensions, duration, and failure reason per element. Use deterministic input data and wait for layout-affecting resources. A successful promise only means the reconstruction completed; it does not certify visual fidelity.

Cost

html2canvas runs in the user’s browser, so there is no screenshot API request charge. You still pay in CPU, memory, battery, bandwidth for assets, and engineering time for CORS, retries, storage, and browser-specific behavior. Server-side browser automation adds infrastructure and operational costs but can provide more consistent rendering.

11. Or skip the browser setup

ScreenshotNeo provides a hosted website screenshot API when you need a clean capture of a URL instead of maintaining browser automation. Its cleanup steps accept cookie and consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.

See the ScreenshotNeo API documentation for all options, including full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, custom CSS and JavaScript, click and wait actions, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous jobs, bulk capture, usage data, and PDF output.

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 also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

12. Checklist for a 100-plus element job

  • Define whether you need separate images or one composite image.
  • Confirm that the required CSS is supported by html2canvas.
  • Measure target dimensions and choose an explicit scale.
  • Resolve CORS for every remote image and avoid inaccessible cross-origin iframes.
  • Wait for layout, images, and fonts that affect the result.
  • Capture sequentially first; profile before adding concurrency.
  • Enable clearImageCache for long-running repeated capture.
  • Release canvas and encoded data after each item.
  • Validate dimensions and output bytes, and record failures by element.
  • Switch to Puppeteer, Playwright, or native tab capture when actual browser pixels are required.

FAQ

Is there a maximum number of divs html2canvas can capture?

No documented fixed count exists. The practical limits come from the bitmap dimensions, supported rendering features, resource access, and available memory.

Should I make one huge canvas?

Usually no when each div is an independent image. Separate canvases keep dimensions and memory manageable. Use one canvas only when a composite image is the actual requirement and its dimensions are safe.

Does lowering the batch size fix unsupported CSS?

No. Batching controls memory and scheduling; it cannot add CSS features that html2canvas does not implement.

Can useCORS read any remote image?

No. The remote server must permit the request with CORS headers, or you must use a permitted proxy.

When should I use ScreenshotNeo?

Use it when you want a hosted URL screenshot, clean output without consent banners and popups, no billing for failed or blocked captures, or an MCP workflow for AI agents.