skip to content

In Playwright, when is locator.screenshot() a better capture than page.screenshot() with clip or fullPage?

level: middleimportance: should knowfreq 44%

answer

  1. One frames a page, one frames an element
  2. Coordinates versus a live box
  3. Scroll and stability come free on one side
  4. fullPage and clip are page-only
  5. Overlays still land in the frame

basics

~20 s

Whenever the subject is one element. Playwright's locator.screenshot scrolls it into view, waits for it to be stable and measures its box at capture time, while a clip rectangle is a fixed region you computed yourself that goes stale as soon as the layout moves.

solid answer

~50 s

`page.screenshot()` photographs the page: the viewport by default, the whole scrollable document with `fullPage: true`, or a fixed rectangle with `clip: { x, y, width, height }`. `locator.screenshot()` photographs one element: it scrolls the element into view, waits for it to be visible and stable, then clips to the box it measures at that moment. So for a single widget -- the driver map card on an order tracker -- the locator form is more robust, because it re-measures instead of trusting coordinates you captured earlier. `fullPage` and `clip` exist only on the page API; `mask`, `maskColor`, `animations`, `caret`, `omitBackground`, `scale`, `type`, `quality`, `path` and `timeout` are common to both. Either returns a Buffer when `path` is omitted. Element capture still shows any overlay covering the element, and a scrollable element only shows its current scroll position.

code

typescript · 7 lines
typescript
import { test } from '@playwright/test';

test('driver map renders', async ({ page }) => {
  await page.goto('/orders/8842');
  const card = page.getByTestId('driver-map-card');
  await card.screenshot({ path: test.info().outputPath('driver-map.png') });
});

go deeper

for a junior

Recall that page.screenshot frames the page, with fullPage and clip as its options, while locator.screenshot frames a single element and needs no coordinates from you.

for a middle

Explain why element capture is more robust: it scrolls into view, waits for stability and measures the box at capture time, whereas a clip rectangle is stale the moment the layout moves.

for a senior

Show the failure mode in practice, that a stale crop silently captures the wrong pixels, and choose per situation between full-page evidence and small element captures for report size and review speed.

for a principal

Set the convention for what a suite captures and how large its evidence is allowed to be, so reports stay openable and reviewers get the frame that answers the question.

## Two different subjects Both APIs write a PNG or JPEG; they differ in what the frame is *about*. - `page.screenshot()` -- the subject is the page. By default it captures the viewport; `fullPage: true` captures the whole scrollable document; `clip: { x, y, width, height }` captures a fixed rectangle in CSS pixels relative to the page. - `locator.screenshot()` -- the subject is one element. Playwright scrolls it into view, waits for actionability (attached, visible, and not animating), measures its bounding box **at that moment** and clips to it. The second is not a convenience wrapper over the first. The measurement happens at capture time, which is the entire reason to prefer it. ## What only the page API can do | Capability | `page.screenshot()` | `locator.screenshot()` | |---|---|---| | Whole scrollable document (`fullPage`) | yes | no | | Arbitrary rectangle (`clip`) | yes | no | | Auto scroll-into-view of the subject | no | yes | | Waits for the subject to stop animating | no | yes | | `mask` / `maskColor` | yes | yes | | `omitBackground`, `animations`, `caret`, `scale`, `style` | yes | yes | | Returns a Buffer when `path` is omitted | yes | yes | ## Why a clip rectangle goes stale A `clip` is numbers, and numbers do not follow the DOM. To crop the driver-map card on an order tracker with `clip` you must first read its box with `locator.boundingBox()`, then pass those coordinates to `page.screenshot()`. Between those two calls the page can: 1. finish loading a promotion banner above the card, pushing it down; 2. settle a layout shift as a web font swaps in; 3. re-render the live status strip and change the card's height. Any of those makes the rectangle photograph the wrong pixels -- silently, because a crop cannot fail. `locator.screenshot()` collapses the two steps into one operation that measures and captures together, and it fails loudly with a timeout if the element never becomes visible or never settles. ## What element capture still cannot do - **Overlays are not removed.** If a cookie banner or a modal covers the card, the capture shows the banner. The frame is the element's *region*, not the element in isolation. - **Scrollable elements show only what is scrolled into view.** A long order-history list clipped to its container is captured at its current scroll position, not in full. - **Off-screen size still applies.** An element taller than the viewport is captured whole, so the page scrolls during capture -- fine for static content, awkward for sticky headers. - **It is still evidence, not a reference.** Comparing an element image against an approved baseline is a different mechanism with its own approval flow. ## Choosing in practice 1. One widget, and you know its locator: `locator.screenshot()`. 2. The whole page as failure evidence: `page.screenshot({ fullPage: true })`. 3. A region defined by geometry rather than by an element -- a fixed area of a canvas-rendered map, for example: `page.screenshot({ clip })`, taken as close in time to the measurement as you can. ## A worked shape ```ts const card = page.getByTestId('driver-map-card'); await card.screenshot({ path: test.info().outputPath('driver-map.png'), mask: [page.getByTestId('customer-address')], }); ``` That capture scrolls the card into view, waits for it to settle, masks one region, and writes into the test's own output folder. The `page.screenshot({ clip })` equivalent needs a `boundingBox()` call, a null check, and an assumption that nothing moved in between. ## Cost and legibility Full-page captures on a long tracker page can run to several megabytes each and are slow to open in a report. Element captures are small and are what a reviewer actually wants when the failure is localised. A useful habit: full page for the automatic failure evidence, element captures for the specific thing a test was asserting about.

  • A modal overlays the driver-map card. What does locator.screenshot() produce, and how would you get a clean image?
    It produces the card's region with the modal drawn over it, because the capture is a crop of the rendered page, not an isolated render of the element. Dismiss or close the overlay first, or capture in a state where it is not shown; there is no option that renders an element free of what covers it.
  • When would you still reach for page.screenshot with clip?
    When the region is defined by geometry rather than by an element -- a fixed quadrant of a canvas-drawn map, or an area spanning several unrelated nodes. Measure and capture as close together as possible, since the rectangle carries no relationship to the DOM and will not notice a layout shift.

saying these in an interview costs you the question

  • Thinks locator.screenshot accepts fullPage or clip
  • Believes element capture hides overlapping elements
  • Computes a clip rectangle early and reuses it later
  • Assumes a scrollable container is captured in full
  • Says only the page API can mask regions