Resource library

QA How-To

Playwright Python screenshots and video (2026)

Master Playwright Python screenshots and video with full-page capture, locator images, pytest settings, artifact retention, masking, and CI diagnostics.

14 min read | 2,988 words

TL;DR

Use page.screenshot() or locator.screenshot() for deliberate still images. Enable video when creating the BrowserContext with record_video_dir, then close the context before reading or saving the video. In pytest-playwright, use CLI artifact options and retain evidence on failure while masking secrets.

Key Takeaways

  • Use page.screenshot() or locator.screenshot() for deliberate still images.
  • Use observable UI state and web-first assertions instead of fixed sleeps.
  • Keep test data, browser state, and artifacts isolated across workers and retries.
  • Use current Python APIs directly and avoid wrappers that hide lifecycle or intent.
  • Preserve actionable failure evidence while masking secrets and limiting retention.
  • Validate the approach with representative CI workflows before standardizing it.

Playwright Python screenshots and video is most reliable when the test design makes browser lifecycle, application state, and expected evidence explicit. This guide gives working Python patterns and explains the tradeoffs a senior QA or SDET should be ready to defend.

The goal is not a clever demo. It is a maintainable approach that survives parallel CI, product change, and failure investigation. Examples use the synchronous Playwright Python API and pytest conventions that remain current in 2026.

TL;DR

Use page.screenshot() or locator.screenshot() for deliberate still images. Enable video when creating the BrowserContext with record_video_dir, then close the context before reading or saving the video. In pytest-playwright, use CLI artifact options and retain evidence on failure while masking secrets.

Decision Recommended default Reconsider when
Scope Smallest scope that covers the behavior Multiple pages or shared infrastructure require coordination
Synchronization Observable state and web-first assertions Elapsed time is itself the requirement
Test data Synthetic, unique, and owned by the test A controlled shared read-only fixture is cheaper
Evidence Trace plus focused failure artifacts Privacy or storage policy requires a narrower set
Abstraction Plain typed helpers around domain behavior Repetition has not yet established a stable boundary

1. What Playwright Python screenshots and video are for

Screenshots capture a rendered state at one moment, while video records the sequence of frames in a page session. They answer different debugging questions. A screenshot is ideal for layout, overlays, and final state. Video helps reveal the action before a failure, unexpected navigation, flicker, or a dialog that quickly disappears.

Neither artifact explains everything. Traces add DOM snapshots, actions, console output, and network details, while logs describe test-side decisions. A practical evidence policy combines small artifacts based on failure type instead of recording every format forever.

A useful review checklist for this area is: identify the observable requirement, choose the narrowest scope, make ownership explicit, and retain evidence when it fails. Keep setup deterministic and independent from test order. Name fixtures and helpers after product behavior so another engineer can understand the test without opening every implementation file. In CI, use the same browser and dependency versions that were validated locally, while keeping credentials outside source control.

2. Capture page and full-page screenshots

page.screenshot() returns bytes and can also write to path. Set full_page=True to capture the entire scrollable page, not only the viewport. Use type='jpeg' and quality when file size matters and transparency is unnecessary; PNG is the default and is better for crisp UI detail.

Capture after a web-first assertion when you need a stable documented state. If the screenshot is specifically evidence of a transient bug, capture immediately and record why. Avoid arbitrary waits before screenshots, because animations and lazy content can still differ.

Treat this decision as part of the test contract. Record what the test controls, what remains real, and which failure proves the requirement is broken. This prevents a helper from silently expanding into infrastructure that nobody owns. When the product changes, update the behavioral assertion first, then adjust the supporting abstraction. That sequence keeps the suite focused on user risk instead of implementation trivia.

3. Capture one component with Locator

locator.screenshot() waits for the element actionability needed for capture and clips the image to that element. This reduces noise for receipts, charts, dialogs, or error panels. A Locator remains resilient if layout around the component moves.

Use locator assertions before capture when the expected text or state matters. Do not use a screenshot as the only assertion unless visual comparison is explicitly the requirement. A human opening an artifact later should see a filename and context that identify the scenario.

