ScreenshotNeo

BlogHow-to

How to Capture a Screenshot of a Specific Element in Cypress

Capture a specific DOM element in Cypress with `.screenshot()`. Learn how to add padding, control filenames, handle timing, and troubleshoot missing or unreliable captures.

By the ScreenshotNeo team4 October 20267 min read

To capture a specific element in Cypress, select it with a query such as cy.get() and chain .screenshot() from the resulting element:

cy.get('.post').first().screenshot()

Cypress saves the image in its screenshots folder. You can add space around the element with padding, or pass a filename as the first argument. The command captures an image; visual comparison against a baseline is a separate workflow.

1. Capture one element

Cypress allows .screenshot() to be chained from cy or from a command that yields a single DOM element. To target a particular element, query it first:

describe('post card screenshot', () => {
  it('captures the first post card', () => {
    cy.visit('/blog')
    cy.get('.post').first().screenshot()
  })
})

Replace /blog and .post with a route and selector from your application. Cypress must be able to find the element when the screenshot command runs. If the selector matches multiple elements, narrow it with .first(), .eq(index), or a more specific query so the command yields one element.

The command yields the same subject, but Cypress warns that it is unsafe to chain later commands that depend on that subject. Keep the screenshot as the end of that subject-dependent chain.

2. Add padding or name the screenshot

Use the padding option to include space around the element. It accepts a number or an array of up to four values in CSS shorthand order:

// 10 pixels on every side
cy.get('.post').first().screenshot({ padding: 10 })

// top, right, bottom, left
cy.get('.post').first().screenshot({ padding: [8, 16, 8, 16] })

Give the capture an explicit name when you want a recognizable artifact:

cy.get('.post').first().screenshot('post-card')

Screenshot paths are relative to the configured screenshots folder and the spec path. Cypress uses test-based names by default. Duplicate names receive a numeric suffix unless overwrite is enabled.

3. Configure where screenshots are saved

The default screenshotsFolder is cypress/screenshots. Set it in Cypress configuration if your CI artifact collection or repository conventions expect another location. For example, in a CommonJS configuration file:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  screenshotsFolder: 'artifacts/cypress-screenshots',
})

Use the configuration format your project already uses if it is an ESM or TypeScript Cypress configuration. Cypress also saves screenshots of failed tests during cypress run by default; that behavior and the folder location can be configured separately from an explicit element screenshot.

4. Understand element capture options and timing

Element screenshots capture the selected DOM element. The capture modes for application viewport, full page, or runner do not change this element-specific behavior; Cypress documents that capture is ignored for element captures. The clip option describes a pixel rectangle using x/y position, width, and height for cropping, but it is not a substitute for selecting the element you want.

Screenshot capture is asynchronous and takes around 100 ms according to Cypress documentation. Application state can change before capture completes. If a non-failure screenshot needs a controlled frame, Cypress supports the screenshot command’s callbacks for synchronous DOM adjustments immediately before and after capture. Avoid adding asynchronous work inside those callbacks.

For deterministic output, make the page state stable before taking the image: wait for the relevant content to render, complete animations or disable them for the test, and ensure the element is visible. Cypress runs chained assertions once for .screenshot(); they do not retry as ordinary query assertions do. Put retryable readiness checks before the capture.

5. A complete Cypress example

This example waits for a card to exist, verifies that it is visible, and saves a named capture with padding:

describe('blog card visual artifact', () => {
  it('captures a ready card', () => {
    cy.visit('/blog')

    cy.get('[data-cy="post-card"]')
      .first()
      .should('be.visible')
      .screenshot('first-post-card', { padding: 12 })
  })
})

For best selector stability, prefer an explicit test attribute such as data-cy over styling classes that may change as the design evolves. If your app renders cards asynchronously, wait on an application-specific signal or assert the target’s required content before capturing.

6. cURL, Python, and Node.js alternatives

The built-in Cypress command is the direct way to capture an element in a Cypress test. The following runnable examples are useful when you need to capture a whole URL from a separate script or service. They capture a page URL rather than selecting a DOM element by Cypress selector.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

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}`)
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())))

See the ScreenshotNeo API documentation for API parameters and response details. For an element inside your app, use the Cypress selector approach above; a URL-based API call does not accept a Cypress DOM subject.

7. Troubleshooting

Symptom Likely cause Fix
No screenshot is created The test failed before reaching the command, the element query did not resolve, or the output is in a different folder than expected. Check the test failure and selector, then inspect the configured screenshotsFolder and spec-relative output path.
The wrong element is captured The query matched a different item or the first match is not the intended card. Use a stable test attribute and narrow the selection with .eq(), .first(), or a scoped query.
The element is missing or clipped The app had not rendered it yet, it was hidden, or the layout changed during capture. Assert visibility and application readiness before calling .screenshot(); stabilize layout and animations.
Padding or full-page mode has no expected effect capture modes do not apply to element captures. Use the documented padding option for space around an element. Select the target element directly.
Assertions after the screenshot behave unexpectedly The screenshot command yields the subject but is not safe for further subject-dependent chaining, and its chained assertions do not retry. Put retryable queries and assertions before .screenshot(); start a fresh query for later work.
Artifacts have unexpected names Cypress defaults to test-based names and adds numeric suffixes for duplicate names unless overwrite is enabled. Pass a descriptive name and choose overwrite behavior intentionally if the same path must be reused.

8. Reliability, performance, and cost

A local Cypress element screenshot adds an asynchronous capture step, documented as taking around 100 ms. Keep captures targeted and avoid taking them before the page reaches a stable state. In CI, collect the configured screenshots folder as an artifact so failures and named captures remain available after the job ends.

Cypress’s built-in screenshot produces an image artifact. If you need to detect visual changes, you also need a baseline and a comparison or review workflow. Cypress’s visual testing guide describes Percy as capturing DOM snapshots and rendering across browsers and responsive widths, and Sauce Labs Visual as providing baseline creation, region ignoring, and review workflows; it also points to Applitools documentation. Choose such a workflow when review and comparison are the goal, rather than expecting .screenshot() alone to produce a visual diff.

For a local Cypress test, the direct command has no ScreenshotNeo API charge. ScreenshotNeo is a separate URL-based service with a free allowance and paid plans; its billing and capture behavior are described below.

9. Or skip the browser setup

When the task is a URL screenshot rather than an element within the running Cypress app, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. Its API parameter names used by other screenshot APIs also work, which can make a switch easier. Read the API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp

Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. An MCP server lets AI agents using Claude, Cursor, or another MCP client take screenshots. 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 required.

10. FAQ

Can I capture more than one element?

Yes. Query and screenshot each target in the test, giving each a distinct name if you need separate, easily identifiable artifacts.

Does an element screenshot create a visual diff?

No. It saves an image. Baseline management, comparison, and review require a separate visual testing workflow.

Can I use this command in a browser session outside Cypress?

cy.screenshot() is a Cypress command. For other automation environments, use that tool’s capture API or a screenshot service that accepts a URL.