Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsDirect fix: jsPDF’s html() method requires html2canvas. Install or import html2canvas in the browser bundle, or load its script before calling pdf.html(). If you pass an HTML string rather than a DOM element, also provide DOMPurify. The conversion must run in a real browser, not Node.js.
What the error means
When the console says html2canvas is not loaded, is undefined, or pdf.html() fails immediately, jsPDF has reached a missing dependency. The html() method delegates page rendering to html2canvas, which turns the DOM into a canvas before jsPDF writes the PDF.
This is different from a blank PDF after successful loading. A missing global is a load or bundling problem; a blank or partial PDF can result from cross-origin assets, an oversized canvas, or content that has not finished rendering.
Fix it in a module or npm build
Install the browser dependencies
Install jsPDF and html2canvas in the application that executes in the browser. The html2canvas project documents this package name:
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, 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#1 Best Overall
npm install jspdf @html2canvas/html2canvas
Import the dependency before the code that invokes html():
import { jsPDF } from "jspdf";
import html2canvas from "@html2canvas/html2canvas";
// This reference makes the dependency explicit to the bundler.
void html2canvas;
export function exportElement() {
const element = document.getElementById("content");
if (!element) throw new Error("#content was not found");
const pdf = new jsPDF({ unit: "mm", format: "a4" });
pdf.html(element, {
callback: (doc) => doc.save("output.pdf")
});
}
Some bundlers include html2canvas automatically when you import the full jsPDF distribution; an explicit import still makes dependency ownership and versioning clear. Keep the function on a browser-only path. Do not execute it during server-side rendering, at module evaluation time in a server process, or in a Node.js script.
Run after the DOM exists
Call the function from a click handler, a browser lifecycle hook, or another point after the target element has been mounted. A module can load correctly while still failing because document.getElementById("content") returns null or because images and fonts are still loading.
Fix it with script tags
Use the required order
For an unbundled html2pdf.js setup, load jsPDF first, html2canvas second, and html2pdf third:
Rank #2
<script src="jspdf.min.js"></script>
<script src="html2canvas.min.js"></script>
<script src="html2pdf.min.js"></script>
Bundled html2pdf.js builds include their dependencies. With an unbundled wrapper, however, the order matters because each layer expects the previous one to be available. Pin one compatible version of each script rather than mixing copies from different releases.
Call jsPDF after all scripts finish
function makePdf() {
if (typeof window.html2canvas !== "function") {
throw new Error("html2canvas did not load");
}
const content = document.getElementById("content");
if (!content) throw new Error("#content was not found");
const pdf = new jspdf.jsPDF();
pdf.html(content, {
callback: function (doc) {
doc.save("output.pdf");
}
});
}
window.addEventListener("DOMContentLoaded", makePdf);
The typeof check is a quick diagnostic for script-tag builds. If it fails, inspect the browser’s Network and Console panels for a 404, blocked CDN request, failed integrity check, or Content Security Policy violation.
Bundled versus unbundled html2pdf.js
| Setup | Dependency handling | What you must verify |
|---|---|---|
| Bundled build | jsPDF, html2canvas and html2pdf are packaged together. | Use the documented entry point and avoid loading a second copy globally. |
| Unbundled scripts | Each library is downloaded independently. | Load jsPDF → html2canvas → html2pdf, keep versions consistent, and wait for every script. |
| ES module build | The bundler resolves imported packages. | Import html2canvas in the browser bundle and do not run the conversion during SSR or in Node.js. |
Why it still fails after html2canvas loads
The code is running in Node.js
html2canvas uses window, document, computed styles and other browser APIs. It is not suitable for Node.js. Move the conversion into client-side code, or use a browser automation or hosted screenshot service when the job must run on a server.
A script is blocked or loaded at the wrong path
Open DevTools and reload the page. A failed Network request, an integrity mismatch, or a CSP error leaves the global undefined even though the HTML contains a script tag. Correct the URL or CSP policy, remove duplicate versions, and confirm that the response is JavaScript rather than an error page.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →The target is not ready
Wait until the element is mounted and any application data, web fonts, and images have settled. A click handler is safer than invoking conversion while a framework is rendering. Confirm the selector and temporarily export a small, static element to separate timing problems from rendering problems.
Images come from another origin
html2canvas can taint the canvas when it reads images or other resources from a different origin. The remote server must send suitable CORS headers. Its useCORS option requests CORS-enabled loading; it cannot grant permission to a server that sends no permission.
const pdf = new jsPDF();
pdf.html(document.getElementById("content"), {
html2canvas: {
useCORS: true
},
callback: (doc) => doc.save("output.pdf")
});
Alternatively, proxy the asset through your own origin, host it locally, or omit the problematic image. Check the Console for canvas-taint messages and verify the image response headers.
The canvas is too large
Very tall or wide documents can exceed browser canvas limits. The result may be blank or only partly rendered without a useful JavaScript exception. Reduce the capture width, lower the scale, shorten the document, or split it into sections and generate multiple pages. Test with a smaller viewport before increasing dimensions again.
Recommended Free Tools
Rank #4
Duplicate or incompatible libraries are present
A page that loads one html2canvas globally and bundles another copy can pass a superficial existence check while jsPDF uses a different object. Remove duplicate tags, let the bundler own the dependency, and inspect the generated bundle or import graph so the symbol used by the calling code is the one actually loaded.
A reliable diagnostic checklist
- Confirm the conversion runs in a browser context with
windowanddocument. - Confirm the target element exists and is visible when
html()starts. - For modules, install and import
@html2canvas/html2canvasbefore the export path. - For script tags, verify jsPDF → html2canvas → html2pdf order.
- Run
typeof window.html2canvasand expect"function"in a script-tag build. - Use DevTools Network and Console to find blocked, missing, or disallowed scripts.
- Remove duplicate versions and retest with a minimal same-origin element.
- If loading succeeds but output is blank, investigate CORS and canvas dimensions rather than reinstalling the package.
When to use a server-side capture instead
Client-side html2canvas is useful when the user is already viewing the page and the content is same-origin and moderate in size. A hosted capture is simpler for scheduled jobs, backend workflows, pages requiring a consistent browser environment, or URLs you do not control. It also avoids shipping a rendering stack to every visitor.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server for developers. One GET request returns PNG, JPEG, WebP or PDF, so your server does not need to load jsPDF and html2canvas in a browser. Cookie and consent banners, newsletter popups and chat widgets are removed before the shot. Bot checks, blank pages, failed loads and timeouts are not billed, and the response identifies the page verdict and billing status in headers.
One-call example
See the parameter reference in the ScreenshotNeo documentation.
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(`${res.status} ${res.statusText}`);
const data = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', data));
ScreenshotNeo also supports full-page captures with lazy images, CSS-selector element shots, dark mode, device presets, custom viewports, retina scale, PDF paper and margin settings, custom CSS and JavaScript, clicks, waits, request blocking, cookies, headers, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. An MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
Best Value
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account to try the hosted path.
FAQ
Does importing html2canvas alone fix a blank PDF?
No. Importing fixes a missing dependency. A blank result after successful loading requires checking cross-origin resources, document dimensions, rendering timing and browser canvas limits.
Can I call pdf.html() from a Web Worker?
The documented dependency requires browser DOM APIs, so code that has no window or document cannot provide the environment html2canvas expects.
Should I load both html2pdf.js and html2canvas manually?
Only for an unbundled setup. A bundled html2pdf.js build is intended to include its dependencies; manually adding another copy can create version conflicts.
Frequently Asked Questions
Does importing html2canvas alone fix a blank PDF?
No. Importing fixes a missing dependency. A blank result after successful loading requires checking cross-origin resources, document dimensions, rendering timing and browser canvas limits.
Can I call pdf.html() from a Web Worker?
The documented dependency requires browser DOM APIs, so code that has no window or document cannot provide the environment html2canvas expects.
Should I load both html2pdf.js and html2canvas manually?
Only for an unbundled setup. A bundled html2pdf.js build is intended to include its dependencies; manually adding another copy can create version conflicts.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →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.

