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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

html2canvas does not automatically capture a video’s displayed frame. It reconstructs a page from DOM and CSS, so you need to draw the desired video frame to a canvas yourself, then add that image to the PDF with jsPDF. This guide covers capturing the current or a specific frame, composing it with page content, handling CORS and canvas limits, and troubleshooting blank output.

Why html2canvas leaves video out of the PDF

html2canvas is not a native screenshot tool. It traverses DOM and style information and rebuilds a rendering in a canvas. As its documentation explains, the result is based on information available on the page and may not match exactly what the browser paints. A video’s currently displayed pixels are not ordinary DOM content that html2canvas can reliably reconstruct.

The reliable approach is to capture the video frame explicitly: wait until the video has decoded data, draw its HTMLVideoElement into a canvas with the Canvas API, and then place the resulting image in the PDF. MDN documents video elements as supported sources for drawImage().

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

Capture the current frame and add it to a PDF

This browser-side example captures the current frame after the video has enough data, creates a PNG data URL, and adds it to a jsPDF document. It assumes jsPDF is already loaded and that the page contains a video with the ID video. For a module-based project, import jsPDF from the package you use and call this function from your application.

#1 Best Overall
Epson EcoTank ET-2800 Wireless Color All-in-One Supertank Printer - Black
  • INNOVATIVE CARTRIDGE-FREE PRINTING — No more dealing with lots of tiny ink cartridges; With this wireless document and photo printer each ink bottle set is equivalent to about 90 individual cartridges²
  • LESS FREQUENT INK REPLACEMENT — Replacement ink bottles don't have to be changed nearly as often as ink cartridges¹; When you choose this combination printer, scanner and copier you can print up to 4,500 pages black/7,500 color³
  • COLOR PRINTING — Up to 2 years of ink in the box4 (and with every replacement ink set) for fewer out-of-ink frustrations
  • ZERO CARTRIDGE WASTE — By using an Epson EcoTank printer you can help reduce the amount of cartridge waste ending up in landfills
  • HOME PRINTER DESIGNED FOR RELIABILITY — The Epson EcoTank ET-2800 All-in-One Supertank Color Printer creates vivid, detailed prints and documents thanks to Micro Piezo Heat-Free Technology; Fire off 10 ISO pages per minute1 to easily finish large jobs
async function makeVideoFramePdf() {
  const video = document.getElementById('video');
  if (!(video instanceof HTMLVideoElement)) {
    throw new Error('Video element #video was not found.');
  }

  // HAVE_CURRENT_DATA (2) means data for the current position is available.
  if (video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
    await new Promise((resolve, reject) => {
      video.addEventListener('loadeddata', resolve, { once: true });
      video.addEventListener('error', () => reject(new Error('Video failed to load.')), { once: true });
    });
  }

  if (!video.videoWidth || !video.videoHeight) {
    throw new Error('Video has no decoded frame dimensions yet.');
  }

  const canvas = document.createElement('canvas');
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
  const context = canvas.getContext('2d');
  if (!context) throw new Error('Could not create a 2D canvas context.');

  context.drawImage(video, 0, 0, canvas.width, canvas.height);
  const imageData = canvas.toDataURL('image/png');

  const { jsPDF } = window.jspdf;
  const pdf = new jsPDF({ orientation: canvas.width > canvas.height ? 'landscape' : 'portrait', unit: 'pt', format: 'a4' });
  const margin = 36;
  const pageWidth = pdf.internal.pageSize.getWidth();
  const pageHeight = pdf.internal.pageSize.getHeight();
  const scale = Math.min((pageWidth - margin * 2) / canvas.width, (pageHeight - margin * 2) / canvas.height);
  const width = canvas.width * scale;
  const height = canvas.height * scale;

  pdf.addImage(imageData, 'PNG', (pageWidth - width) / 2, (pageHeight - height) / 2, width, height);
  pdf.save('video-frame.pdf');
}

The canvas’s intrinsic dimensions come from video.videoWidth and video.videoHeight, the decoded media dimensions. The sizing calculation preserves the frame’s aspect ratio and fits it within an A4 page with margins. jsPDF’s API reference documents its page configuration and addImage method.

Check readiness before drawing

MDN notes that drawing a video correctly requires the media element’s readyState to be greater than 1. The example waits for loadeddata if the current frame is not ready. If playback has already begun, consider pausing the video before capture when you want a stable still. If the media errors or never emits loadeddata, do not continue with zero dimensions; surface a useful failure to the user.

