To capture a video at a particular time, wait for its metadata, set the video element’s currentTime, wait for the seeked event, and then screenshot the video element with Puppeteer or Playwright. For a frame already on screen, skip the seek and use the framework’s element screenshot method. If you need image pixels for processing rather than a screenshot of what the browser rendered, use canvas—but cross-origin video can prevent canvas export.
Choose the right capture method
There are two different jobs that are often both called “taking a video screenshot”:
- Capture the rendered player: use a screenshot API on the video element. This is usually the simplest way to save the frame the browser displays.
- Capture pixels for image processing: draw the video onto a canvas and export the canvas. This gives you image data to manipulate, but it is subject to cross-origin restrictions.
For a specific media time, first seek the HTML <video> element and wait for the browser to finish seeking. A completed seek does not guarantee frame-accurate results for every codec, browser, or streaming player; the documented APIs establish the seek lifecycle, not universal precision at arbitrary timestamps.
Capture a video frame at a specific time
What the video events tell you
loadedmetadata indicates that media metadata is available, so values such as duration can be used. loadeddata indicates that the first frame has loaded. The seeked event fires after a seek completes, the playback position changes, and the element is no longer seeking. Install event listeners before setting currentTime so a fast event is not missed.
#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
Reusable browser-side seek helper
The following function is intended to run inside the page. It waits for metadata if necessary, validates the requested time, pauses playback, and handles media errors and timeouts. If the video is already at the requested time, it does not wait for an event that may never fire.
async function seekVideo(video, seconds, timeoutMs = 15000) {
if (!(video instanceof HTMLVideoElement)) {
throw new Error('The selected element is not a video.');
}
const waitFor = (eventName) => new Promise((resolve, reject) => {
const timer = setTimeout(() => {
cleanup();
reject(new Error(`Timed out waiting for ${eventName}.`));
}, timeoutMs);
const cleanup = () => {
clearTimeout(timer);
video.removeEventListener(eventName, onEvent);
video.removeEventListener('error', onError);
};
const onEvent = () => { cleanup(); resolve(); };
const onError = () => {
cleanup();
reject(video.error || new Error('Video failed to load.'));
};
video.addEventListener(eventName, onEvent, { once: true });
video.addEventListener('error', onError, { once: true });
});
if (video.readyState < HTMLMediaElement.HAVE_METADATA) {
await waitFor('loadedmetadata');
}
if (!Number.isFinite(seconds) || seconds < 0) {
throw new Error('Time must be a non-negative number of seconds.');
}
if (Number.isFinite(video.duration) && seconds > video.duration) {
throw new Error(`Requested time exceeds video duration (${video.duration}s).`);
}
video.pause();
if (Math.abs(video.currentTime - seconds) < 0.01 && video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
return;
}
const seekFinished = waitFor('seeked');
video.currentTime = seconds;
await seekFinished;
if (video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
await waitFor('loadeddata');
}
}
The tolerance check avoids waiting on an unchanged playback position; it is not a claim about frame accuracy. A live stream may have an unknown duration, and a seek outside its available seekable range may fail or be adjusted by the player. For those cases, inspect video.seekable and use a time within an available range.
Capture with Puppeteer
This Node.js example opens a page, locates its first video, seeks to 12.5 seconds, and saves only the video element as a PNG. Install Puppeteer in your project first with npm install puppeteer. The page may need authentication, navigation waits, or a selector more specific than video.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com/video-page', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('video');
const video = await page.$('video');
await page.evaluate(async (seconds) => {
const video = document.querySelector('video');
// Insert the seekVideo helper from above into this page context.
await seekVideo(video, seconds);
}, 12.5);
await video.screenshot({ path: 'frame.png' });
} finally {
await browser.close();
}
})();
For the code to run as written, define seekVideo in the page context first. One straightforward option is to pass its function body to page.evaluate, or register it with page.evaluateOnNewDocument before navigation. Puppeteer’s page.screenshot() captures the page; ElementHandle.screenshot() captures a particular element. For a player-only image, the element method avoids including surrounding page content.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesRank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
Capture with Playwright
Install the Node.js package with npm install playwright and install its browser binaries as directed by the package. The example uses a locator screenshot and the same seek lifecycle. It returns a buffer if no path is supplied; here it writes directly to a file.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com/video-page', { waitUntil: 'domcontentloaded' });
const video = page.locator('video').first();
await video.waitFor({ state: 'visible' });
await page.evaluate(async (seconds) => {
const video = document.querySelector('video');
// Define seekVideo in the page context using the helper above.
await seekVideo(video, seconds);
}, 12.5);
await video.screenshot({ path: 'frame.png' });
} finally {
await browser.close();
}
})();
As with Puppeteer, make the helper available within the page before invoking it. For example, serialize the function into an initialization script and expose it on window, or place its logic directly inside page.evaluate. Use a selector tied to the intended player when a page has multiple videos. A full-page capture is a separate option in Playwright: page.screenshot({ path: 'page.png', fullPage: true }).
Screenshot the current frame without seeking
If the exact time does not matter, wait for the player to be visible and for it to have frame data, then take its element screenshot. This avoids changing playback state and is useful for a thumbnail of whatever frame is currently displayed.
await page.waitForFunction(() => {
const video = document.querySelector('video');
return video && video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA;
});
await page.locator('video').first().screenshot({ path: 'current-frame.png' });
For Puppeteer, replace the final line with (await page.$('video')).screenshot({ path: 'current-frame.png' }). If playback is running, pause it first when you need a stable displayed frame. A video can exist in the DOM before it has loaded usable image data, so merely waiting for the selector is not enough.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
Use canvas when you need image pixels
Canvas is useful when the next step is pixel analysis, cropping, compositing, or converting the frame. After the video has loaded and sought, draw its frame into a canvas and export it:
const canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const context = canvas.getContext('2d');
context.drawImage(video, 0, 0, canvas.width, canvas.height);
const blob = await new Promise((resolve, reject) => {
canvas.toBlob(value => value ? resolve(value) : reject(new Error('Canvas export failed.')), 'image/png');
});
Canvas dimensions come from the decoded video dimensions, not necessarily the CSS size of the player. If you need a file in Node.js, transfer the blob’s bytes out of the page and write them with Node’s filesystem API.
Why cross-origin export can fail
When video data comes from another origin without CORS approval, drawing it can taint the canvas. Reading pixels or exporting with toBlob() or toDataURL() can then throw a SecurityError. Set the video’s crossorigin attribute before its media source loads, using a mode supported by the server, and ensure the media server sends an allowing CORS response header. The attribute alone cannot grant permission. A browser screenshot of rendered content and exporting canvas pixels are different operations: the latter is subject to this canvas security rule.
When a frame stream or recording is the real requirement
A still image at one media timestamp is not the same thing as collecting browser frames over time. Playwright documents a page screencast facility that can deliver JPEG frames with timestamps and viewport dimensions. The feature is version-sensitive: the Playwright reference lists it as added in v1.59, so check that the installed version supports the API before building around it. It produces a sequence of page frames, not a seek operation on the video element.
Recommended Free Tools
Rank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
Puppeteer’s documented Page.screencast() reference marks that API obsolete, says it works with Chrome 153 or newer, and recommends Page.record(); its described recording workflow requires ffmpeg. Check your installed Puppeteer and browser versions before relying on that route. For a single still, use a normal page or element screenshot instead of introducing recording dependencies.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. It can capture the rendered page or player, but it does not replace the video seek step above: seek the page’s video to the desired time before requesting a capture if the page is under your control. A screenshot API cannot promise arbitrary timestamp seeking inside every third-party player.
Here is a one-request capture of a page as rendered:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/video-page -o shot.webp
See the ScreenshotNeo API documentation for authentication and request options. Cookie banners are accepted and more than 60 known consent platforms, newsletter popups, and chat widgets are removed before capture; each cleanup step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers. Its MCP server offers 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.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
Best Value
- 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
- Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
- Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
- HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
- What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
Troubleshoot common failures
The screenshot shows the wrong or an old frame
- Wait for
seekedafter settingcurrentTime; do not take the screenshot immediately after assigning the time. - Confirm that the video has frame data, such as
readyState >= HAVE_CURRENT_DATA, and wait forloadeddatawhen needed. - Pause playback before capturing if it might advance while the browser takes the screenshot.
- Check that the selector resolves to the intended video, especially on pages with preview clips or hidden players.
The wait for metadata, seek, or frame data times out
- Check whether the page actually loaded a video element and whether its media request failed.
- Inspect the element’s
error,readyState,currentTime, andseekableranges in the page. - Use a time inside the available range. Live or segmented streams may not expose a simple seekable timeline.
- Increase the timeout only when slow loading is expected; a longer timer does not fix a failed or inaccessible media request.
Canvas export throws SecurityError
Check the media origin, set crossorigin before loading the source, and verify that the server authorizes the requesting origin with CORS. If you only need an image of what is visible, use a browser element screenshot instead of canvas export.
The page has no usable video element
Some player implementations do not expose a straightforward HTML video element or controllable seek path. Inspect the page and player behavior rather than assuming the generic snippets apply. The cited API references do not establish a general method for protected or DRM streams.
Practical reliability and cost considerations
Capturing one still through Puppeteer or Playwright involves browser automation and the page’s own media loading; a canvas export adds origin-permission constraints. A recording or screencast adds a different workflow, version compatibility, and—in Puppeteer’s documented recording route—an ffmpeg dependency. Choose the least complex path that produces the needed output.
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 minuteFor repeatable captures, make the page state explicit: use a stable player selector, wait for the intended readiness events, seek to a valid time, and set a finite timeout with a useful error message. If you are capturing many timestamps, reuse the browser rather than launching a new one for every frame, while still waiting for each seek to finish. Do not infer exact codec-level frame accuracy from a successful seeked event; verify output on the specific browser, media, and player combination when precision matters.
Frequently Asked Questions
Can I use either framework with JavaScript or TypeScript?
Yes. The examples use Node.js JavaScript; TypeScript can use the same browser APIs with suitable package typings.
Does a page screenshot capture just the video?
No. A page screenshot captures page content; use the video element’s screenshot method when you want the player alone.
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.
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 →

