How to Capture Mobile Website Screenshots with Playwright in Landscape Mode
Use Playwright’s mobile device emulation to capture a website in landscape mode. Learn how to choose a device preset or custom viewport and control the capture area and image scale.
To capture a mobile website screenshot in landscape mode with Playwright, create a browser context using a landscape device profile, navigate to the page, and call page.screenshot(). For a specific responsive breakpoint, use a custom viewport whose width is greater than its height. Playwright emulates a browser device profile; this does not mean the capture was taken on a physical phone.
Use a landscape device preset
Playwright’s device registry includes named profiles, including a landscape mobile profile. This JavaScript example uses the iPhone 13 Mini landscape descriptor and saves the visible viewport:
import { chromium, devices } from '@playwright/test';
const browser = await chromium.launch();
try {
const context = await browser.newContext({
...devices['iPhone 13 Mini landscape'],
});
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'load' });
await page.screenshot({ path: 'mobile-landscape.png' });
await context.close();
} finally {
await browser.close();
}
Install Playwright Test with npm install -D @playwright/test and install the browser with npx playwright install chromium if it is not already installed. Save the example as an ES module, for example capture.mjs, and run it with node capture.mjs. The imported device descriptor sets the profile’s emulation parameters. When the target browser engine matters, use the descriptor’s documented defaultBrowserType rather than assuming the preset is intended for every engine. See the official Playwright emulation guide and device descriptor source.
Choose a preset or a custom landscape viewport
A preset is useful when you want a familiar device configuration. A custom context is better when the layout width itself is the requirement, such as checking a particular responsive breakpoint. Keep the viewport wider than it is tall and set mobile, touch, and scale behavior to match the profile you want to emulate.
import { chromium } from '@playwright/test';
const browser = await chromium.launch();
try {
const context = await browser.newContext({
viewport: { width: 844, height: 390 },
screen: { width: 844, height: 390 },
isMobile: true,
hasTouch: true,
deviceScaleFactor: 2,
});
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'load' });
await page.screenshot({ path: 'custom-mobile-landscape.png' });
await context.close();
} finally {
await browser.close();
}
These dimensions are an example custom profile, not a claim about a particular physical device. Change them to the CSS viewport dimensions you need to test. Playwright’s emulation guide documents viewport overrides and device parameters. See Emulation.
Choose the capture area and image scale
By default, page.screenshot() captures the visible viewport. Pick the capture area based on what you need to inspect:
| Capture | Option | Use it for |
|---|---|---|
| Visible viewport | No extra option | A screen-level view of the page in landscape. |
| Entire scrollable page | fullPage: true |
Content below the fold, such as a long landing page. |
| Specific rectangle | clip: { x, y, width, height } |
A region of the rendered page. |
// Entire page
await page.screenshot({ path: 'full-page.png', fullPage: true });
// A rectangle in page coordinates
await page.screenshot({
path: 'page-region.png',
clip: { x: 0, y: 0, width: 420, height: 240 },
});
Set scale deliberately. 'css' produces one image pixel per CSS pixel, which is useful for compact, comparable layout captures. 'device' uses device pixels, preserving the emulated device pixel density and potentially producing a larger image file.
await page.screenshot({ path: 'css-pixels.png', scale: 'css' });
await page.screenshot({ path: 'device-pixels.png', scale: 'device' });
Playwright’s screenshot API documents fullPage, clip, and scale. See Page screenshot options.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. Its screenshot endpoint returns an image or PDF from one GET request. This example asks for a landscape viewport; see the ScreenshotNeo API documentation for parameters and formats.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-d viewport_width=844 \
-d viewport_height=390 \
-o mobile-landscape.webp
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot, and each step can be turned off. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per 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.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The page still uses a desktop layout. | The chosen viewport is wider than the site’s mobile breakpoint, or the context is not using the intended mobile profile. | Check the viewport dimensions and use the landscape preset or set the custom mobile and touch parameters for the emulation you need. |
| The image is portrait-shaped. | The context inherited portrait dimensions or a later viewport override changed its dimensions. | Set width greater than height in the context and check for test-level viewport overrides. |
| The screenshot cuts off content below the fold. | The default screenshot covers only the visible viewport. | Use fullPage: true for the full scrollable page, or increase the viewport if you need a taller screen-level capture. |
| The output file is larger than expected. | Device scale can produce multiple image pixels per CSS pixel for a high-density profile. | Use scale: 'css' when CSS-pixel dimensions are sufficient. |
| The preset behaves unexpectedly in the selected browser. | A device profile records browser-engine metadata; not every profile is intended for every engine. | Check the preset’s defaultBrowserType in Playwright’s device descriptors and launch that engine. |
| Navigation ends before the page appears ready. | The page may still be loading resources or rendering content after the chosen navigation condition. | Choose an appropriate navigation wait condition, then explicitly wait for a page-specific selector or state before taking the screenshot. |
Performance, reliability, and cost
Playwright runs a browser locally or in your own browser environment, so capture time and resource use depend on the page, browser, and machine. Reuse a browser process when taking multiple captures, close each context when finished, and avoid device-pixel output when CSS-pixel captures meet the requirement. Full-page captures can take more time and produce larger files than viewport captures, especially on long pages.
For repeatable results, keep the browser engine, device descriptor, viewport, and screenshot scale consistent. Wait for the page state you need rather than relying on a fixed delay alone. Emulation is useful for checking responsive layouts, but it is not proof of rendering on a physical phone. Playwright itself is software; the cited workflow does not require buying a phone or test-device accessory.
FAQ
Can I take a landscape screenshot without a physical phone?
Yes. Playwright can emulate a device profile and viewport in a browser context. Describe the result as an emulated capture.
Should I use a landscape preset or set dimensions myself?
Use a preset for a named device configuration. Set a custom viewport when a specific breakpoint or width and height are what you need to validate.
Does landscape mode automatically capture the whole page?
No. The default is the visible viewport. Add fullPage: true for the full scrollable page.
Why does device scale create a larger screenshot?
It maps output image pixels to device pixels instead of CSS pixels. Choose scale: 'css' for one output pixel per CSS pixel.