Capture a particular point in the video

To capture a requested timestamp, set currentTime and wait for the seek operation to finish before calling drawImage(). Seeking is asynchronous; drawing immediately after assigning currentTime can capture the old frame or no usable frame.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function waitForEvent(target, eventName) {
  return new Promise((resolve, reject) => {
    target.addEventListener(eventName, resolve, { once: true });
    target.addEventListener('error', () => reject(new Error('Video media error.')), { once: true });
  });
}

async function seekVideo(video, seconds) {
  if (!Number.isFinite(seconds) || seconds < 0) {
    throw new Error('The requested time must be a non-negative number.');
  }
  if (video.readyState < HTMLMediaElement.HAVE_METADATA) {
    await waitForEvent(video, 'loadedmetadata');
  }
  if (Number.isFinite(video.duration) && seconds > video.duration) {
    throw new Error('Requested time is beyond the video duration.');
  }

  const sought = waitForEvent(video, 'seeked');
  video.currentTime = seconds;
  await sought;
  if (video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
    await waitForEvent(video, 'loadeddata');
  }
}

Call await seekVideo(video, 12.5) before drawing to capture near 12.5 seconds. A media file may seek to a nearby keyframe or report a duration that is not yet finite while streaming; validate the actual result with the target source and browser.

Use compositor-frame timing when it matters

For closer synchronization with a frame presented by the browser’s video compositor, requestVideoFrameCallback() can schedule work when a new frame arrives. MDN marks this API Baseline 2024, with support across current devices and browsers since October 2024; older environments may lack it. See MDN’s reference.

Rank #2
Sale
Epson EcoTank Photo ET-8550 Wireless Wide-Format All-in-One Tank Printer
  • CARTRIDGE-FREE PRINTING — Print lab-quality photos, graphics and creative projects; Get vibrant colors and sharp text with Epson's high-accuracy printhead and Claria ET Premium 6-color inks
  • INK BOTTLES — Save on photos1 and creative projects with affordable in-house printing; All-in-one printer allows you to print 4" x 6" photos for about 4 cents each vs. 40 cents with traditional ink cartridges1
  • LESS FREQUENT INK REPLACEMENT — Replacement ink bottles don't have to be changed nearly as often as ink cartridges¹; Printer, scanner and copier lets you print up to 6,200 color pages³
  • PRINT FOR LONGER — Up to 2 years of ink in the box² (and with every replacement ink set) for fewer out-of-ink frustrations with this wireless printer
  • ZERO CARTRIDGE WASTE — Epson EcoTank printer helps reduce the amount of cartridge waste ending up in landfills; Cartridge-free printer uses high-yield ink bottles; Each replacement ink bottle set is equivalent to about 100 individual ink cartridges⁴
function waitForNextVideoFrame(video) {
  if (typeof video.requestVideoFrameCallback !== 'function') {
    return Promise.resolve(); // Fall back to readyState/seeked-based capture.
  }
  return new Promise(resolve => {
    video.requestVideoFrameCallback(() => resolve());
  });
}

// After starting playback or completing a seek:
await waitForNextVideoFrame(video);
context.drawImage(video, 0, 0, canvas.width, canvas.height);

This callback is useful when you need to align capture work with a newly presented frame rather than simply the media element’s current position. It is not a substitute for checking that the video has decoded dimensions and usable data.

Compose the frame with the rest of the page

There are two practical ways to combine a frame with other content, and the right choice depends on whether you prioritize matching the DOM layout or placing the frame precisely on a PDF page.

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

Put the prepared still in the DOM before html2canvas

Convert the frame canvas to an image or use the canvas element itself in a visible capture area, then run html2canvas on the surrounding page. This keeps the still aligned with nearby DOM content such as labels, captions, and layout. Ensure the image is available before starting html2canvas; an asynchronous image conversion or render that finishes later can leave the captured area empty.

const frameImage = document.createElement('img');
frameImage.alt = 'Selected video frame';
frameImage.src = canvas.toDataURL('image/png');
document.querySelector('#pdf-content').appendChild(frameImage);

const rendered = await html2canvas(document.querySelector('#pdf-content'));
const { jsPDF } = window.jspdf;
const pdf = new jsPDF('p', 'pt', 'a4');
pdf.addImage(rendered.toDataURL('image/png'), 'PNG', 0, 0, 595, 842);
pdf.save('page-with-video-frame.pdf');

