ScreenshotNeo

BlogHow-to

How to test a website at mobile viewport sizes with Cypress screenshots

Set mobile viewports in Cypress, assert responsive behavior, and save stable screenshots. Learn viewport versus full-page capture, CI setup, and troubleshooting.

By the ScreenshotNeo team4 October 20268 min read

Use Cypress’s cy.viewport(width, height) to set the application’s mobile viewport, assert the responsive behavior you expect, then call cy.screenshot(name, { capture: 'viewport' }) to save the visible page. Cypress captures screenshots; it does not compare them. Use consistent viewport dimensions and a consistent browser environment when you review visual changes.

1. Set the mobile viewport and capture it

This example checks a responsive navigation state at three explicit viewport sizes. Replace the paths and data-testid selectors with those in your application. It uses Cypress commands documented for viewport control, assertions, and screenshot capture.

const mobileViewports = [
  { name: 'narrow mobile', width: 320, height: 640 },
  { name: 'typical mobile', width: 375, height: 812 },
  { name: 'wide mobile', width: 414, height: 896 },
]

describe('responsive navigation', () => {
  mobileViewports.forEach(({ name, width, height }) => {
    it(`works at ${name}`, () => {
      cy.viewport(width, height)
      cy.visit('/')

      cy.get('[data-testid="mobile-menu-button"]').should('be.visible')
      cy.get('[data-testid="desktop-navigation"]').should('not.be.visible')

      cy.screenshot(`navigation-${width}x${height}`, {
        capture: 'viewport',
      })
    })
  })
})

The dimensions above are useful example inputs, not a claim about the most common devices. Choose sizes around your own CSS breakpoints and the layouts your users need. Assertions make the test explain what should change; the screenshot records the resulting state for inspection.

Run it

Save the spec in your project’s configured Cypress end-to-end spec folder, start the application using your existing development or CI workflow, and run the spec with Cypress. Cypress writes screenshots to cypress/screenshots by default; the screenshots folder can be changed in Cypress configuration. Cypress automatically captures screenshots on failure during cypress run, but not during cypress open.

2. Choose the right viewport and screenshot mode

Explicit dimensions or a device preset

cy.viewport(width, height) sets the application viewport in pixels. Cypress also accepts supported device preset names, with portrait or landscape orientation. Explicit dimensions are often easier to map to CSS breakpoints and to keep stable over time. Presets are convenient when their dimensions and orientation match the case you intend to cover.

The viewport controls the page’s available layout area. It does not simulate a physical device’s devicePixelRatio, so this is responsive viewport testing rather than complete phone emulation. To test behavior that depends on pixel ratio, hardware, or a mobile browser environment, use an appropriate device testing setup in addition to viewport tests.

Need What to set
One size for most tests Set viewportWidth and viewportHeight in Cypress configuration.
A size for one suite or test Use test or suite configuration with viewportWidth and viewportHeight.
Several sizes in one test run Call cy.viewport(width, height) for each case.
Portrait or landscape preset Use a supported preset and the orientation option.

Cypress documents a default viewport of 1000 by 660 pixels. A viewport changed with cy.viewport() resets to the configured default between tests. In Cypress 16.0.0 and later, do not use Cypress.config() during test execution to change viewportWidth or viewportHeight; set the viewport with cy.viewport() instead.

Viewport, full-page, and runner screenshots

  • capture: 'viewport' records the currently visible application viewport. Use it to inspect what fits on screen at the chosen mobile dimensions.
  • capture: 'fullPage' scrolls and stitches captures to show the whole page. Fixed or sticky elements may repeat in the stitched image, and it does not represent the screen as a user sees it at one moment.
  • capture: 'runner' includes the Cypress browser context, which can help debug a test. It is not an application-only screenshot.

The default screenshot capture mode is fullPage. Set the mode explicitly when the artifact must represent the mobile viewport. Automatic screenshots captured after test failures are coerced to runner captures.

Keep screenshot state stable

  1. Visit the page at the target size and wait for the intended page state.
  2. Assert the content and responsive controls you expect to appear.
  3. Capture only after those assertions pass.
  4. Keep the browser, browser version, operating system, display scaling, fonts, and viewport consistent when comparing screenshots.

Cypress’s screenshot API disables JavaScript timers and CSS animations by default during capture. If the application still has changing content, wait for a stable state or use the screenshot API’s callbacks to make synchronous adjustments immediately before or after capture. Avoid relying on an arbitrary delay when an assertion or explicit application-ready condition can establish that the page is ready.

3. Test several sizes without losing useful failures

A small set of sizes should cover the application’s actual responsive transitions: include sizes just below and above relevant breakpoints, plus any important narrow or landscape layout. Give each capture a descriptive name that includes its dimensions. This makes local review and CI artifacts easier to identify.

Keep assertions specific to the layout at each size. For example, verify that the mobile menu button is visible and desktop navigation is hidden where appropriate; at a wider breakpoint, assert the opposite. A screenshot alone cannot tell the test runner that a layout is correct.

