How to Capture an HTML Document as an Image in Chrome
Capture a viewport, full HTML page, or single DOM element in Chrome with DevTools, CDP, headless Chrome, or ScreenshotNeo.
Direct answer: Open the HTML document in Chrome, open DevTools, open the command menu, and choose Capture screenshot for the visible viewport or Capture full size screenshot for the entire page. To export one element, inspect it in the Elements panel, right-click the node, and choose Capture node screenshot. Chrome saves the image to your normal downloads folder.
For repeatable captures, use the Chrome DevTools Protocol (Page.captureScreenshot) or headless Chrome. If you want an API that handles consent banners, popups, chat widgets, failed loads, and billing decisions for you, see ScreenshotNeo after the browser workflows below.
Capture an HTML document with Chrome DevTools
1. Load the page in the state you want to preserve
- Open the HTML document or URL in Chrome.
- Wait until fonts, images, animations, and client-side content look correct.
- Scroll through the page once if it loads content lazily as you scroll.
DevTools captures the rendered page, not the original HTML source. A capture can therefore include the effects of CSS, JavaScript, loaded fonts, responsive breakpoints, and the current scroll or viewport state.
2. Open DevTools and the screenshot commands
- Open DevTools with F12, Ctrl+Shift+I on Windows/Linux, or Cmd+Option+I on macOS.
- Open the DevTools command menu with Ctrl+Shift+P on Windows/Linux or Cmd+Shift+P on macOS.
- Type
screenshot.
Chrome’s screenshot commands are documented in the Chrome DevTools screenshot guide.
3. Choose the capture scope
| Command | What it captures | Use it when |
|---|---|---|
| Capture screenshot | The current visible viewport. | You need exactly what a user sees at the current browser size. |
| Capture full size screenshot | The whole page, including content outside the current viewport. | You need one tall image of a complete document. |
| Capture area screenshot | A rectangle you draw in the page. | You need a temporary crop without editing the file afterward. |
The full-size command captures the whole page, including content that is not currently visible in the viewport. Very long pages, sticky headers, animations, lazy-loaded sections, and cross-origin embeds can behave differently from page to page, so inspect the saved image before using it in production.
Capture one HTML element
- Open DevTools and select the Elements panel.
- Use the element picker or the DOM tree to select the component, article, card, or other node.
- Right-click the node.
- Choose Capture node screenshot.
Chrome documents this workflow as: “You can screenshot any individual node in the DOM Tree using Capture node screenshot.” The resulting image is downloaded automatically.
Use node capture for a component that has its own background, border, or layout. If the element’s appearance depends on an ancestor’s clipping, transforms, or overflow rules, verify that the exported bounds match what you expect.
Control the result before capturing
Set the viewport and device scale
For responsive pages, enable the device toolbar in DevTools and select a device preset or enter a custom width and height. Capture again at each breakpoint you support. A viewport capture reflects the emulated dimensions; a full-size capture uses the page layout produced by that viewport.
For pixel-dense output, use a device scale factor in an automated workflow. A larger scale factor increases image dimensions and memory use, so choose it only when the consuming system needs the extra resolution.
Make lazy content available
Scroll through the document before a full-page capture when images or sections load on intersection. If a page has an explicit “load more” control, activate it first. Chrome does not guarantee that every lazy resource will be fetched merely because a full-size command is selected.
Freeze transient UI
Dismiss cookie dialogs, newsletter prompts, chat bubbles, hover menus, and video overlays before capturing. Pause animations when a stable frame matters. A sticky header may appear once for every viewport segment in a stitched full-page result; check the output and hide or disable it temporarily if necessary.
Automate with the Chrome DevTools Protocol
The DevTools Protocol exposes Page.captureScreenshot. It returns base64-encoded image data and supports png, jpeg, and webp. The captureBeyondViewport option allows captures beyond the current viewport. See the Page.captureScreenshot protocol reference.
A minimal protocol sequence is:
- Launch Chrome with remote debugging enabled.
- Connect to the browser’s DevTools WebSocket.
- Navigate with
Page.navigateand wait for the page to reach your chosen ready state. - Call
Page.captureScreenshotwith an image format and capture options. - Base64-decode the returned
datafield and write it to a file.
Protocol automation is useful in tests and build jobs because the viewport, wait strategy, format, and output path can be version-controlled. Your code must still decide how to wait for fonts, client-side rendering, network activity, and lazy resources.
Use headless Chrome from a shell
Headless Chrome has a documented --screenshot flag. This command writes screenshot.png in the current working directory:
google-chrome --headless --disable-gpu \
--screenshot \
--window-size=1280,1696 \
https://example.com
Use the Chrome executable available on your system, such as google-chrome, chromium, or chromium-browser. The --window-size value controls the capture dimensions. Headless mode is a good fit for a shell-based job that needs an image file, while the DevTools Protocol gives finer control over navigation and capture options. See the Chrome headless documentation.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. A GET request returns a PNG, JPEG, WebP, or PDF. The same request can be used from a shell, Python, or Node.js.
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)
open("shot.webp", "wb").write(r.content)
Node.js
const fs = require('node:fs/promises');
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(`ScreenshotNeo returned ${res.status}`);
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
See the ScreenshotNeo API documentation for request options. Before capture it accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Responses identify the result with X-Page-Verdict and X-Billed headers.
For this use case you can configure full-page capture with lazy images loaded, a CSS selector for one element, dark mode, a device preset or custom viewport, retina scale, custom CSS or JavaScript, a click before capture, hidden selectors, selector or delay waits, network-idle waits, blocked ads or requests, custom headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, image resizing, and a chosen cache TTL. PDF output supports paper size, margins, landscape mode, and page ranges. Async jobs, signed webhooks and bulk capture of up to 100 URLs per call are available when a job should run outside a single request.
An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. ScreenshotNeo has a free plan with 1,000 shots per month and no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is on every plan. Create a free ScreenshotNeo account.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The image contains only the visible area. | The viewport command was used. | Choose Capture full size screenshot or set captureBeyondViewport in protocol automation. |
| A section is missing from a full-page image. | Lazy loading or an untriggered “load more” control. | Scroll through the page, activate the control, wait for the resource, then capture. |
| The page is cut off or has unexpected dimensions. | Responsive layout, fixed viewport, or an element with overflow clipping. | Set the intended viewport explicitly and compare the element’s layout at that width. |
| A cookie banner, popup, or chat bubble covers content. | Transient UI was still present. | Dismiss it, pause the page, hide the selector temporarily, or use ScreenshotNeo’s pre-capture cleanup. |
| Fonts or icons look wrong. | Web fonts or external assets had not finished loading. | Wait for the rendered state, confirm network completion, and capture again. |
| Animations produce inconsistent frames. | The capture occurred mid-animation. | Pause animations with DevTools or custom CSS/JavaScript and use a deterministic delay. |
| Headless Chrome cannot start. | The executable name or sandbox settings differ by environment. | Use the installed executable path, check --help, and run the command in the same user/container environment as the job. |
| Protocol output is blank. | Capture happened before navigation or rendering completed. | Wait for navigation and the page’s own ready condition before calling Page.captureScreenshot. |
| An API response is not an image. | The request failed or returned an error payload. | Check the HTTP status and response headers before writing bytes to disk; inspect X-Page-Verdict and X-Billed for ScreenshotNeo. |
Performance, reliability, and cost notes
- Viewport captures are cheaper to process locally: they contain fewer pixels and finish faster than very tall full-page images.
- Full-page captures use more memory: long documents and high device scale factors increase image dimensions and encoding time.
- Wait deliberately: a short, page-specific wait for fonts, selectors, or network idle is more reliable than an arbitrary screenshot immediately after navigation.
- Make runs reproducible: fix the Chrome version, viewport, device scale, color scheme, timezone, and page data when image diffs matter.
- Cache stable pages: local automation can reuse outputs, while ScreenshotNeo lets you choose a cache TTL. Cache hits are not billed by ScreenshotNeo.
- Control failures: retry transient navigation failures with a limit and record the URL, viewport, and error. ScreenshotNeo identifies bot checks, blank pages, timeouts, and failed loads, and does not bill those results.
FAQ
Can Chrome save an entire HTML page as one image?
Yes. Use Capture full size screenshot from the DevTools command menu. The result is one image containing content outside the current viewport.
How do I screenshot only a div?
Inspect the div in the Elements panel, right-click its DOM node, and select Capture node screenshot.
Which format does Chrome use?
DevTools saves a screenshot image directly. For automated control, the DevTools Protocol supports PNG, JPEG, and WebP.
Can I automate this without opening a browser window?
Yes. Use headless Chrome with --screenshot, or connect to Chrome through the DevTools Protocol.
What should I use for scheduled screenshots of many URLs?
Use a protocol or API workflow with explicit waits, retries, and output checks. ScreenshotNeo also supports async jobs with signed webhooks and bulk capture of up to 100 URLs per call.


