ScreenshotNeo

BlogHow-to

How to Generate High-Resolution Screenshots and Videos with Cypress

Configure Cypress display size, viewport, device scale factor, screenshots, and video compression without confusing their effects.

By the ScreenshotNeo team4 October 20268 min read

To get higher-resolution Cypress screenshots, configure the headless browser’s display size and, for supported Chromium runs, its device scale factor in before:browser:launch. Set the application’s CSS viewport separately with viewportWidth, viewportHeight, or cy.viewport(). For videos, enable video for cypress run and tune videoCompression for the quality, file-size, and processing-time tradeoff. These settings solve different problems: a larger CSS viewport alone does not produce a retina screenshot.

1. Set up a high-resolution headless browser

In Cypress configuration, use setupNodeEvents to handle before:browser:launch. This documented Chromium pattern sets the headless window to 1400 × 1200 and requests a device scale factor of 2:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on('before:browser:launch', (browser, launchOptions) => {
        if (browser.name === 'chrome' && browser.isHeadless) {
          launchOptions.args.push('--window-size=1400,1200')
          launchOptions.args.push('--force-device-scale-factor=2')
        }
        return launchOptions
      }),
    },
  },
})

For an ES module configuration, use the equivalent import and export syntax supported by your project:

import { defineConfig } from 'cypress'

export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on('before:browser:launch', (browser, launchOptions) => {
        if (browser.name === 'chrome' && browser.isHeadless) {
          launchOptions.args.push('--window-size=1400,1200')
          launchOptions.args.push('--force-device-scale-factor=2')
        }
        return launchOptions
      }),
    },
  },
})

The dimensions are an example for the documented Chromium headless setup, not a guarantee for every browser, operating system, Cypress release, or page. Cypress documentation illustrates 1400 × 1200 at scale factor 1 and 2800 × 2400 at scale factor 2 for this setup. The headless display size does not set Cypress’s viewportWidth or viewportHeight; those define the app area shown inside the runner. See Cypress’s browser launch API.

Choose settings for the browser you run

Launch flags differ by browser family and mode. Check browser.name and browser.isHeadless before appending Chromium-specific flags. Select the browser explicitly in your run command so that local and CI captures use the intended browser. Avoid applying Chrome flags to another browser and assuming they have the same effect.

2. Set the application viewport separately

Use global viewport settings when most tests need the same responsive layout. Cypress documents a default viewport of 1000 × 660 CSS pixels.

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  viewportWidth: 1400,
  viewportHeight: 1200,
  e2e: {
    setupNodeEvents(on, config) {
      // Add browser launch configuration here if needed.
      return config
    },
  },
})

For a specific test, change the viewport directly:

it('renders the desktop layout', () => {
  cy.viewport(1400, 1200)
  cy.visit('/dashboard')
  cy.get('[data-testid="dashboard"]').should('be.visible')
})

cy.viewport() changes the app’s CSS viewport; it does not simulate devicePixelRatio. Use the browser launch setup when you need a higher pixel density in a supported headless Chromium capture. Cypress explains this distinction in its viewport API.

3. Capture the intended part of the page

Use cy.screenshot() for a manual capture. The API supports viewport, full-page, and runner captures. Its default is full page.

it('saves a full-page screenshot', () => {
  cy.visit('/pricing')
  cy.screenshot('pricing-full-page', { capture: 'fullPage' })
})

Capture only the current viewport when the test concerns a particular visible state:

it('saves the visible menu state', () => {
  cy.visit('/')
  cy.get('[data-testid="menu-button"]').click()
  cy.screenshot('open-menu', { capture: 'viewport' })
})

The capture option accepts 'viewport', 'fullPage', or 'runner'. The scale option controls whether the app is scaled to fit the browser viewport. It defaults to false, except runner captures where it is coerced to true. For screenshots captured automatically after a test failure during cypress run, Cypress uses runner capture. Disable automatic failure screenshots with screenshotOnRunFailure: false if that better suits your artifact workflow. Consult the screenshot API for the complete option list and behavior.

4. Record and tune Cypress videos

Video recording is off by default. Enable it in Cypress configuration to record each spec during cypress run; Cypress does not record these videos in cypress open. Videos are saved per spec under cypress/videos by default.

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  video: true,
  videoCompression: 20,
  e2e: {
    setupNodeEvents(on, config) {
      return config
    },
  },
})

videoCompression controls video compression. Compression is disabled by default; true uses CRF 32. Cypress documents a CRF range of 1–51: lower values generally improve image quality and increase file size, while encoding consumes processing time. A numeric value such as 20 is an example setting, not a promise of a particular visual result. Choose a lower CRF when detail matters most; choose a higher CRF when smaller artifacts matter more. Measure the result with your pages and CI workload.

When video and compression are both enabled, Cypress can embed chapters for attempts in a spec. Supported players include VLC, QuickTime, and IINA. Cypress Cloud also presents tests alongside the run video and lets viewers jump to the corresponding point. Read the official screenshots and videos guide and the configuration reference.