A useful review checklist for this area is: identify the observable requirement, choose the narrowest scope, make ownership explicit, and retain evidence when it fails. Keep setup deterministic and independent from test order. Name fixtures and helpers after product behavior so another engineer can understand the test without opening every implementation file. In CI, use the same browser and dependency versions that were validated locally, while keeping credentials outside source control.

4. Control animations, carets, masking, and styling

Screenshot options can disable animations, hide the caret, mask sensitive locators, and apply temporary CSS through style. Masking overlays elements, while omit_background can preserve transparency in supported images. These controls make diagnostic or visual images more stable.

Mask credentials, tokens, email addresses, payment data, and customer content before artifacts leave the worker. Remember that masking is not a full security boundary: secrets may appear elsewhere, including URLs, console output, network payloads, or earlier video frames. Use synthetic data and restricted artifact access.

Treat this decision as part of the test contract. Record what the test controls, what remains real, and which failure proves the requirement is broken. This prevents a helper from silently expanding into infrastructure that nobody owns. When the product changes, update the behavioral assertion first, then adjust the supporting abstraction. That sequence keeps the suite focused on user risk instead of implementation trivia.

5. Record video with BrowserContext

Video recording is configured when a new BrowserContext is created using record_video_dir and optional record_video_size. Each Page in that context has a Video object. The encoded file is finalized when the browser context closes. Attempting to consume the path too early is a common lifecycle error.

For a deliberate save, keep a reference to page.video, perform the scenario, close the context, then call save_as(). delete() removes an unwanted recording after finalization. When a remote browser connection is involved, save_as() is safer than assuming a local path.

A useful review checklist for this area is: identify the observable requirement, choose the narrowest scope, make ownership explicit, and retain evidence when it fails. Keep setup deterministic and independent from test order. Name fixtures and helpers after product behavior so another engineer can understand the test without opening every implementation file. In CI, use the same browser and dependency versions that were validated locally, while keeping credentials outside source control.

6. Configure pytest-playwright artifacts

The pytest plugin exposes command-line controls for screenshots, video, traces, and output directory. Common policies retain artifacts only on failure or on first retry, depending on plugin options and team needs. Check the installed plugin's help output for exact supported values rather than copying an old CI command blindly.

Centralize the policy in CI configuration so local defaults stay lightweight. Keep output folders unique per job and upload them even when tests fail. The Playwright Python pytest fixtures guide explains where plugin fixtures and custom contexts meet.

Treat this decision as part of the test contract. Record what the test controls, what remains real, and which failure proves the requirement is broken. This prevents a helper from silently expanding into infrastructure that nobody owns. When the product changes, update the behavioral assertion first, then adjust the supporting abstraction. That sequence keeps the suite focused on user risk instead of implementation trivia.

7. Name, retain, and publish artifacts

Use test identity, browser, shard, retry, and timestamp or run ID in artifact paths. Sanitize node IDs for the filesystem. Preserve the original evidence from every attempt instead of overwriting failure.png. CI should publish an index or structured attachment that maps a failing test to its artifacts.

Retention should reflect value and sensitivity. Short failure-only retention is often sufficient for routine CI, while release investigations may require controlled longer retention. Document who can access recordings and how deletion works.

A useful review checklist for this area is: identify the observable requirement, choose the narrowest scope, make ownership explicit, and retain evidence when it fails. Keep setup deterministic and independent from test order. Name fixtures and helpers after product behavior so another engineer can understand the test without opening every implementation file. In CI, use the same browser and dependency versions that were validated locally, while keeping credentials outside source control.

8. Use screenshots for visual comparison correctly

A diagnostic screenshot is not automatically a visual regression assertion. Pixel comparison requires reviewed baselines, consistent browser builds, fonts, viewport, device scale, animation control, and environment. Playwright's screenshot assertions are first-class in the Node.js test runner, while Python teams typically integrate a dedicated comparison workflow or compare image files deliberately.

Do not invent a Python expect(page).to_have_screenshot() API. For Python, separate capture from the chosen comparison library and report diffs clearly. The Playwright Python visual testing guide covers baseline governance.

