Use navigator.mediaDevices.getDisplayMedia() to capture a user-authorized tab, window, or display as a live MediaStream. Attach that stream to a preview, grab a still with ImageCapture and a canvas, or record it with MediaRecorder. To capture only a playing <video>, use HTMLMediaElement.captureStream() where the target browser supports it. These APIs capture rendered pixels or media streams; they do not serialize an arbitrary page DOM into a screenshot.
The examples below run in a secure context (HTTPS or localhost), start from a user gesture, and include explicit stop controls. A browser chooser and permission prompt are intentional privacy boundaries: the person operating the page chooses what is shared.
Choose the capture route
| Goal | API path | Main trade-offs |
|---|---|---|
| Capture a tab, window, or monitor | getDisplayMedia() |
User selection and consent are required; secure context and browser support are required; the selected surface can expose anything visible on it. |
| Capture a video element | video.captureStream() |
Targets that element directly, but support is limited and varies by browser. |
| Save one still frame | Display capture, then ImageCapture.grabFrame(), canvas, and toBlob() |
The frame is taken from the captured track. Cropping or element targeting depends on browser support and can be affected by layout changes. |
| Record a canvas animation | canvas.captureStream() plus MediaRecorder |
Canvas must remain origin-clean when pixel access is needed; codec and container support differ by browser. |
Do not treat these methods as a silent, unrestricted screenshot service. Display capture always goes through browser UI and user permission.
Capture the current tab, window, or screen
Minimal working example
The following page starts capture from a button, previews the selected surface, records it, and stops every track when finished.
#1 Best Overall
- Easily record quick videos of your screen and camera that offer the same connection as a meeting without the calendar wrangling
- Draw on your screen as you record video with customizable arrows, squares, and step numbers to emphasize important information
- Provide clear feedback and explain complex concepts with easy-to-use professional mark-up tools and templates
- Instantly create a shareable link where your viewers can leave comments and annotations or upload directly to the apps you use every day
- Version Note: This listing is for Snagit 2024. Please note that official technical support and software updates for this version are scheduled to conclude on December 31, 2026.
<button id="start">Start capture</button>
<button id="stop" disabled>Stop</button>
<video id="preview" autoplay muted playsinline style="max-width:100%"></video>
<a id="download" hidden>Download recording</a>
<script>
const start = document.querySelector('#start');
const stop = document.querySelector('#stop');
const preview = document.querySelector('#preview');
const download = document.querySelector('#download');
let stream;
let recorder;
let chunks = [];
start.addEventListener('click', async () => {
try {
stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true
});
preview.srcObject = stream;
chunks = [];
recorder = new MediaRecorder(stream);
recorder.ondataavailable = event => {
if (event.data.size) chunks.push(event.data);
};
recorder.onstop = () => {
const blob = new Blob(chunks, { type: recorder.mimeType });
download.href = URL.createObjectURL(blob);
download.download = 'webpage-capture.webm';
download.hidden = false;
download.textContent = 'Download recording';
};
stream.getVideoTracks()[0].addEventListener('ended', stopCapture);
recorder.start();
start.disabled = true;
stop.disabled = false;
} catch (error) {
console.error(error);
alert('Capture was cancelled or is unavailable in this browser.');
}
});
stop.addEventListener('click', stopCapture);
function stopCapture() {
if (recorder && recorder.state !== 'inactive') recorder.stop();
if (stream) stream.getTracks().forEach(track => track.stop());
preview.srcObject = null;
start.disabled = false;
stop.disabled = true;
}
</script>
What happens in order
- Call
getDisplayMedia()in the click handler. Calling it on page load is commonly rejected because the request is not tied to a user action. - The browser opens its chooser. The user selects a tab, window, or entire display and grants permission.
- The promise resolves to a
MediaStream. Assigning it tovideo.srcObjectgives a live preview. MediaRecorderemits chunks throughdataavailable. Combine all chunks into oneBlob; an individual slice is not guaranteed to be independently playable.- Stop the recorder and every track. Also handle the track’s
endedevent, which fires when the user stops sharing from browser chrome.
Audio and privacy
Audio availability depends on the selected surface and browser. A tab may offer audio while a window or monitor does not. Never assume audio: true guarantees an audio track. Tell users exactly what to select and provide a visible stop button: a display can contain passwords, private messages, or other material outside the intended page.
Take a still screenshot from the captured stream
For a still, capture first, wait for the preview’s first frame, then use the video track with ImageCapture.grabFrame(). Draw the resulting bitmap to a canvas and encode it.
async function captureStill(stream) {
const track = stream.getVideoTracks()[0];
if (!track) throw new Error('No video track');
const imageCapture = new ImageCapture(track);
const bitmap = await imageCapture.grabFrame();
const canvas = document.createElement('canvas');
canvas.width = bitmap.width;
canvas.height = bitmap.height;
const context = canvas.getContext('2d');
context.drawImage(bitmap, 0, 0);
bitmap.close();
return new Promise((resolve, reject) => {
canvas.toBlob(blob => blob ? resolve(blob) : reject(new Error('Encoding failed')), 'image/png');
});
}
// After getDisplayMedia() resolves:
const png = await captureStill(stream);
const link = document.createElement('a');
link.href = URL.createObjectURL(png);
link.download = 'webpage-still.png';
link.click();
This produces the captured track’s dimensions, not necessarily the CSS pixel dimensions of the page. If the user resizes the shared window, the track may change size; inspect the track settings before allocating a fixed canvas.
Rank #2
- Record videos and take screenshots of your computer screen including sound
- Highlight the movement of your mouse
- Record your webcam and insert it into your screen video
- Edit your recording easily
- Perfect for video tutorials, gaming videos, online classes and more
Element and region targeting
Element Capture and Region Capture APIs can restrict or crop a display capture in browsers that implement them. Treat these as progressive enhancements: feature-detect them, keep a full-surface fallback, and expect moving layout or scrolling to affect the selected region. A crop is still derived from an authorized display stream; it does not bypass the chooser.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsCapture a video element directly
HTMLMediaElement.captureStream() exposes the rendered output of an <video> or <audio> element as a MediaStream. It avoids capturing browser chrome and unrelated page content, but MDN marks the method as limited availability, so test every browser/version in your support matrix.
<video id="source" controls crossorigin="anonymous" src="/media/demo.mp4"></video>
<button id="recordVideo">Record video element</button>
<script>
const source = document.querySelector('#source');
document.querySelector('#recordVideo').addEventListener('click', () => {
if (typeof source.captureStream !== 'function') {
alert('This browser does not implement video capture.');
return;
}
const stream = source.captureStream();
const chunks = [];
const recorder = new MediaRecorder(stream);
recorder.ondataavailable = event => {
if (event.data.size) chunks.push(event.data);
};
recorder.onstop = () => {
const blob = new Blob(chunks, { type: recorder.mimeType });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'video-element.webm';
link.click();
setTimeout(() => URL.revokeObjectURL(url), 0);
};
recorder.start();
source.play();
source.addEventListener('ended', () => {
if (recorder.state !== 'inactive') recorder.stop();
stream.getTracks().forEach(track => track.stop());
}, { once: true });
});
</script>
Autoplay policies can block play(); start playback from the same user gesture or use controls. Media licensing and cross-origin delivery rules still apply—you should only record content you are authorized to capture.
Rank #3
- Screen capture software records all your screens, a desktop, a single program or any selected portion
- Capture video from a webcam, network IP camera or video input device
- Use video overlay to record your screen and webcamsimultaneously
- Intuitive user interface to allow you to get right to video recording
- Save your recordings to ASF, AVI, and WMV
Record a canvas animation
const canvas = document.querySelector('canvas');
const stream = canvas.captureStream(30); // requested frames per second
const recorder = new MediaRecorder(stream);
const chunks = [];
recorder.ondataavailable = event => event.data.size && chunks.push(event.data);
recorder.onstop = () => {
const recording = new Blob(chunks, { type: recorder.mimeType });
// Save recording as needed.
};
recorder.start();
// Later:
recorder.stop();
stream.getTracks().forEach(track => track.stop());
The canvas must be origin-clean for operations that read or export pixels. Drawing an image or video from another origin without an appropriate CORS setup can taint it; subsequent pixel access or capture may throw a SecurityError. Configure the remote resource for CORS before drawing it, or keep all media same-origin.
Recording choices, formats, and performance
Detect a usable recorder format
const candidates = [
'video/webm;codecs=vp9,opus',
'video/webm;codecs=vp8,opus',
'video/mp4'
];
const mimeType = candidates.find(type => MediaRecorder.isTypeSupported(type));
if (!mimeType) throw new Error('No supported recording format');
const recorder = new MediaRecorder(stream, { mimeType });
Container and codec support differ, and a browser may report a MIME type as unsupported even when another candidate works. Keep the original chunks until the recorder stops, and release object URLs after downloads to avoid retaining large recordings in memory.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Reduce resource use
- Capture only the necessary surface or element instead of a whole monitor.
- Use a sensible canvas frame rate; higher values increase CPU, memory, and output size.
- Stop tracks promptly when navigation, upload, or recording ends.
- For long sessions, process data in periodic
dataavailableevents rather than waiting for one very large in-memory blob. - Do not assume the captured frame rate equals the display refresh rate; inspect actual track settings and test on the slowest supported device.
Troubleshooting common failures
| Symptom | Likely cause | Fix |
|---|---|---|
getDisplayMedia is undefined or rejected immediately |
Unsupported browser, insecure context, or no user gesture | Serve over HTTPS or localhost, call from a click/tap handler, and feature-detect the method. |
| Chooser appears but promise rejects | User cancelled, policy blocked capture, or an unavailable surface was requested | Handle NotAllowedError/AbortError, explain the required selection, and let the user retry. |
| Preview is black or frozen | Track ended, video not ready, or rendering is blocked | Check stream.active, listen for ended, wait for metadata/first frame, and confirm the selected surface is visible. |
| No sound in recording | Selected surface did not provide audio or the browser omitted it | Inspect stream.getAudioTracks().length; ask the user to select a tab when tab audio is required. |
captureStream is not a function |
Browser lacks the limited-availability API | Offer display capture as a fallback or use a browser that implements the method. |
SecurityError from canvas |
Canvas is not origin-clean because of cross-origin media | Serve media with suitable CORS headers, set the media element’s CORS mode before loading, or avoid pixel reads. |
| Downloaded file will not play | Chunks were saved separately or the selected container is unsupported by the player | Combine all chunks into one Blob, choose a MIME type with MediaRecorder.isTypeSupported(), and test playback in the target player. |
Or skip the browser setup
For server-side screenshots, ScreenshotNeo provides a one-call website screenshot API. It is different from local display capture: it loads the URL for you, accepts cookie/consent banners before capture, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and bills only clean shots. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status.
Use the API documentation at https://screenshotneo.com/docs/ for all options. The following calls are runnable; replace the URL and key.
Rank #4
- Capture video directly to your hard drive
- Record video in many video file formats including avi, wmv, flv, mpg, 3gp, mp4, mov and more
- Capture video from a webcam, network IP camera or a video input device (e.g.: VHS recorder)
- Screen capture software records the entire screen, a single window or any selected portion
- Digital zoom with the mouse scroll wheel, and drag to scroll the recording window
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(`${res.status} ${res.statusText}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', buffer));
ScreenshotNeo also supports full-page captures with lazy images loaded, CSS-selector element shots, dark mode, 12 device presets or custom viewports, retina scale, PDF output, HTML/CSS-to-image, custom CSS and JavaScript, pre-capture clicks, hidden selectors, waits for selectors/delays/network idle, request and resource blocking, custom headers/cookies/user agents/Authorization, timezone and geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, an OpenAPI specification, and familiar parameter names for easier migration.
It also includes an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. Every feature is on every plan: 1,000 shots per month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to start.
When to use each method
- Choose display capture when the user must capture exactly what they see, including an interactive tab or desktop application.
- Choose
video.captureStream()when you control a media element and need only its rendered output. - Choose canvas capture for an animation already rendered into a canvas.
- Choose ScreenshotNeo when a backend or automation job needs repeatable URL screenshots without asking a person to operate a chooser.
Frequently Asked Questions
Does JavaScript capture the page DOM directly?
No. The browser APIs described here capture rendered display pixels or media streams. DOM serialization is a separate operation and does not produce a faithful visual screenshot by itself.
Best Value
- 【1080P HD High Quality】Capture resolution up to 1080p for video source and it is ideal for all HDMI devices such as PS4, PS3, Xbox One, Xbox 360, Wii U, DVDs, DSLR, Camera, Security Camera and set top box. Note: Video input supports 4K30/60Hz and 1080p120/144Hz. Does not support 4K120Hz/144Hz. Output supports up to 2K30Hz.
- 【Plug and Play】No driver or external power supply required, true PnP. Once plugged in, the device is identified automatically as a webcam. Detect input and adjust output automatically. Won't occupy CPU, optional audio capture. No freeze with correct setting.
- 【Compatible with Multiple Systems】suitable for Windows and Mac OS. High speed USB 3.0 technology and superior low latency technology makes it easier for you to transmit live streaming to Twitch, Youtube, Facebook, Twitter, OBS, Potplayer and VLC.
- 【HDMI LOOP-OUT】Based on the high-speed USB 3.0 technology, it can capture one single channel HD HDMI video signal. There is no delay when you are playing game live.
- 【Support Mic-in for Commentary】Rybozen capture card has microphone input and you can use it to add external commentary when playing a game. Please note: it only accepts 3.5mm TRS standard microphone headset.
Can a website start screen capture without the user knowing?
No. Display capture requires a browser chooser and permission, normally initiated by a user action. The user can stop sharing from browser controls at any time.
Why is a recorded video element missing subtitles or overlays?
captureStream() captures the media element’s rendered media output, not necessarily separate HTML controls or page overlays layered around it. Capture the display surface when those overlays must be included.
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.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.




