ScreenshotNeo

BlogHow-to

How to Take Mobile Website Screenshots with Cypress Viewport Settings

Set a mobile-sized Cypress viewport, wait for the right page state, and capture the visible screen or full page. Includes configuration, troubleshooting, and a ScreenshotNeo option.

By the ScreenshotNeo team4 October 20267 min read

Set the browser viewport with cy.viewport(width, height) or a Cypress device preset, visit the page, wait until the responsive state you want is visible, and call cy.screenshot(). Use { capture: 'viewport' } to save the visible application area, or { capture: 'fullPage' } to capture the page from top to bottom.

describe('mobile layout', () => {
  it('captures the mobile home page', () => {
    cy.viewport(375, 667)
    cy.visit('/')
    cy.get('h1').should('be.visible')
    cy.screenshot('mobile-home', { capture: 'viewport' })
  })
})

The example assumes the app is available at the base URL configured for Cypress and that a visible heading indicates the page is ready. Replace that assertion with one that represents the state your screenshot needs. Cypress viewport settings test layout dimensions; they do not emulate every physical-device characteristic.

1. Set a mobile viewport

Call cy.viewport() before visiting the page or before the actions that depend on the viewport. It accepts explicit width and height in pixels, or a named preset from Cypress’s documented list. See the Cypress viewport API.

// Explicit dimensions: useful for testing a breakpoint
cy.viewport(375, 667)

// Named preset
cy.viewport('iphone-6')

// Preset in landscape
cy.viewport('iphone-6', 'landscape')
Preset Portrait dimensions Landscape dimensions
iphone-5 320 × 568 568 × 320
iphone-6 375 × 667 667 × 375
iphone-x 375 × 812 812 × 375
samsung-s10 360 × 760 760 × 360

Use an explicit size when you need to exercise a CSS breakpoint or match a project’s target viewport precisely. Preset labels provide convenient dimensions; they do not make the test equivalent to running on that physical phone. Cypress documents that devicePixelRatio is not simulated.

2. Capture the viewport or the full page

cy.screenshot() supports several capture modes. For a mobile website screenshot, the distinction between the visible viewport and a full-page capture matters: a full-page image may be much taller than a phone screen.

Capture mode What it includes When to use it
viewport The application content in the current viewport Check the initial mobile screen, header, or above-the-fold layout
fullPage The application page from top to bottom Review a whole page or save a long-page reference
runner The browser viewport including Cypress Command Log chrome, subject to Cypress’s documented behavior Capture test-runner context for debugging

Manual screenshots default to fullPage. Specify the mode when the output needs a predictable scope. The Cypress screenshot API documents capture modes, clipping, element screenshots, and callbacks.

// Visible application area
cy.screenshot('mobile-viewport', { capture: 'viewport' })

// Entire page, top to bottom
cy.screenshot('mobile-full-page', { capture: 'fullPage' })

// Crop a rectangle from the viewport
cy.screenshot('mobile-crop', {
  capture: 'viewport',
  clip: { x: 0, y: 0, width: 375, height: 300 },
})

// Capture one element
cy.get('[data-testid="product-card"]').screenshot('product-card')

A clip is expressed in pixels with x, y, width, and height. Make sure the requested rectangle fits the image you intend to capture. For an element capture, select the element after the page has rendered and use the element’s .screenshot() command.

3. Wait for the state you want to save

Screenshot capture is asynchronous. The application can change after the command is issued and before the image is finished, so establish the state with Cypress assertions and commands first. Avoid arbitrary sleeps when a visible element, loaded data, or completed transition can be asserted directly.

describe('mobile product page', () => {
  it('captures a product after its data loads', () => {
    cy.viewport(375, 812)
    cy.visit('/products/example')

    cy.get('[data-testid="product-title"]')
      .should('be.visible')
      .and('contain.text', 'Example')
    cy.get('[data-testid="product-price"]').should('be.visible')

    cy.screenshot('product-mobile', { capture: 'viewport' })
  })
})

For a page whose content appears after a request, wait on the relevant request or assert on the resulting content. For pages with animations, capture after the UI reaches its settled state. Cypress screenshot defaults normally disable JavaScript timers and CSS animations during capture; those behaviors can be customized through screenshot configuration.

4. Configure project defaults and save location

Cypress’s default viewport is 1000 × 660 pixels. Set project defaults in Cypress configuration when most tests use the same dimensions, or set the viewport in a test for a specific mobile scenario. The default screenshot folder is cypress/screenshots.

// cypress.config.js
const { defineConfig } = require('cypress')

module.exports = defineConfig({
  viewportWidth: 375,
  viewportHeight: 667,
  screenshotsFolder: 'cypress/screenshots',
  e2e: {
    baseUrl: 'http://localhost:3000',
  },
})

A per-test viewport can override the configured defaults:

it('uses a narrow viewport for this case', () => {
  cy.viewport(320, 568)
  cy.visit('/')
  cy.get('main').should('be.visible')
  cy.screenshot('narrow-mobile', { capture: 'viewport' })
})

Cypress resets the viewport to its configured default between tests. Starting with Cypress 16.0.0, changing viewportWidth or viewportHeight through Cypress.config() during test execution throws. Use cy.viewport() or test configuration for runtime test sizing. See the configuration reference and Cypress.config() API.

5. Run the test and find the screenshot

Manual cy.screenshot() calls work in Cypress open mode and run mode. With the default configuration, a failed test in cypress run also gets an automatic failure screenshot; Cypress does not automatically take failure screenshots in open mode. Configure screenshotOnRunFailure if you need to change failure-screenshot behavior.

# Run the end-to-end suite in the terminal
npx cypress run

Look in the configured screenshot folder, which defaults to cypress/screenshots. Manual screenshot names become image files there. For the failure behavior and related settings, see Cypress screenshots and videos.

6. Make mobile screenshots repeatable

A screenshot is an image capture; cy.screenshot() does not compare it with a baseline. If you are checking visual changes, keep the viewport and execution environment consistent across baseline and candidate images. Cypress notes that operating systems, browser versions, display scaling, and installed fonts can change rendered output. Its visual testing guide describes the comparison workflow and available integrations.

  • Use the same explicit viewport dimensions or preset for every run.
  • Keep browser, operating system, and installed fonts consistent when comparing images.
  • Assert that the responsive state and important page content are present before capture.
  • Wait for meaningful application readiness instead of capturing during a loading transition.
  • Choose viewport or fullPage deliberately so image dimensions remain consistent.

7. Troubleshooting

The screenshot has desktop dimensions

Cause: The test did not set the viewport before capture, or the viewport was reset between tests. Fix: Call cy.viewport() in the test that captures the image, or configure viewportWidth and viewportHeight as project defaults.

The screenshot is much taller than expected

Cause: Manual screenshots use fullPage by default. Fix: Pass { capture: 'viewport' } for only the visible application area.

The screenshot shows a loading state or incomplete content

Cause: The screenshot was requested before the relevant UI appeared, or capture overlapped a changing page state. Fix: Assert on the page content, data, or state that matters before calling cy.screenshot().

The image differs across machines

Cause: Browser versions, operating systems, display scaling, or fonts can affect rendering. Fix: Use the same execution environment for both images and hold the viewport constant. Cypress viewport sizing does not simulate device pixel ratio or fully reproduce a physical phone.

Changing viewport configuration at runtime throws

Cause: In Cypress 16.0.0 and later, changing viewportWidth or viewportHeight via Cypress.config() during a test is unsupported. Fix: Call cy.viewport(width, height), or provide dimensions through Cypress or test configuration.

No failure screenshot appears in open mode

Cause: Automatic failure screenshots are enabled by default for cypress run, not cypress open. Fix: Add an explicit cy.screenshot() call when you need a manual capture in open mode, or run the suite in run mode for automatic failure captures.

8. Performance, reliability, and cost

For a small set of responsive checks, Cypress captures images as part of the browser test flow. Keep each screenshot purposeful: full-page captures produce taller images, while viewport captures focus on the mobile screen under test. Waiting for an application-specific condition improves reliability and avoids saving transient loading states.

Cypress’s screenshot command is not a visual diff engine. If you need regression detection, use a comparison workflow and keep its rendering environment fixed. The Cypress visual testing guide lists integrations; verify current product capabilities and terms directly before selecting one. No service is required just to set a viewport and save an image. Project costs depend on the Cypress setup and any comparison service you choose; the cited Cypress API documentation does not establish a general price.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. A GET request returns a PNG, JPEG, WebP, or PDF capture. Its API documentation covers the parameters, including the names used by other screenshot APIs.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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(`Screenshot request failed: ${res.status}`)
const bytes = new Uint8Array(await res.arrayBuffer())
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes))

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, and failed loads are never billed. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Plans include every feature, and yearly billing gives two months free. Sign up free and get 1,000 screenshots a month with no card.

FAQ

Does a Cypress mobile viewport emulate a real phone?

No. It sets the browser viewport dimensions and orientation. Cypress documents that devicePixelRatio is not simulated, so it is useful for responsive layout checks but is not a full device emulation.

How do I take a screenshot at a custom breakpoint?

Pass the breakpoint’s desired dimensions directly, such as cy.viewport(390, 844), then assert that the expected layout is visible before capturing.

Can Cypress capture just one element?

Yes. Select the element and call .screenshot() on it. This is useful when the component matters more than the page around it.

Does Cypress compare screenshots automatically?

No. cy.screenshot() saves an image. A separate visual comparison workflow is needed to detect differences between a baseline and a later capture.