Treat this decision as part of the test contract. Record what the test controls, what remains real, and which failure proves the requirement is broken. This prevents a helper from silently expanding into infrastructure that nobody owns. When the product changes, update the behavioral assertion first, then adjust the supporting abstraction. That sequence keeps the suite focused on user risk instead of implementation trivia.

9. Troubleshoot blank, partial, or missing media

A blank image can indicate capture before content rendered, a cross-origin media limitation, a crashed page, or a page hidden by navigation. A partial full-page image may reflect virtualized content that renders only visible rows. Scroll intentionally or assert the required component rather than assuming full_page materializes an infinite list.

A missing video usually means recording was not enabled at context creation or the context was not closed. If video dimensions look unexpected, remember the recording is scaled to fit the configured size. Use the Playwright Python debugging guide to correlate media with traces.

A useful review checklist for this area is: identify the observable requirement, choose the narrowest scope, make ownership explicit, and retain evidence when it fails. Keep setup deterministic and independent from test order. Name fixtures and helpers after product behavior so another engineer can understand the test without opening every implementation file. In CI, use the same browser and dependency versions that were validated locally, while keeping credentials outside source control.

10. Create a safe CI evidence strategy

Record traces and screenshots on failure for most suites, then add video to flows where motion or navigation history has diagnostic value. Video increases storage and processing, so measure its utility. Use a small, predictable viewport and synthetic accounts.

Artifact capture should survive test exceptions through fixture teardown. Upload happens in an always-run CI step. The Playwright Python CI guide shows how evidence fits into reliable pipelines.

Treat this decision as part of the test contract. Record what the test controls, what remains real, and which failure proves the requirement is broken. This prevents a helper from silently expanding into infrastructure that nobody owns. When the product changes, update the behavioral assertion first, then adjust the supporting abstraction. That sequence keeps the suite focused on user risk instead of implementation trivia.

11. Implement Playwright Python screenshots and video

The example creates a context with video enabled, captures a masked full-page screenshot, then closes the context before saving the video. The try/finally block guarantees finalization even when an assertion fails. In a pytest suite, a fixture would own this lifecycle and decide whether to retain artifacts based on the test result.

Use pathlib paths and create directories before passing them to Playwright. Keep captures scoped to a scenario and avoid production data. The best artifact is one an engineer can connect to the failure in seconds.

A useful review checklist for this area is: identify the observable requirement, choose the narrowest scope, make ownership explicit, and retain evidence when it fails. Keep setup deterministic and independent from test order. Name fixtures and helpers after product behavior so another engineer can understand the test without opening every implementation file. In CI, use the same browser and dependency versions that were validated locally, while keeping credentials outside source control.

Runnable Python example

Install dependencies with pip install pytest pytest-playwright and browser binaries with playwright install. Adapt the example URL and locators to your application.

from pathlib import Path
from playwright.sync_api import sync_playwright, expect


def capture_checkout_evidence() -> None:
    artifacts = Path("test-results/checkout")
    artifacts.mkdir(parents=True, exist_ok=True)

    with sync_playwright() as playwright:
        browser = playwright.chromium.launch()
        context = browser.new_context(
            record_video_dir=artifacts / "raw-video",
            record_video_size={"width": 1280, "height": 720},
            viewport={"width": 1280, "height": 720},
        )
        page = context.new_page()
        video = page.video
        try:
            page.goto("https://example.test/checkout")
            expect(page.get_by_role("heading", name="Checkout")).to_be_visible()
            page.screenshot(
                path=artifacts / "checkout.png",
                full_page=True,
                mask=[page.get_by_test_id("customer-email")],
                animations="disabled",
            )
        finally:
            context.close()
            if video is not None:
                video.save_as(artifacts / "checkout.webm")
            browser.close()


if __name__ == "__main__":
    capture_checkout_evidence()

12. Production readiness checklist for Playwright Python screenshots and video

Define an artifact matrix rather than enabling every format by habit. For assertion failures, a trace and final screenshot may be enough. For navigation loops, disappearing dialogs, drag interactions, or animation defects, video adds sequence evidence. For visual regression, keep reviewed baselines and diffs separate from diagnostic media. Each artifact should answer a known investigation question.