The dimensions shown are an approximate A4 page size in points; for production, calculate page bounds and margins rather than assuming that the rendered content fits. html2canvas supports only the CSS and browser information it can inspect, so test the resulting composition against your actual layout.

Insert the still separately with jsPDF

Alternatively, render the surrounding DOM with html2canvas, then call jsPDF’s addImage separately for the video still. This gives direct control over the frame’s PDF coordinates and size, which can be useful for layouts where the frame needs a fixed position. You must calculate the placement in the PDF’s configured units and prevent the frame from overlapping the rendered page content.

Rank #3
HP Smart Tank 5000 Wireless All-in-One Ink Tank Printer, Scanner, Copier with 2 Years of Ink Included, Best-for-Home, Cartridge-Free, Refillable and AI-Enabled. (5D1B6A)
  • SET IT UP ONCE AND PRINT WITH CONFIDENCE. No complicated maintenance. Just easy, reliable printing you can count on.
  • INK FOR YEARS. NOT MONTHS. Up to 2 years of ink included. Get thousands of pages of cartridge-free printing. More pages, less hassle
  • KEEPS PRINTING WELL AFTER COMPETITORS HAVE QUIT. No complex maintenance. Sharper text, richer colors.[2] Only with HP Smart Tank
  • PREMIUM SUPPORT - Strong technical expertise to solve issues faster
  • THE LAST PRINTER YOU'LL EVER NEED. Enjoy years of refillable, cartridge-free printing.

The official API documentation establishes the relevant APIs, but there is no universal performance or layout winner: the choice depends on your page design, content flow, and required positioning.

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

Handle CORS, embeds, and canvas export

A video that plays in the page is not necessarily readable by a canvas. If the video or images come from another origin, browser security rules can taint the canvas and block export. The html2canvas FAQ explains that cross-origin resources are skipped by default when they would taint its canvas, and that useCORS: true only works when the remote server supplies appropriate Access-Control-Allow-Origin headers. A same-origin proxy is another documented option.

  • For a video hosted on another origin, the server must allow the page’s origin for the media request; set the element’s crossOrigin property before assigning its source where applicable, and configure the server’s CORS response headers.
  • For html2canvas DOM rendering, useCORS: true can request eligible images with CORS, but it cannot override a server that denies access.
  • Cross-origin iframe documents are inaccessible to html2canvas. A player embedded in an iframe cannot be inspected as if it were same-origin page DOM.
  • A canvas becomes tainted if a non-CORS-approved resource is drawn into it. Once tainted, converting it with toDataURL() or exporting it may throw a security error; fixing the resource access is required.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Canvas size, image quality, and performance

Using the source video’s decoded dimensions preserves its native frame resolution, but large canvases consume memory and can exceed browser limits. The html2canvas FAQ gives rough current evergreen-browser guidance as accessed in 2026: Chrome/Chromium maximum canvas area around 268 megapixels, Firefox around 472 megapixels, and maximum dimensions around 32,767 pixels for Chrome/Chromium, Firefox, and desktop Safari. These are approximate limits, not stable guarantees; platform, GPU, operating system, RAM, and browser version can lower them. iOS Safari limits are lower and device-dependent.

If a frame is much larger than its PDF display size, scale it down deliberately when drawing to the canvas to reduce memory use and PDF size. The Canvas API’s source-and-destination rectangle overload supports cropping and scaling. Do not enlarge a small source frame expecting sharper detail. If the PDF will be printed or zoomed, test quality at the intended output size.

