What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
To capture a long page from its bottom to its top with html2canvas, render the entire scrolling element instead of only the viewport. Measure its scrollWidth and scrollHeight, pass those values as windowWidth and windowHeight, then export the canvas as an image. This avoids manually scrolling and stitching screenshots.
Capture the full page in one render
Run this code in the page you want to capture, after the content and required images have loaded:
const element = document.documentElement;
const canvas = await html2canvas(element, {
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight,
});
canvas.toBlob((blob) => {
if (!blob) return;
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'full-page.png';
link.click();
URL.revokeObjectURL(url);
}, 'image/png');
The element whose dimensions you measure must be the element passed to html2canvas. windowWidth and windowHeight control the rendering viewport and can affect responsive layout and media queries. If you need to force the output canvas to an exact size, add width and height, but normally the scroll dimensions are the correct values.
Choose the correct scrolling element
Most documents scroll through document.documentElement. Some applications put scrolling on document.body, while dashboards and panels commonly use a wrapper with overflow: auto. Capture that actual scrolling element.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →#1 Best Overall
Document root
const element = document.documentElement;
const canvas = await html2canvas(element, {
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight,
});
Body-scrolling pages
const element = document.body;
const canvas = await html2canvas(element, {
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight,
});
A scrollable component
const element = document.querySelector('.article-scroll');
if (!element) throw new Error('Scrollable element not found');
const canvas = await html2canvas(element, {
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight,
});
Measuring one element and rendering another is a common reason for a result that is cut off. Inspect the page’s layout and check which node has the changing scrollTop, scrollWidth, and scrollHeight.
Wait for content before capturing
Start the capture only after the page has rendered the material that must appear in the image. For images already present in the document, wait for completion before calling html2canvas:
await Promise.all(
Array.from(document.images).map((image) => {
if (image.complete) return Promise.resolve();
return new Promise((resolve) => {
image.addEventListener('load', resolve, { once: true });
image.addEventListener('error', resolve, { once: true });
});
})
);
const element = document.documentElement;
const canvas = await html2canvas(element, {
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight,
});
This wait does not make an application’s data fetching complete automatically. If a framework loads content after an API request, wait for the application’s own “ready” condition, a known selector, or a suitable delay before measuring dimensions. Measure after expansion, lazy loading, and font loading have changed the page; otherwise the captured height can be too small.
Export PNG, JPEG, or a data URL
PNG with toBlob
toBlob is preferable for large captures because it avoids creating one enormous base64 string in JavaScript memory.
canvas.toBlob((blob) => {
if (!blob) return;
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'full-page.png';
link.click();
URL.revokeObjectURL(url);
}, 'image/png');
JPEG output
canvas.toBlob((blob) => {
if (!blob) return;
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'full-page.jpg';
link.click();
URL.revokeObjectURL(url);
}, 'image/jpeg', 0.9);
JPEG uses a quality value from 0 to 1 and is usually smaller, but it introduces compression artifacts. PNG is safer for text, diagrams, and transparency.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Data URL
const dataUrl = canvas.toDataURL('image/png');
A data URL is convenient for embedding or sending to another API, but it duplicates the image in memory and can be impractical for very tall pages.
Improve fidelity and control what appears
Retina-scale rendering
const element = document.documentElement;
const canvas = await html2canvas(element, {
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight,
scale: window.devicePixelRatio,
});
A larger scale increases detail and output dimensions, but also increases memory use and the chance of exceeding browser canvas limits. Use a moderate scale for long pages.
Remove fixed or sticky controls
Add data-html2canvas-ignore to a node that should not appear:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minute<button data-html2canvas-ignore>Chat</button>
For temporary changes that should exist only in the cloned capture document, use onclone:
const canvas = await html2canvas(document.documentElement, {
windowWidth: document.documentElement.scrollWidth,
windowHeight: document.documentElement.scrollHeight,
onclone: (clonedDocument) => {
clonedDocument.querySelectorAll('.sticky, .fixed-toolbar')
.forEach((node) => { node.style.display = 'none'; });
},
});
Animations, transforms, sticky positioning, plugin content, and rapidly changing elements may not match what a person sees at a particular instant. Freeze or hide those elements in the clone when consistency matters.
Cross-origin images and iframes
html2canvas reconstructs the image from the DOM and CSS; it does not bypass browser security. A remote image must send CORS headers that permit the requesting page, and you must enable CORS handling:
Rank #3
const element = document.documentElement;
const canvas = await html2canvas(element, {
windowWidth: element.scrollWidth,
windowHeight: element.scrollHeight,
useCORS: true,
});
useCORS cannot grant permission that the image server did not send. If you control a same-origin proxy, configure html2canvas’s proxy option and have the proxy fetch the image. Never treat a proxy as permission to access content you are not authorized to retrieve.
Cross-origin iframes cannot be rendered because their contentDocument is inaccessible. Same-origin iframes can be traversed recursively. If an embedded frame is essential and cross-origin, capture it separately with cooperation from that application or use a real browser automation workflow.
Why a capture is blank, partial, or too short
Canvas dimension and area limits
Evergreen desktop browsers have rough maximum canvas dimensions near 32,767 pixels per side, with additional total-area limits. Exact limits vary by browser, operating system, GPU, and available memory; iOS limits are generally lower and depend heavily on device memory. A page can therefore produce a blank or partially rendered canvas without a useful exception.
- Reduce
scale, including avoiding an unnecessarily high device-pixel ratio. - Capture independent sections and save them as separate images.
- Shorten or paginate the content before rendering.
- For extremely long pages, use browser automation or a native capture API instead of one giant canvas.
Only the viewport appears
Check that windowWidth and windowHeight use the measured element’s scrollWidth and scrollHeight. Also verify that the element is not a child inside another scrolling container. A fixed height or clipping rule on a wrapper can make the measured scroll area smaller than the visible content.
Images are missing or the canvas is unreadable
Wait for images, use useCORS: true only when the image server supplies appropriate headers, or route permitted requests through a same-origin proxy. A cross-origin image without permission can be skipped or taint the canvas, preventing export.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteRank #4
- 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
Text or CSS looks different
html2canvas implements CSS properties individually and is not a native bitmap screenshot. Unsupported or partially supported CSS can differ from the browser’s display. Test important pages with their real fonts, effects, transforms, and responsive breakpoints.
When html2canvas is the wrong tool
html2canvas runs in a browser context and depends on window, document, and computed styles; it is not a Node.js rendering library. For server-side screenshots, use browser automation such as Puppeteer or Playwright, which drive a real browser. Browser extensions should prefer native tab-capture APIs such as Chrome, Edge, or Opera’s chrome.tabs.captureVisibleTab(), or Firefox’s browser.tabs.captureVisibleTab(), particularly when a page exceeds canvas limits.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server when you need a repeatable server-side capture. It accepts a URL and can return PNG, JPEG, WebP, or PDF. Before capture, it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
Use the API documentation at screenshotneo.com/docs/ for all options, including full-page lazy-image loading, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF page settings, custom CSS and JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, selectable cache TTL, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting, and the OpenAPI specification.
Free tools Windows power users keep installed
One-click scans. No signup required.
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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then((fs) => fs.writeFile('shot.webp', data));
ScreenshotNeo also offers take_screenshot, get_page_info, and capture_pdf through its MCP server 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. Every feature is available on every plan, and yearly billing provides two months free.
Create a free ScreenshotNeo account to try the 1,000 monthly screenshots without a card.
Best Value
Practical troubleshooting checklist
- Wrong height: measure after all dynamic content, fonts, and lazy images have settled.
- Missing fixed controls: mark them with
data-html2canvas-ignoreor hide them inonclone. - Missing remote images: confirm server CORS headers;
useCORSalone is insufficient. - Cross-origin frame: html2canvas cannot access it; capture it independently or use an authorized browser workflow.
- Blank giant image: reduce scale or split the page because of dimension, area, or memory limits.
- Visual mismatch: test unsupported CSS, animations, transforms, plugins, and sticky positioning explicitly.
- Export failure: prefer
toBlobfor large outputs and check whether cross-origin content has tainted the canvas.
Frequently Asked Questions
Can html2canvas capture the page by scrolling repeatedly?
It can be combined with a stitching routine, but the normal full-page method is to render the scrolling element using its complete scroll dimensions in one call.
Does html2canvas create a native browser screenshot?
No. It reconstructs a canvas from DOM nodes and supported CSS, so fidelity depends on the properties and content it can reproduce.
Can I capture a cross-origin iframe with useCORS?
No. CORS image loading does not expose a cross-origin iframe’s document; only same-origin frames can be rendered recursively.
What should I use for a server-side capture?
Use a real browser automation workflow such as Puppeteer or Playwright, or a screenshot API such as ScreenshotNeo.
Quick Recap
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.