Test the failure path of the capture system itself. Force an assertion failure, verify teardown closes the context, confirm video finalizes, and inspect the uploaded CI links. Repeat with multiple browsers, workers, shards, and retries to detect filename collisions. An artifact policy that works only on passing tests provides false confidence.

Perform a privacy review using the actual output. Search filenames, screenshots, videos, traces, and logs for emails, tokens, payment details, customer names, and internal URLs. Prefer synthetic identities and isolated test environments. Apply access controls and retention at the CI storage layer, because masking one element cannot erase sensitive frames captured earlier.

A production-ready evidence system uses predictable viewport and browser versions, preserves original failures, distinguishes attempts, and exposes artifact metadata beside the test result. It has storage budgets and deletion rules. Engineers know when to capture a locator instead of a full page and when to open a trace instead of watching a long video.

Standardize media readability as well as capture. Use a viewport large enough to show the relevant layout, keep zoom and device scale deliberate, and avoid filenames that require decoding an internal hash. A short metadata file can record test node ID, browser version, viewport, attempt, commit, and artifact paths. This makes evidence useful after the CI interface has expired or changed.

Video is particularly easy to overvalue. Watching a recording may show where the page stopped, but it rarely explains why. Teach investigators to begin with the assertion and trace, then use video to answer a sequence question. Trim scope by creating a fresh context for the behavior when a long setup would produce an unhelpful recording. Do not edit original evidence after a failure. If a clip is created for a defect report, retain the source under the same security policy.

For screenshots used in documentation, separate them from test failure artifacts. Documentation images may need stable seeded content and intentional composition, while failure captures must remain automatic and faithful. Mixing the two purposes encourages tests to hide dynamic state for prettier output. A clear boundary keeps diagnostic evidence honest and published images controlled.

Finally, run linting, collection, and a representative browser test in the same container image used by CI. Review failure output with someone who did not write the test. If that person can identify the broken requirement, relevant evidence, and resource owner quickly, the implementation is ready to scale. If not, improve naming and lifecycle boundaries before adding more cases.

Interview Questions and Answers

Q: How do you take a full-page screenshot in Playwright Python?

I call page.screenshot(path=..., full_page=True). I assert stable page state first and disable animations when consistency matters. For a single component I use locator.screenshot().

Q: When is a video file ready?

The recording is finalized when its BrowserContext closes. I keep the Video reference, close the context in teardown, then call save_as() or inspect its path. This lifecycle must survive test exceptions.

Q: What is the difference between screenshots and traces?

A screenshot is one rendered frame. A trace connects actions, DOM snapshots, console, and network information over time. I use screenshots for quick visual state and traces for causal debugging.

Q: How do you protect sensitive information in artifacts?

I use synthetic data, mask sensitive locators, restrict artifact access, and set retention. Masking one locator is not enough if data appears in URLs, logs, or video. Security starts with the test environment.

Q: Why might full-page screenshots miss list rows?

Virtualized lists render only a window of items even though the page can scroll. full_page captures rendered content, not hypothetical DOM nodes. I test pagination or scroll behavior explicitly and capture the relevant component.

Q: How do you avoid artifact filename collisions?

I include run, shard, worker, browser, node ID, and retry where relevant, or use framework-provided per-test directories. Every attempt keeps separate evidence. CI maps paths back to the test result.

Q: Does Playwright Python have to_have_screenshot()?

That matcher belongs to Playwright Test in Node.js, not the Python expect API. In Python I capture with screenshot() and use a chosen visual comparison workflow. I do not invent parity where the bindings differ.

Q: When would you enable video for every test?

Only when its diagnostic value justifies storage and runtime cost, such as a short critical-flow suite. Most teams benefit from failure or retry policies. I measure usefulness and keep retention bounded.

Common Mistakes

  • Reading a video path before closing the BrowserContext.
  • Treating a diagnostic screenshot as a visual regression assertion.
  • Capturing production secrets or customer data in CI artifacts.
  • Overwriting artifacts from different browsers, workers, shards, or retries.
  • Using fixed sleeps to make screenshots appear stable.
  • Expecting full_page capture to materialize every virtualized row.
  • Recording all media indefinitely without retention, access, or cost controls.

