Use a canvas. Wait for the HTML video’s metadata, seek to the required timestamp, draw the rendered frame at the video’s intrinsic dimensions, and export the canvas as a JPEG with toBlob('image/jpeg', quality). The method works for same-origin media and media servers that authorize your page with CORS. Without that authorization, the browser may display the video but will block pixel readback with a tainted-canvas SecurityError.
The browser pipeline
A video element exposes its current playback frame and its intrinsic dimensions through video.videoWidth and video.videoHeight. A reliable JPG capture follows this order:
- Load metadata and confirm that dimensions are available.
- Set
currentTimewhen a particular timestamp is required. - Wait for
seeked, so the requested frame has actually been rendered. - Size a canvas to the intrinsic video dimensions.
- Call
drawImage()and encode the canvas as JPEG.
A paused video represents the frame at its current playback position. For a live stream, however, exact seeking might not exist; capture the currently rendered frame and tell users that the result is live-position rather than timestamp-accurate.
Complete browser example: save one frame as JPG
This self-contained page captures 12.5 seconds from a video, preserving the source pixel dimensions rather than the displayed CSS size.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
- 4K Pass Through & Full HD Recording: Experience 4K content on TV while capturing in full HD with EzRecorder 330. Compatible with PS5, Nintendo Famicom, and set-top boxes (recording of encrypted or HDCP content is not supported). Ideal for digitizing VHS tapes.
- High Efficiency Video Coding (HEVC - H.265): Enjoy 2x compression rate with H.265 encoding. Maintains exceptional video quality while saving storage space.
- Remote Operation and Included IR Blaster: Control EzRecorder 330 with ER330G remote (batteries not included). Built-in IR blaster for set-top box activation.
- Flexible Storage Solutions: Record content using external hard drives, micro SD cards, or NAS storage. Choose the storage device that suits your needs effortlessly. Note: SD card not included.
- Stream Directly Without a PC: Connect gaming consoles, camcorders, or DSLRs directly to EzRecorder 330. Effortlessly broadcast to YouTube, Facebook, or Twitch without complex setups.
<video id="source" src="video.mp4" crossorigin="anonymous" preload="metadata" controls></video>
<button id="save">Save JPG</button>
<script>
const video = document.querySelector('#source');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
async function frameAsJpeg(time, quality = 0.92) {
await new Promise((resolve, reject) => {
if (video.readyState >= 1) return resolve();
video.addEventListener('loadedmetadata', resolve, { once: true });
video.addEventListener('error', () => reject(video.error), { once: true });
});
if (Number.isFinite(time)) {
const end = Number.isFinite(video.duration) ? video.duration : time;
video.currentTime = Math.max(0, Math.min(time, end));
await new Promise((resolve, reject) => {
video.addEventListener('seeked', resolve, { once: true });
video.addEventListener('error', () => reject(video.error), { once: true });
});
}
if (!video.videoWidth || !video.videoHeight) {
throw new Error('Video dimensions unavailable');
}
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
return new Promise((resolve, reject) => {
canvas.toBlob(blob => {
if (blob) resolve(blob);
else reject(new Error('JPEG encoding failed'));
}, 'image/jpeg', quality);
});
}
document.querySelector('#save').onclick = async () => {
try {
const blob = await frameAsJpeg(12.5, 0.92);
const link = Object.assign(document.createElement('a'), {
href: URL.createObjectURL(blob),
download: 'frame-12.5s.jpg'
});
link.click();
URL.revokeObjectURL(link.href);
} catch (error) {
console.error(error);
alert(error.message);
}
};
</script>
Set crossorigin="anonymous" before assigning the source when the media is hosted on another origin. The media server must return an Access-Control-Allow-Origin value that permits the page. The attribute alone cannot grant permission.
Choosing a timestamp and getting dependable results
Wait for metadata
Before loadedmetadata, the media element is in the HAVE_NOTHING state: duration and intrinsic dimensions can be zero. Reading videoWidth, videoHeight, or duration earlier can produce invalid canvas sizes or an incorrect clamp for the requested time.
Seek, then capture
Assigning currentTime starts an asynchronous seek. Drawing immediately can capture the previous frame or an intermediate buffering state. The seeked event indicates that the seek has completed. For a timestamp near the end, clamp the value to the known duration; a source may also report an unknown or infinite duration.
Understand frame accuracy
Media seeking is time-based, while compressed video is commonly decoded around keyframes. The browser selects the frame it can present for the requested position; do not describe this as guaranteed source-frame indexing. If your application needs to show the actual captured time, display the requested timestamp and, where appropriate, the element’s current time after seeking.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Rank #2
- 【Real USB3.0 YUY2 1080P 60FPS Capture Card】It is a real USB3.0 HDMI capture card with real USB3.0 protocol chipset, fast transfer rate and low power consumption. It can support capture YUY2 1080P 60FPS resolution,share superb game skills with excellent visual experience.
- 【Support 4K@30Hz Input and Pass-through】This capture card supports 4K@30Hz input and 4K@30Hz Zero Latency Pass-through.The capture resolution of this game capture card can reach up to 1080p 60fps; Note: USB3.0 output can only reach up to 1080P 60FPS, HDMI OUT output can reach 4K 30FPS.The capture card for streaming is suitable for high definition acquisition, live broadcasts, video recording, conference rooms etc.
- 【Support Mic-in for Commentary】This audio video capture card allows you to plug in a 3.5mm headset or microphone so you can easily stream your voice and record your voice through the port. For example, add external audio to a live game or interview. Note: it does not record party chats.
- 【Plug & Play】Once plugged in, the capture card is identified automatically. No drivers or external power supply required.Detects inputs and automatically adjusts outputs. you can use third party software to capture or stream your HD gaming video sources. Capture cards for streaming are very effective for recording game play.
- 【Compatible with Multiple Systems】This 4K capture card suitable for Windows Unix,Mac OS,Windows 7/8/10/11, Android and more. It is compatible with most devices such as Wii U, PS3, PS4, PS5, Xbox One, Xbox 360, Wii, Switch, DVDs, DSLR Camera, ZOSI Security Camera and set top box etc. Make it easier to provide live streaming for Twitch, Youtube, OBS, Facebook live, skype, XSplit, Tiktok, Potplayer and VLC.
Use a sensible JPEG quality
The quality argument is normally between 0 and 1. A value such as 0.92 is a practical starting point; lower values produce smaller files and more visible compression. toBlob() is preferable for normal downloads because it avoids creating a large base64 string. Use toDataURL('image/jpeg', quality) only when an API specifically requires a data URL.
Export alternatives: Blob, data URL, and resized output
JPEG Blob
toBlob() returns an encoded binary object asynchronously. Create an object URL for a download or upload the Blob with fetch or FormData. Revoke object URLs after use to release browser memory.
Data URL
const dataUrl = canvas.toDataURL('image/jpeg', 0.9); is convenient for an <img> element or JSON payload, but base64 expands data and duplicates it in JavaScript strings. Avoid it for high-resolution or batch captures unless the receiving interface requires it.
Resizing deliberately
To make a thumbnail, draw into a second canvas whose width and height preserve the source aspect ratio. Do not use the video’s CSS dimensions accidentally: a small, responsive player can otherwise produce a low-resolution JPG even when the source is large.
Rank #3
Why “tainted canvas” errors happen
If pixels from another origin are drawn without a successful CORS handshake, the canvas becomes tainted. Calling toBlob(), toDataURL(), getImageData(), or captureStream() on that canvas then throws a SecurityError (or refuses to return pixels). The video can still look normal because displaying media does not grant script access to its decoded pixels.
Correct server and client configuration
- Configure the media host to send
Access-Control-Allow-Originfor your page’s origin (or an appropriate wildcard policy for non-credentialed media). - Set
crossorigin="anonymous"on the video before settingsrc. - Ensure redirects, CDN responses, byte-range requests, and error responses carry compatible CORS headers.
- Do not send credentials unless the server is configured for credentialed CORS; wildcard origin responses cannot be used with credentials.
Client-side JavaScript cannot override a server that withholds permission. If you cannot change that server, capture must happen in a context that has authorization, or on the server side where you control the request.
Capturing many frames or a continuous stream
Repeated timestamp captures
For a contact sheet, call the same function sequentially for an array of times. Await each capture before the next seek; concurrent assignments to currentTime race and can resolve with the wrong frame. Keep the canvas and context, but encode each Blob before replacing references so memory remains bounded.
HTMLMediaElement.captureStream()
video.captureStream() produces a real-time MediaStream of the media rendered by the element. It is designed for recording or piping frames to another media API, not for directly producing individual JPG files. Browser support and behavior vary because the related media-capture specifications remain Working Drafts.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Rank #4
- RECORD AND CONVERT: A capture card that has the ability to record videos or audio files. Records full HD 1080p video quality with an HDMI pass through support. After recording, it also converts the file into digital format
- STREAM LIVE: This video game capture device has the ability to instantly stream live on social media and YouTube while playing. It can play and record simultaneously for a hassle free media file creation
- HOT BUTTON RECORDING: Manage recorded media easily and post to social media like YouTube. It has an on-board hot button for one-click recording and screenshot capture ability
- PLUG AND PLAY: No installation needed, simply plug and play this device to start recording, It also has a built-in software that supports voice commentary and multi language support
- COMPATIBLE DEVICES: This capture card can record videos from any devices with HDMI output like Xbox 360, Xbox One, PS4, PS3, Wii U, PC computers, PS3, PS4, Blu-ray DVD player, Set-top Box, and DVR
Manual frame requests from a canvas
canvas.captureStream(0) creates a stream with a zero automatic frame rate. Where supported, call the video track’s requestFrame() after drawing to request a frame manually. The canvas must remain origin-clean; CORS restrictions still apply.
ImageCapture when a track already exists
If you already have a MediaStreamTrack, ImageCapture.grabFrame() returns an ImageBitmap, which you can draw to a canvas and encode. takePhoto() instead returns an encoded Blob. These APIs are optional and are most useful in camera or stream workflows rather than a simple file-backed video element.
Common failures and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
videoWidth and videoHeight are zero |
Metadata has not loaded, or the source failed. | Wait for loadedmetadata; handle the video’s error event and verify the URL. |
| Captured image is from the wrong moment | Canvas was drawn before seeking completed. | Set currentTime, await seeked, then call drawImage. |
SecurityError during export |
The canvas is tainted by cross-origin media. | Set crossorigin before src and configure CORS on the media server, including redirects and range responses. |
| JPEG Blob is null | Encoding failed or the canvas is invalid. | Check non-zero dimensions, avoid canvas-size limits, and reject a null callback result. |
| Live video will not seek | The stream has no seekable timeline. | Capture the currently rendered frame and label it as live-position capture. |
| Downloads become slow or memory-heavy | Large data URLs or too many retained Blobs. | Prefer toBlob(), process frames sequentially, and revoke object URLs. |
Performance, limits, and operational decisions
- Decode cost: seeking repeatedly may require decoding from keyframes. For dozens or hundreds of frames, a server-side media pipeline can be more efficient than driving a browser tab.
- Canvas limits: browsers impose maximum canvas dimensions and total pixel-area limits. Very large 4K or 8K sources may fail or consume substantial memory; downscale before encoding.
- Network behavior: seeking often uses byte-range requests. A CDN or media server must support those requests and return CORS headers consistently.
- Playback state: pause the element for deterministic single-frame work. If it is playing, the displayed frame can change between the seek and draw.
- Security: never treat a client-side CORS workaround or proxy as permission to redistribute media. Respect access controls and copyright.
Or skip the browser setup
If what you need is a screenshot of the webpage containing the embedded video—not extraction of a decoded video frame—ScreenshotNeo provides a one-request website capture API. It can remove cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and each response identifies the page verdict and billing status.
Request a page image with cURL (replace the URL with your page):
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The same call in 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)
And in 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(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
See the parameter reference and options in the ScreenshotNeo documentation. Its MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000. That captures the page around a video, not an exact decoded frame at 12.5 seconds, so use the canvas workflow when frame-level timing matters. Sign up for the free plan.
Best Value
- 【8MP HD Camera】Smart glasses with camera feature an 8MP HD camera for clear, stable shooting. Enjoy up to 12 minutes of video recording and 120 minutes of audio recording, plus intelligent AI object recognition. With easy WiFi transfer, you can quickly import all your photos, videos and audio clips—making it effortless to capture life’s moments hands-free
- 【Immersive Wireless Audio】Ai glasses with camera equipped with advanced Bluetooth 5.4 and dual-microphone ENC noise cancellation, these smart glasses meet all your audio needs. Take calls, listen to music or audiobooks, and access AI functions (audio/video recording, voice commands) with ease. Hi-Fi sound delivers clear vocals and great bass, ensuring a top-tier audio experience in any scenario
- 【AI Assistant & Translation】Ai glasses built-in AI assistant and translator make communication and work more efficient. Support real-time translation for international talks, simultaneous interpretation, and auto meeting notes—perfect for breaking language barriers during global conversations or multi-language meetings, helping you work smarter
- 【Long Battery Life】Ai glasses with camera come with fast charging (full charge in 2 hours) and reliable battery life for daily use. Enjoy 7 hours of non-stop music and 4 hours of smooth calls, making them your ideal companion for commuting, working or relaxing all day long
- 【Upgraded Materials】Smart glasses crafted with lightweight, flexible TR90 frames and bendable temple legs for a comfortable, customizable fit. IP68 waterproof and dustproof (resistant to rain, splashes and dust) ensures durability, even during hiking or sudden downpours—built to last in any environment
When to use each approach
| Requirement | Best fit |
|---|---|
| One exact frame from a same-origin or CORS-authorized file | Video element, canvas, seeked, and toBlob(). |
| Many frames at known times | Sequential canvas captures, with bounded memory; consider server-side processing at large scale. |
| Continuous recording of rendered playback | captureStream() and a media recorder pipeline. |
| An existing media track | ImageCapture.grabFrame() or takePhoto(). |
| A clean screenshot of the surrounding webpage | ScreenshotNeo, with its consent and popup removal and verdict-based billing. |
Frequently Asked Questions
Can I extract a frame without showing video controls?
Yes. Remove the controls attribute or keep the element off-screen; the video still must load and decode before the canvas draw.
Does JPEG quality 1 guarantee a lossless frame?
No. JPEG is inherently lossy. Use a lossless format such as PNG when exact pixel preservation is required, or choose a high JPEG quality when smaller files matter.
Why is my frame slightly different from the requested timestamp?
Seeking is time-based and depends on the encoded stream’s keyframes and browser decoder. The browser captures the frame it can present after seeked, not a guaranteed source-frame index.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
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.

