# How to Take Screenshots of Web Pages with zendriver: A Complete Guide

> Learn how to take screenshots of web pages using zendriver. Capture full pages or specific elements with simple, powerful commands for your automation needs.

- Repository: [CDP Driver/zendriver](https://github.com/cdpdriver/zendriver)
- Tags: how-to-guide
- Published: 2026-02-27

---

**Use `Tab.screenshot_b64()` or `Tab.save_screenshot()` for full-page captures, and `Element.screenshot_b64()` or `Element.save_screenshot()` for specific DOM elements in the zendriver library.**

The `zendriver` library provides asynchronous Python APIs for controlling Chrome through the Chrome DevTools Protocol (CDP), including robust screenshot capabilities for both entire web pages and individual elements. Whether you need to capture full-page renders for visual regression testing or isolate specific UI components, zendriver abstracts the underlying CDP complexity into simple methods on `Tab` and `Element` objects. This guide covers the implementation details, configuration options, and source code structure you need to take screenshots of web pages effectively.

## Full-Page and Viewport Screenshots

The `Tab` class in [`zendriver/core/tab.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/core/tab.py) exposes two primary methods for capturing page-level screenshots. According to the source code at lines 1313–1350, both methods automatically wait for the page to settle before invoking the CDP command to ensure stable captures.

### Capturing Base-64 Data

Use `screenshot_b64()` when you need the image data as a Base-64 encoded string for further processing or API uploads:

```python
async def get_page_image(tab):
    # Returns a Base-64 string of the full page

    b64_data = await tab.screenshot_b64(format="png", full_page=True)
    return b64_data

```

The `format` parameter accepts `"jpeg"` (default) or `"png"`, while `full_page` determines whether to capture the entire scrollable document (`True`) or only the current viewport (`False`).

### Saving to Disk

Use `save_screenshot()` to write the image directly to the filesystem. This method handles Base-64 decoding internally using `base64.b64decode` and automatically generates a filename if omitted:

```python
async def save_page_image(tab):
    saved_path = await tab.save_screenshot(
        "homepage.png", 
        format="png", 
        full_page=True
    )
    print(f"Screenshot saved to: {saved_path}")

```

If the page isn't ready, these methods raise a `ProtocolException` as implemented in the error handling logic at lines 1329–1345 of [`zendriver/core/tab.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/core/tab.py).

## Element-Level Screenshots

For capturing specific DOM elements, the `Element` class in [`zendriver/core/element.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/core/element.py) (lines 867–904) provides analogous methods that clip the screenshot to the element's bounding box.

### Isolating Specific Components

After locating an element using `query_selector()`, you can capture it independently of the rest of the page:

```python
async def capture_header(tab):
    header = await tab.query_selector("header#main")
    if header:
        # Save with 2x resolution for high-DPI displays

        await header.save_screenshot("header.jpg", format="jpeg", scale=2)

```

The `scale` parameter multiplies the captured dimensions, allowing you to generate higher resolution images (e.g., `scale=2` captures at double the element's size). Under the hood, the method calculates the viewport rectangle using `pos.to_viewport(scale)` and passes it as the `clip` parameter to the CDP command.

### Error Handling

If the target element is hidden or lacks geometry (zero width/height), `Element.screenshot_b64()` raises a `RuntimeError` according to the validation logic at lines 867–888 of [`zendriver/core/element.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/core/element.py).

## CDP Implementation Details

Both screenshot APIs delegate to the Chrome DevTools Protocol command `Page.captureScreenshot`, defined in [`zendriver/cdp/page.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/cdp/page.py) at lines 2259–2274. The `Tab` implementation calls `cdp.page.capture_screenshot(format_, capture_beyond_viewport=full_page)` directly, while the `Element` implementation constructs a clip rectangle from the element's position data before making the same CDP call.

The actual image encoding and file I/O occur in the high-level methods:
- `Tab.save_screenshot()` decodes the CDP response and writes binary PNG/JPEG data
- `Element.save_screenshot()` performs the same decoding but applies the calculated clip region to isolate the element

## Complete Working Example

This standalone script demonstrates the full workflow from browser initialization to capturing both full-page and element-specific screenshots:

```python
import asyncio
from zendriver import Browser, Tab

async def main():
    async with Browser(headless=True) as browser:
        tab: Tab = await browser.new_tab("https://example.com")
        
        # Wait for page load to ensure elements are rendered

        await tab.wait_for_load()
        
        # Capture full-page screenshot

        await tab.save_screenshot("full_page.png", full_page=True)
        
        # Capture specific element

        logo = await tab.query_selector("img.logo")
        if logo:
            await logo.save_screenshot("logo_element.png", scale=2)

if __name__ == "__main__":
    asyncio.run(main())

```

The script follows best practices by awaiting `tab.wait_for_load()` before screenshotting to ensure the DOM is fully rendered and stable.

## Summary

- **Full-page captures**: Use `Tab.screenshot_b64()` for Base-64 data or `Tab.save_screenshot()` for file output; both support `full_page=True` to capture beyond the viewport.
- **Element isolation**: Use `Element.screenshot_b64()` or `Element.save_screenshot()` with optional `scale` parameter for high-resolution element captures.
- **Core files**: Implementation resides in [`zendriver/core/tab.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/core/tab.py) (page-level) and [`zendriver/core/element.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/core/element.py) (element-level), with the underlying CDP command defined in [`zendriver/cdp/page.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/cdp/page.py).
- **Error handling**: Expect `ProtocolException` if the page isn't ready, and `RuntimeError` if attempting to screenshot hidden elements.

## Frequently Asked Questions

### What image formats does zendriver support for screenshots?

zendriver supports **JPEG** (default) and **PNG** formats via the `format` parameter in both `Tab` and `Element` screenshot methods. JPEG offers smaller file sizes for photographs, while PNG preserves transparency and sharp edges for UI elements.

### How do I capture a full-page screenshot instead of just the viewport?

Pass `full_page=True` to `Tab.screenshot_b64()` or `Tab.save_screenshot()`. This sets `capture_beyond_viewport=True` in the underlying CDP `Page.captureScreenshot` command, instructing Chrome to capture the entire scrollable document rather than only the visible viewport.

### Can I take screenshots of hidden elements?

No. If an element has no visible geometry (zero width or height) or is hidden via CSS, `Element.screenshot_b64()` raises a `RuntimeError` according to the validation in [`zendriver/core/element.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/core/element.py) lines 867–888. You must ensure the element is visible and rendered before attempting capture.

### Where are the screenshot methods implemented in the source code?

The `Tab` screenshot methods are implemented in [`zendriver/core/tab.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/core/tab.py) at lines 1313–1350, while `Element` screenshot methods live in [`zendriver/core/element.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/core/element.py) at lines 867–904. Both delegate to the CDP command defined in [`zendriver/cdp/page.py`](https://github.com/cdpdriver/zendriver/blob/main/zendriver/cdp/page.py) at lines 2259–2274.