How to Set a Custom Mobile Viewport Size in Playwright
Set exact mobile viewport dimensions in Playwright Test or the library API, and learn when viewport sizing alone is not enough to emulate a phone.
Set viewport to an object with pixel dimensions: { width: 390, height: 844 }. In Playwright Test, put it in the project’s use configuration, or use test.use() to scope it to a test file or group. With the Playwright library, configure it when creating a browser context, or call page.setViewportSize() before navigating.
A viewport sets the page’s available width and height. It does not, by itself, reproduce every phone behavior. If the test needs touch input, a mobile user agent, a device scale factor, or a particular screen size, configure those separately or start from a Playwright device preset.
1. Set a project-wide viewport in Playwright Test
Add viewport to use in playwright.config.ts. The dimensions are CSS pixels.
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
viewport: { width: 390, height: 844 },
},
});
This applies to tests in the configured project unless a more specific setting overrides it. It is useful when most tests in a project should run at the same dimensions.
2. Override a device preset’s viewport
A device preset bundles emulation settings, which can include a viewport, user agent, screen size, device scale factor, and touch behavior. Spread the preset first, then put your custom viewport after it so the custom dimensions take precedence.
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'custom mobile viewport',
use: {
...devices['iPhone 13'],
viewport: { width: 390, height: 844 },
},
},
],
});
This keeps the preset’s other emulation settings while replacing its viewport dimensions. Change the preset name to another supported device if it better matches the behavior you need. Check Playwright’s current [device emulation documentation](https://playwright.dev/docs/emulation) for the available presets and settings.
3. Scope the viewport to a test or group
Use test.use() when only one test file needs a particular size. Put it at the top level of the file, or inside a test.describe() block to scope the setting to that group.
import { test, expect } from '@playwright/test';
test.use({
viewport: { width: 390, height: 844 },
});
test('navigation fits the mobile viewport', async ({ page }) => {
await page.goto('https://example.com');
await expect(page.locator('nav')).toBeVisible();
});
To use a different size for a separate group, place that group’s test.use() inside its describe block. Keep the dimensions explicit so failures are reproducible across machines.
4. Set the viewport with the Playwright library
If you use Playwright without the test runner, configure the viewport on a new browser context before creating the page.
import { chromium } from 'playwright';
const browser = await chromium.launch();
const context = await browser.newContext({
viewport: { width: 390, height: 844 },
});
const page = await context.newPage();
await page.goto('https://example.com');
console.log(await page.locator('body').boundingBox());
await context.close();
await browser.close();
Context-level configuration is the clearest choice when you want every page created in that context to share the same viewport.
5. Resize an existing page
For an existing page, call page.setViewportSize():
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.setViewportSize({ width: 390, height: 844 });
await page.goto('https://example.com');
await browser.close();
Set the size before navigation when possible. Playwright’s API documentation notes that changing the viewport also resets the page’s screen size; sites that assume a phone’s dimensions do not change may behave differently if you resize after loading. If your test needs a distinct screen size and viewport size, set both on the browser context. See [the page.setViewportSize() reference](https://playwright.dev/docs/api/class-page) for API details.
6. Understand viewport size versus mobile emulation
Choose settings based on what the test is meant to simulate:
| What you need to control | Setting or approach |
|---|---|
| Page width and height | viewport: { width, height }, or page.setViewportSize() |
| A named device configuration | Spread a preset from devices, then override any settings you need |
| Mobile viewport-tag and touch behavior | Use mobile emulation settings such as isMobile and touch support where supported |
| A particular device pixel ratio | Set deviceScaleFactor or use a preset that supplies it |
| Screen dimensions distinct from page dimensions | Configure screen and viewport on the browser context |
| Browser-specific behavior | Run the test in the browser engine you need and confirm it supports each emulation option |
For example, a 390-by-844 viewport controls the page’s CSS layout area. It does not necessarily set the device scale factor, user agent, or touch input. A device preset supplies a coordinated set of emulation options; a custom viewport lets you adjust the dimensions within that setup.
Playwright documents isMobile as unsupported in Firefox. If a test depends on a particular mobile emulation option, check support for the browser engine you run. See [Playwright’s emulation guide](https://playwright.dev/docs/emulation) and [BrowserType API reference](https://playwright.dev/docs/api/class-browsertype).
7. Generate a test with a chosen viewport
The Playwright code generator accepts a viewport size in width-by-height form:
npx playwright codegen --viewport-size="800,600" https://example.com
You can also record against a named device:
npx playwright codegen --device="iPhone 13" https://example.com
Use --viewport-size when you want particular dimensions, and --device when you want to begin with a device preset. The [codegen documentation](https://playwright.dev/docs/codegen) describes these options.
8. Check the viewport in a test
When a responsive test fails, inspect the dimensions Playwright actually applied. The page’s innerWidth and innerHeight expose the viewport size in the browser:
import { test, expect } from '@playwright/test';
test.use({ viewport: { width: 390, height: 844 } });
test('uses the expected viewport', async ({ page }) => {
await page.goto('https://example.com');
const viewport = await page.evaluate(() => ({
width: window.innerWidth,
height: window.innerHeight,
}));
expect(viewport).toEqual({ width: 390, height: 844 });
});
This is a straightforward check that the browser received the dimensions you intended. It does not verify that every mobile emulation property is active.
9. Troubleshoot common problems
| Symptom | Likely cause | Fix |
|---|---|---|
| The page still uses the preset’s dimensions | The preset was spread after the custom viewport, overwriting it. | Spread the preset first and set viewport afterward. |
| The page layout is narrow, but mobile interactions are missing | A viewport controls page dimensions, not every device behavior. | Use a device preset or configure the needed user agent, touch, screen, or scale settings. |
isMobile has no effect in Firefox |
Playwright does not support that option in Firefox. | Use a supported browser engine for that emulation, or test the responsive layout with a viewport alone. |
| Changing the size after navigation gives unexpected behavior | The site may assume device dimensions are fixed, or the page’s screen size changed along with its viewport. | Set the viewport before navigation. If screen and viewport need different values, configure both on the context. |
| Tests disagree about the viewport | A project setting, test-level setting, preset, or page resize may override another value. | Review the order of preset spreads and overrides, then inspect window.innerWidth and window.innerHeight in the running page. |
| A layout breakpoint does not trigger at the expected value | The test may be using a different viewport than intended, or the breakpoint may be defined in CSS pixels with a different threshold. | Check the actual inner dimensions and the site’s media query before changing the test size. |
10. Performance, reliability, and cost
Viewport settings are local browser configuration; they do not require a paid service. A fixed viewport makes responsive checks easier to reproduce. For reliable comparisons, keep dimensions and emulation settings stable across runs, use the same browser engine where browser-specific behavior matters, and set the viewport before loading the site.
Testing one mobile size cannot cover every responsive breakpoint. Choose dimensions that correspond to the layouts your application supports, and add separate configurations or tests for other important widths. A device preset is useful when those tests also depend on device behavior beyond page dimensions.
Or skip the browser setup
If you need a screenshot of a page at a custom viewport without maintaining browser capture code, [ScreenshotNeo](https://screenshotneo.com) can return an image from one API request. Its API supports custom viewports and other capture options; see the [ScreenshotNeo API documentation](https://screenshotneo.com/docs/) for configuration details.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-d width=390 \
-d height=844 \
-o shot.webp
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed, and response headers identify the page verdict and billing status. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up for free and capture your first 1,000 screenshots a month with no card.
FAQ
Are viewport width and height measured in pixels?
Yes. Set them as integer pixel values, for example { width: 390, height: 844 }.
Does a custom viewport make a page behave like a real phone?
No. It sets the page dimensions. Use a device preset or additional emulation settings for behavior such as touch support, user agent, or device scale factor.
Can I use a viewport size different from a device preset?
Yes. Spread the preset into the configuration, then set your custom viewport after the spread.
Should I set the viewport before or after navigation?
Prefer setting it before navigation, either in configuration or when creating the context. That avoids resizing a page after the site has loaded.


