How to Make an AI Agent Screenshot a Webpage at 2x Device Pixel Ratio
Set Playwright’s device scale factor to 2, choose a CSS-pixel viewport, and capture the viewport or full page at high resolution.
For a Playwright-based AI agent, set deviceScaleFactor: 2 on the browser context before opening the page, set the viewport in CSS pixels, then call page.screenshot(). Use fullPage: true when the capture should include the full scrollable document. The scale and capture area are separate settings.
This creates a browser context with a 1280 × 800 CSS-pixel viewport and an emulated 2x device pixel ratio. It does not mean you should double the viewport dimensions.
Runnable Playwright example
Install Playwright and its browser in your project, then save this as screenshot.mjs. Pass the target URL as the first command-line argument.
import { chromium } from 'playwright';
const url = process.argv[2];
if (!url) throw new Error('Usage: node screenshot.mjs https://example.com');
const browser = await chromium.launch();
try {
const context = await browser.newContext({
viewport: { width: 1280, height: 800 },
deviceScaleFactor: 2,
});
const page = await context.newPage();
await page.goto(url, { waitUntil: 'networkidle', timeout: 60_000 });
await page.screenshot({ path: 'page-2x.png' });
await context.close();
} finally {
await browser.close();
}
Run it with node screenshot.mjs https://example.com. The screenshot captures the current viewport by default. With device-pixel output, a 1280 × 800 CSS-pixel viewport is expected to produce roughly 2560 × 1600 pixels. Actual image dimensions can depend on the capture area and browser behavior.
Playwright’s screenshot API distinguishes CSS-pixel output from device-pixel output: using device scale produces one image pixel per device pixel. Its emulation guide shows configuring device scale on the context.
Choose viewport or full-page capture
Use the viewport capture when the agent needs only what is currently visible. For content below the fold, set fullPage: true:
await page.screenshot({ path: 'full-page-2x.png', fullPage: true });
Full-page mode changes how much of the document is captured; deviceScaleFactor controls the emulated pixel density. A long page at 2x can create a very large image, so use it only when the whole document is useful to the agent or downstream task.
Make sure the page is ready
A completed navigation does not prove every dynamic component is ready. Client-rendered content, lazy-loaded images, animations, consent dialogs, and other overlays can change what the screenshot contains. Choose a readiness condition that matches the page.
For example, wait for a known element before capturing:
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60_000 });
await page.locator('main').waitFor({ state: 'visible', timeout: 15_000 });
await page.screenshot({ path: 'page-2x.png' });
Replace main with a selector that indicates the content your agent needs. If the page has no stable marker, a short delay may help, but it is less reliable than waiting for a meaningful element. For pages that keep network connections open, networkidle may never be a suitable readiness signal. Puppeteer’s official screenshot guide also demonstrates waiting for navigation as part of its capture workflow; navigation waits should be chosen for the page rather than treated as universal proof of visual readiness.
Important configuration choices
| Choice | What it controls | Guidance |
|---|---|---|
deviceScaleFactor |
Emulated device pixel ratio for the browser context. | Set to 2 for 2x DPR. Configure it before creating and navigating the page. |
viewport |
Visible browser area, measured in CSS pixels. | Choose the layout width and height the page should render at, such as 1280 × 800. Do not double these values to get 2x output. |
fullPage |
Whether the capture extends through the full scrollable page. | Leave it off for the viewport; enable it for a full-page image. |
scale |
Screenshot output scaling mode. | Playwright’s screenshot API supports CSS-pixel and device-pixel scale choices. Use device-pixel output when you need the high-DPI pixels. |
| Navigation and readiness waits | When capture begins relative to page loading. | Choose a navigation event, selector wait, or task-specific delay that fits the site. |
For an agent runtime, check that its browser integration allows configuring the Playwright context. If the runtime creates the browser context for you and does not expose this setting, you may need to use the runtime’s supported configuration mechanism or run the capture in a Playwright process you control.
Common problems and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Image is still viewport-sized vertically. | The screenshot call uses the default viewport capture. | Set fullPage: true if the complete scrollable document is required. |
| Image is too large or memory use spikes. | The page is long and output uses 2x device pixels. | Capture the viewport if sufficient; otherwise consider whether the task can use separate, smaller captures. |
| Layout looks like a mobile or unexpected size. | Viewport dimensions or context configuration differ from the intended CSS-pixel layout. | Set the intended CSS viewport explicitly and set deviceScaleFactor on the context before navigation. |
| Screenshot is blank or missing rendered content. | Capture occurred before client rendering or the relevant content became visible. | Wait for a stable content selector or an appropriate page-ready condition before capture. |
| Consent dialog, popup, or chat widget covers the page. | The page displayed an overlay before the screenshot. | Handle the overlay in your browser workflow or capture a clean page through a screenshot service that removes supported overlays. |
networkidle wait times out. |
The page continues making background network requests. | Use a less restrictive navigation wait and then wait for the specific content your agent needs. |
| Agent cannot set DPR. | Its browser wrapper hides context configuration. | Check the wrapper’s documented options or run Playwright in an environment where you can create the browser context directly. |
Performance, reliability, and cost considerations
- Image size: Doubling both pixel dimensions produces about four times as many pixels for the same capture area. Full-page captures can grow quickly with page height.
- Capture time: High-resolution rendering and encoding can take longer and consume more memory, especially on long pages. Limit capture area when the agent only needs a region.
- Repeatability: Keep viewport, device scale, wait condition, and page state consistent when comparing screenshots. Dynamic content, animations, and personalized pages can still vary.
- Failure handling: Set a navigation timeout, wait for a meaningful readiness condition, and close the context and browser in a
finallyblock so resources are released if capture fails. - Cost: A self-hosted Playwright capture uses your own browser runtime and infrastructure; its cost depends on where it runs and how often it captures. If using a hosted screenshot service, check its billing rules for failed loads, bot checks, and cached responses.
Or skip the browser setup
ScreenshotNeo is a website screenshot API: send one GET request with a URL to receive a PNG, JPEG, WebP, or PDF. Its API accepts viewport and device options, and the parameter names used by other screenshot APIs also work. See the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-d device_scale_factor=2 \
-o shot.webp
Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Does 2x DPR mean a 2560-pixel-wide viewport?
No. Set the viewport in CSS pixels, for example 1280 pixels wide, and set deviceScaleFactor: 2 for the higher device pixel density.
Does 2x DPR automatically capture the whole page?
No. Use fullPage: true separately when the entire scrollable page is needed.
Can every AI agent use this Playwright setting?
Only if its browser runtime exposes Playwright context configuration or lets you supply your own Playwright process. The agent framework is unspecified, so check its browser integration.
Is a navigation event enough to guarantee the screenshot is ready?
No. Wait for a page-specific element or other readiness signal when the content is rendered asynchronously.