A mature review does more than reject these patterns. It asks what pressure created them, such as slow environments, weak test data APIs, missing accessibility semantics, or insufficient failure artifacts. Fix the enabling condition as well as the individual test. Keep exceptions documented, narrow, and measurable so a temporary workaround does not become the permanent architecture.

Conclusion

Playwright Python screenshots and video should make tests easier to understand, isolate, and diagnose. Start with the smallest representative workflow, use the real API shown here, and verify behavior through user-visible outcomes. Keep data and artifacts safe, measure CI results, and resist abstractions that hide lifecycle or intent.

Your next step is to implement one focused scenario, review its failure evidence with the team, and then standardize only the parts that proved reusable.

Interview Questions and Answers

How do you take a full-page screenshot in Playwright Python?

I call page.screenshot(path=..., full_page=True). I assert stable page state first and disable animations when consistency matters. For a single component I use locator.screenshot().

When is a video file ready?

The recording is finalized when its BrowserContext closes. I keep the Video reference, close the context in teardown, then call save_as() or inspect its path. This lifecycle must survive test exceptions.

What is the difference between screenshots and traces?

A screenshot is one rendered frame. A trace connects actions, DOM snapshots, console, and network information over time. I use screenshots for quick visual state and traces for causal debugging.

How do you protect sensitive information in artifacts?

I use synthetic data, mask sensitive locators, restrict artifact access, and set retention. Masking one locator is not enough if data appears in URLs, logs, or video. Security starts with the test environment.

Why might full-page screenshots miss list rows?

Virtualized lists render only a window of items even though the page can scroll. full_page captures rendered content, not hypothetical DOM nodes. I test pagination or scroll behavior explicitly and capture the relevant component.

How do you avoid artifact filename collisions?

I include run, shard, worker, browser, node ID, and retry where relevant, or use framework-provided per-test directories. Every attempt keeps separate evidence. CI maps paths back to the test result.

Does Playwright Python have to_have_screenshot()?

That matcher belongs to Playwright Test in Node.js, not the Python expect API. In Python I capture with screenshot() and use a chosen visual comparison workflow. I do not invent parity where the bindings differ.

When would you enable video for every test?

Only when its diagnostic value justifies storage and runtime cost, such as a short critical-flow suite. Most teams benefit from failure or retry policies. I measure usefulness and keep retention bounded.

Frequently Asked Questions

What is Playwright Python screenshots and video?

Use page.screenshot() or locator.screenshot() for deliberate still images. Enable video when creating the BrowserContext with record_video_dir, then close the context before reading or saving the video. In pytest-playwright, use CLI artifact options and retain evidence on failure while masking secrets.

Is Playwright Python screenshots and video suitable for CI?

Yes. Make browser versions, configuration, test data, and artifacts repeatable in CI. Start with a small representative workflow, measure reliability, and preserve evidence for failures.

What is the best first step for Playwright Python screenshots and video?

Build one focused test from the runnable example, then adapt it to a real risk in your application. Keep lifecycle ownership explicit and verify the user-visible outcome.

Should I use fixed sleep calls in Playwright Python tests?

No for normal synchronization. Use locators, web-first assertions, request or response expectations, or another observable application signal. A bounded delay is justified only when elapsed time itself is the behavior under test.

How should a team debug failures?

Keep the original Playwright error and collect a trace plus focused screenshots or logs. Reproduce with the same browser, data, and concurrency. Diagnose the first incorrect observable state instead of adding retries immediately.

How many scenarios should one UI test cover?

Usually one coherent behavior and its important outcome. Use data-driven tests only when failures remain independently diagnosable. Large journeys reduce scheduling flexibility and hide the first cause.

How do I keep the implementation maintainable?

Prefer plain typed helpers, clear fixture ownership, semantic locators, and small domain examples. Review abstractions when product behavior changes. Delete helpers that only rename the underlying API.

Related Guides