html2canvas runs in the browser and depends on browser APIs. Its FAQ suggests headless browser drivers such as Puppeteer or Playwright when server-side screenshot generation is required. A client-side capture can also be affected by slow media loading, network interruptions, and the page’s own rendering workload, so keep waits tied to media events rather than relying on a short arbitrary delay.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
NDYIN Portable Printers Wireless for Travel, N80 Bluetooth Thermal Printer
  • Wireless Bluetooth Printer: Portable thermal printer compatible with iPhone, Android phones, iPad and tablet computers via Bluetooth. For smartphones, please download the "Nada Print" App. You can also connect to laptops and computers for printing using a USB-C cable. (Note: Laptops and computers can only be connected via USB and require the installation of a driver first. Bluetooth connection is not supported.)
  • No-ink printing: Only supports US Letter and A4 size thermal paper.(Doesn't support regular paper) The no-ink portable thermal printer uses direct thermal technology, requiring no ink, toner or ribbons, making it environmentally friendly, cost-effective and time-saving. The thermal printer package comes with a roll of US Letter thermal printing paper. Note: When installing the paper, remember to switch the paper size switch on APP
  • Clear Print: NDYIN N80 portable thermal printer adopts high-definition printing technology, with a 203DPI resolution to provide you with clear printing results. This mobile printer is compatible with roll paper, folded paper and tattoo transfer paper, supporting printing from your mobile phone PDF, Word, pictures and web pages anytime and anywhere. It is recommended to use our NDYIN thermal paper to achieve good printing quality
  • Portable wireless printer for travel: The thermal printer is equipped with a built-in 1500mAh rechargeable battery, which can print 160 sheets of 8.5" x 11" thermal paper after being fully charged. It weighs only 1.5 pounds and is compact in size. This ink-free portable printer can be easily carried in a backpack or briefcase! It is perfect for business travel, cars, small offices, construction sites, schools and homes. You can print documents, contracts, invoices and boarding passes anytime and anywhere
  • The N80 thermal printer has a wide range of uses. The package includes the N80 printer, a roll of US Letter paper(7m/roll), a user manual, a guide card, a type-C soft cable and a type C adapter. Note: The charging adapter is not included. Special thermal paper is required for use; ordinary paper cannot be used. This ink-free portable thermal printer is suitable for various scenarios such as home, school, travel, office, and outdoor, meeting the printing needs of different groups of people. This tattoo template printer is also compatible with tattoo transfer paper, making it an ideal choice for tattoo art

Troubleshooting common failures

Symptom Likely cause What to do
Video is blank in the PDF The video was not explicitly drawn, or data for the current frame was not ready. Wait for readyState > 1 or loadeddata, check non-zero videoWidth/videoHeight, then draw the video to a canvas before adding the image.
Wrong frame after seeking Capture ran before asynchronous seeking completed. Wait for the video’s seeked event after assigning currentTime; optionally wait for a compositor frame callback where supported.
toDataURL() throws a security error A cross-origin resource tainted the canvas. Use media hosted on the same origin, configure valid CORS response headers and request CORS appropriately, or use a same-origin proxy. A client-side flag cannot bypass CORS policy.
html2canvas omits an image or part of an embedded player The remote resource lacks CORS permission or the content is inside a cross-origin iframe. Serve an accessible image or prepared frame, configure CORS, or avoid relying on inaccessible iframe contents.
Canvas is blank, partial, or export fails only on some devices The canvas exceeded a device or browser limit. Reduce capture dimensions or split the page into smaller regions; test on the actual target device, especially iOS Safari.
PDF layout differs from the browser page html2canvas reconstructs the DOM and does not support every CSS property exactly as the browser paints it. Inspect the rendered canvas separately, simplify unsupported styling, and insert the video image directly with jsPDF when precise placement is needed.

Or skip the browser setup

If your goal is to capture a website page as an image or PDF rather than to export a frame from a particular HTML video element, ScreenshotNeo is a website screenshot API and MCP server. A single request can return a screenshot or PDF, but it does not replace the explicit video-frame capture technique above.

For example, this cURL request captures a website screenshot:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for setup and options. Its consent handling can accept cookie banners and remove known consent platforms, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are not billed. Its MCP server exposes screenshot tools for AI agents. The Free plan includes 1,000 shots per month with no card, and paid plans start at $5 for 3,000 shots.

Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month with no card.

Free tools Windows power users keep installed

One-click scans. No signup required.

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

Frequently asked questions

Can I capture a frame from a YouTube or other iframe player?

Not by reading a cross-origin iframe’s internal video element with html2canvas. The browser’s same-origin policy prevents access to the embedded document. Use a source or integration that provides an accessible frame, or capture content you control.

Does requestVideoFrameCallback replace the seeked event?

No. For a requested timestamp, wait for the seek to complete. The callback is useful for scheduling work around a presented frame; it does not make a cross-origin video readable or guarantee support in older browsers.

Can html2canvas generate the PDF on a server?

html2canvas is a browser-side library. For server-side page rendering, its FAQ points to browser automation such as Puppeteer or Playwright instead.

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.

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