Prefer separate test cases for independently meaningful viewport scenarios. If a test fails at one size, the test name and screenshot name should make that size apparent. Cypress resets a changed viewport between tests, so set the intended viewport in each test rather than depending on a size left by a previous test.

4. Run screenshots in CI and compare changes

Cypress’s built-in cy.screenshot() command captures images but does not compare them. For manual review, save the artifacts and inspect them. For visual regression review, add a visual testing integration that fits your team’s browser coverage, responsive rendering, pull-request review, and approval workflow.

Cypress’s visual testing guide describes integrations including Applitools Eyes, Argos, Chromatic, Happo, LambdaTest SmartUI, and Percy. Their capabilities, pricing, availability, and plan limits can change; check each provider’s current documentation before selecting one. Keep the Cypress assertions even when adding image comparison: assertions verify behavior, while visual comparison helps surface unintended rendering changes.

When a CI screenshot differs from a local one, first check environment consistency: browser version, operating system, installed fonts, display scaling, viewport dimensions, and data or page state. A visual diff can arise from those rendering differences even when the application change is not meaningful.

5. Viewport versus browser display size

cy.viewport() sets the application’s viewport dimensions. Cypress’s before:browser:launch API can configure the headless browser display size, which affects screenshots and videos separately. Changing the browser window size is not a replacement for setting the application viewport to a mobile width.

6. Troubleshooting

Symptom Likely cause Fix
The screenshot is desktop-sized The test changed the browser display size, or captured before setting the application viewport. Call cy.viewport(width, height) in the test before visiting or capturing. Use the browser launch setting only for display-size needs.
The screenshot includes Cypress controls The capture mode is runner, or the screenshot came from automatic failure capture. For an application-only image, explicitly call cy.screenshot(name, { capture: 'viewport' }).
The image contains the whole long page The default capture mode is fullPage. Set capture: 'viewport' to capture only the visible mobile area.
Sticky headers or buttons repeat in the image A full-page capture stitches screenshots taken while scrolling. Use viewport capture for a user-view screenshot, or account for repeated fixed elements when using full-page capture for page review.
The mobile control assertion fails The breakpoint, selector, or expected responsive state may not match the app; alternatively the page may not have reached the expected state. Check the CSS breakpoint at the exact viewport width, confirm the selector, and assert or wait for the page state before capturing.
Viewport changes unexpectedly between tests Cypress resets viewport changes to the configured default between tests. Set the desired dimensions in every test, or configure the suite’s default viewport.
Code using Cypress.config() to resize fails Since Cypress 16.0.0, changing viewport configuration at runtime with Cypress.config() is unsupported. Use cy.viewport() during a test or set dimensions in test or suite configuration.
Screenshot diffs vary between local and CI Rendering environments or page state differ. Align browser and OS versions, fonts, display scaling, viewport, data, and loaded state; keep animations and timers controlled.

7. Performance, reliability, and cost

Each viewport scenario adds page visits, assertions, and screenshot artifacts to the run. Start with sizes that exercise real breakpoints and important layouts; add more cases when they cover a distinct behavior. Full-page captures can take more work because Cypress scrolls and stitches the page, and their fixed-element artifacts may make visual review less reliable.

For repeatable results, use deterministic test data and explicit readiness assertions, capture after the relevant state is visible, and keep rendering environments aligned. Cypress’s screenshot command is part of the test workflow; visual comparison services are optional and have their own current pricing and terms. The dossier does not establish a universal performance or cost figure for those services.

8. Or skip the browser setup

If you need a screenshot of a public page at a chosen viewport without configuring Cypress, ScreenshotNeo provides a website screenshot API and MCP server. Set the viewport in the request parameters; see the ScreenshotNeo API documentation for the supported parameter names and options.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -d viewport_width=375 \
  -d viewport_height=812 \
  -o mobile.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={
        "access_key": "YOUR_API_KEY",
        "url": "https://stripe.com",
        "viewport_width": 375,
        "viewport_height": 812,
    },
    timeout=90,
)
r.raise_for_status()
open("mobile.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com',
  viewport_width: '375',
  viewport_height: '812',
})
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`)
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`)
const fs = await import('node:fs/promises')
await fs.writeFile('mobile.webp', Buffer.from(await res.arrayBuffer()))

ScreenshotNeo accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan. Create a free ScreenshotNeo account to get started.

9. FAQ

Does a Cypress screenshot test verify a physical phone?

No. It sets the browser application viewport and checks responsive rendering at those dimensions. It does not simulate device pixel ratio or all physical-device behavior.

Can Cypress tell whether two screenshots look the same?

The built-in screenshot command captures images but does not compare them. Use a visual testing integration if you need automated visual change review.

Should I use a preset or exact dimensions?

Use exact dimensions when testing specific breakpoints or when you need a stable, clearly named case. Use a supported preset when its dimensions and orientation match the behavior you want to cover.