5. Keep captures repeatable and artifacts manageable

  1. Pin the browser and dimensions. Use the same browser, headless mode, display size, device scale factor, and CSS viewport in local and CI runs.
  2. Wait for the page state you intend to capture. Let the relevant content render before requesting a screenshot; otherwise the image may show a transient loading or animation state.
  3. Compare like with like. Generate and compare visual captures in the same environment with a fixed viewport, as Cypress recommends in its visual testing guidance.
  4. Plan artifact cleanup. Cypress clears screenshot and video artifact folders before cypress run by default, including nested folders. Set trashAssetsBeforeRuns: false if you need to preserve existing files. Change screenshotsFolder and videosFolder to choose other locations.
  5. Account for Cloud processing. On Cloud-recorded runs, video processing and upload happen after each spec. Compression can add encoding work and an interval before the artifact is ready.

Cypress Cloud can store and share test run artifacts with a team. Its recorded runs documentation describes the workflow.

6. Troubleshoot low-resolution or missing artifacts

Symptom Likely cause What to change
Increasing cy.viewport() did not make the screenshot denser. The CSS viewport does not simulate devicePixelRatio. For headless Chromium, configure the device scale factor in before:browser:launch, then capture with the intended screenshot mode.
The capture has the wrong page dimensions. Headless display dimensions and Cypress viewport dimensions are separate settings. Set the launch window size and viewportWidth/viewportHeight independently; verify the browser and headless mode used by the run.
Chromium flags appear to have no effect. The run may use a different browser or headed mode, or the launch handler may not match its name. Inspect the browser passed to before:browser:launch, branch on its name and isHeadless, and use browser-specific documented options.
A failure screenshot shows the runner instead of just the app. Cypress coerces automatic failure captures during cypress run to runner captures. Use manual cy.screenshot({ capture: 'viewport' }) for the app view, or disable automatic failure captures with screenshotOnRunFailure: false.
No video appears. Video is disabled by default, or the command used cypress open. Set video: true and run the spec with cypress run.
Videos are much larger than expected. Compression is disabled or the CRF is low. Enable compression or use a higher CRF, then compare artifact size and visible detail for representative specs.
Video processing takes longer. Compression adds processing time, and Cloud runs may need time to encode and upload videos. Use a higher CRF or disable compression if processing time matters more than file size; account for Cloud artifact processing in your pipeline.
Artifacts from a previous run disappeared. Cypress clears artifact folders before cypress run by default. Set trashAssetsBeforeRuns: false or write artifacts to a location managed by your own workflow.

7. Performance, reliability, and cost

Higher pixel dimensions increase the amount of image data in the resulting artifact, and video compression trades processing time against file size and quality. The precise runtime, output size, and visual result depend on the browser, page, environment, and configuration; the Cypress documentation provides configuration behavior rather than universal performance guarantees.

For reliable visual comparisons, keep browser version, operating environment, CSS viewport, display size, and scale factor consistent. Treat screenshots and videos as run artifacts: decide where they are stored, how long they are retained, and whether cleanup before each run is acceptable. Cypress Cloud is an optional team workflow for storing and sharing run artifacts; review its current documentation for plan and usage details.

8. Or skip the browser setup

If the goal is a clean screenshot of a URL rather than a Cypress test artifact, ScreenshotNeo is a website screenshot API and MCP server. It returns PNG, JPEG, WebP, or PDF from one GET request. Its API also accepts the parameter names used by other screenshot APIs, which can make switching easier. The API documentation lists the request options.

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}`);

ScreenshotNeo accepts cookie banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and responses include X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan.

More options include full-page capture with lazy images loaded, CSS selector element capture, dark mode, device presets and custom viewports, retina scale, PDF settings, HTML/CSS capture, custom CSS and JavaScript, clicks, selector hiding, wait conditions, request blocking, headers and cookies, timezone and geolocation, transparent backgrounds, resizing, cache TTL, signed image links, async jobs with signed webhooks, bulk capture for 100 URLs per call, a usage API, and an OpenAPI spec. See the ScreenshotNeo docs for configuration details.

Sign up for 1,000 free screenshots a month with no card, or choose a paid plan starting at $5 for 3,000 screenshots.

9. FAQ

Does a high device scale factor change responsive breakpoints?

Responsive layout is driven by the CSS viewport. Device scale factor affects the relationship between CSS pixels and device pixels; set and verify viewport dimensions independently.

Can Cypress record video while running tests in the interactive app?

The documented Cypress video recording workflow applies to cypress run. Cypress does not record these videos in cypress open.

Should every project use the same CRF value?

No. Choose based on the visual detail your team needs, artifact size limits, and encoding time, then keep the choice consistent for comparable runs.

Will a scale factor of 2 always double screenshot width and height?

Do not assume a universal result. Cypress’s documented Chromium example illustrates doubled output dimensions for its stated setup; behavior can depend on browser, operating system, Cypress release, and capture mode.