> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zenrows.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Page Screenshot

> Capture a screenshot of any page (above the fold, full page, or a specific element) using the `screenshot=true` parameter.

The `screenshot=true` parameter tells ZenRows to capture a screenshot of the target page and return it as a PNG image. You get a pixel-accurate visual snapshot of the page as it appears in a browser, including styles, fonts, and JavaScript-rendered content.

This is useful for visual monitoring, page archiving, UI testing, or any workflow that needs a rendered image of a page rather than its raw content.

<Warning>
  Screenshot parameters cannot be combined with the `outputs` parameter. Use one or the other depending on whether you need a visual capture or targeted data extraction.
</Warning>

## How it works

Screenshot generation always requires a full browser render. You must include `js_render=true` in every screenshot request. ZenRows renders the page in a headless browser and captures the result as an image before returning it as binary content.

By default, the screenshot captures only the above-the-fold visible area of the page. You can expand this to the full page or narrow it to a specific element using the additional parameters described below.

<Tip>Find more details on our [JS Rendering Documentation](/universal-scraper-api/features/js-rendering).</Tip>

## Basic usage

Add `screenshot=true` and `js_render=true` to your request parameters:

<CodeGroup>
  ```python Python theme={null}
  import requests

  url = "https://www.scrapingcourse.com/ecommerce/"
  apikey = "YOUR_ZENROWS_API_KEY"

  params = {
      "url": url,
      "apikey": apikey,
      "js_render": "true",
      "screenshot": "true",
  }

  response = requests.get("https://api.zenrows.com/v1/", params=params)

  with open("screenshot.png", "wb") as file:
      file.write(response.content)

  print("Screenshot saved to screenshot.png")
  ```

  ```javascript Node.js theme={null}
  import axios from "axios";
  import fs from "fs";

  const url = "https://www.scrapingcourse.com/ecommerce/";
  const apikey = "YOUR_ZENROWS_API_KEY";

  const response = await axios.get("https://api.zenrows.com/v1/", {
  params: {
      url,
      apikey,
      js_render: "true",
      screenshot: "true",
  },
  responseType: "stream",
  });

  const file = fs.createWriteStream("screenshot.png");
  response.data.pipe(file);
  ```

  ```java Java theme={null}
  import java.io.File;
  import org.apache.hc.client5.http.fluent.Request;

  public class APIRequest {
      public static void main(final String... args) throws Exception {
          File file = new File("screenshot.png");
          String apiUrl = "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&js_render=true&screenshot=true";
          Request.get(apiUrl).execute().saveContent(file);
      }
  }
  ```

  ```php PHP theme={null}
  <?php
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&js_render=true&screenshot=true");
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  $response = curl_exec($ch);
  file_put_contents("screenshot.png", $response);
  curl_close($ch);
  ?>
  ```

  ```go Go theme={null}
  package main

  import (
      "io"
      "log"
      "net/http"
      "os"
  )

  func main() {
      client := &http.Client{}
      req, err := http.NewRequest("GET", "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&js_render=true&screenshot=true", nil)
      if err != nil {
          log.Fatalln(err)
      }

      resp, err := client.Do(req)
      if err != nil {
          log.Fatalln(err)
      }
      defer resp.Body.Close()

      img, _ := os.Create("screenshot.png")
      defer img.Close()

      io.Copy(img, resp.Body)
  }
  ```

  ```ruby Ruby theme={null}
  require "faraday"

  url = URI.parse("https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&js_render=true&screenshot=true")
  conn = Faraday.new()
  conn.options.timeout = 180
  res = conn.get(url, nil, nil)
  File.open("screenshot.png", "wb") { |file| file.write(res.body) }
  ```

  ```bash cURL theme={null}
  curl "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.scrapingcourse.com%2Fecommerce%2F&js_render=true&screenshot=true" > screenshot.png
  ```
</CodeGroup>

## Screenshot options

### Capture mode

Three capture modes are available depending on how much of the page you need:

| Parameter                            | Description                                                           |
| ------------------------------------ | --------------------------------------------------------------------- |
| `screenshot=true`                    | Captures the above-the-fold visible area only. Default behavior.      |
| `screenshot_fullpage=true`           | Captures the entire page by scrolling and stitching the full content. |
| `screenshot_selector=<CSS Selector>` | Captures only the element matched by the given CSS selector.          |

<Warning>
  `screenshot_fullpage` and `screenshot_selector` are mutually exclusive. Use one or the other in a single request.
</Warning>

### Image format and quality

By default, screenshots are returned as PNG. You can switch to JPEG for smaller file sizes using the following parameters:

| Parameter            | Values        | Description                                                                    |
| -------------------- | ------------- | ------------------------------------------------------------------------------ |
| `screenshot_format`  | `png`, `jpeg` | Sets the output format. Defaults to `png`.                                     |
| `screenshot_quality` | `1` to `100`  | Sets the JPEG compression quality. Only applies when `screenshot_format=jpeg`. |

<Tip>Full-page screenshots can exceed 10MB as PNG. If you are hitting size limits, switch to `screenshot_format=jpeg` and tune `screenshot_quality` to find the right balance between file size and visual fidelity.</Tip>

### Combining with other parameters

Screenshot requests are compatible with `wait`, `wait_for`, and `js_instructions`, which lets you control exactly when the capture happens. Use these when the page loads content after the initial render or requires user interaction before the target content is visible.

<Tip>Find more details on our [Wait Documentation](/universal-scraper-api/features/wait), [Wait For Selector Documentation](/universal-scraper-api/features/wait-for), and [JS Instructions Documentation](/universal-scraper-api/features/js-instructions).</Tip>

When using `json_response=true`, the screenshot data is returned base64-encoded inside a JSON object instead of as raw binary, which makes it easier to handle in API workflows that expect structured responses.

## When to use page screenshots

Screenshots are the right choice when you need a visual record of a page rather than its text or data. They work well for:

* **Visual monitoring**: detect layout changes, broken pages, or UI regressions across time.
* **Page archiving**: preserve a timestamped visual snapshot of how a page looked at a specific moment.
* **Element capture**: isolate and capture specific UI components, charts, or widgets using `screenshot_selector`.
* **QA and testing**: validate that pages render correctly across different URLs or conditions.
* **Reporting and sharing**: generate visual page previews for dashboards, reports, or stakeholder communication.

<Note>If you need to extract text or structured data from the page rather than a visual snapshot, use `response_type=markdown`, `response_type=plaintext`, or the `outputs` parameter instead.</Note>

## Best practices

**Always include `js_render=true`:** <br />
Screenshot generation requires a full browser render. Requests without `js_render=true` will not return a valid image.

**Use `wait` or `wait_for` for pages with delayed content:** <br />
If the page loads content after the initial render, use `wait` (milliseconds) or `wait_for` (CSS selector) to ensure everything is visible before the screenshot is captured.

<Tip>Find more details on our [Wait Documentation](/universal-scraper-api/features/wait) or [Wait For Selector Documentation](/universal-scraper-api/features/wait-for).</Tip>

**Switch to JPEG for large full-page screenshots:** <br />
Full-page screenshots of long pages can exceed 10MB as PNG, which causes errors. Use `screenshot_format=jpeg` with `screenshot_quality` set between `60` and `85` for a good balance of clarity and file size.

**Save as binary, not text:** <br />
Screenshot files are binary. Always write the response body in binary mode (for example, `"wb"` mode in Python and Ruby, `Buffer` in Node.js, `FileOutputStream` in Java). Writing binary content as text will corrupt the image file.

**Credits are charged on successful responses:** <br />
A screenshot request is charged when the API returns a `200` status code, regardless of whether the image contains the content you expected. Because `js_render=true` is required, the JS rendering credit cost also applies. Test on a small set of URLs before running at scale.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The screenshot is blank or shows a loading state">
    The page likely loads content after the initial render. Add `wait` (in milliseconds) to give the page time to finish loading, or use `wait_for` with a CSS selector that is only present once the main content is visible.
  </Accordion>

  <Accordion title="The screenshot file is corrupted or cannot be opened">
    You are likely writing the response as text instead of binary. Always use binary write mode in your language of choice (`"wb"` in Python and Ruby, `Buffer` in Node.js, `FileOutputStream` in Java) and write the raw response body. Image files are binary and writing them as text will produce a corrupt file.
  </Accordion>

  <Accordion title="The full-page screenshot is too large or returns an error">
    Full-page screenshots of long pages can exceed 10MB as PNG. Switch to `screenshot_format=jpeg` and set `screenshot_quality` to a value between `60` and `85` to reduce the file size significantly while keeping the image readable.
  </Accordion>

  <Accordion title="screenshot_selector is not capturing the right element">
    Make sure the CSS selector you are passing targets a single, visible element. If the element is loaded dynamically, use `wait_for` with the same selector to ensure it is present in the DOM before the screenshot is taken. Avoid auto-generated or highly dynamic class names, as these can change between requests.
  </Accordion>

  <Accordion title="screenshot_fullpage and screenshot_selector are conflicting">
    These two parameters are mutually exclusive. Use `screenshot_fullpage=true` when you want the entire page, and `screenshot_selector` when you want a specific element. You cannot use both in the same request.
  </Accordion>
</AccordionGroup>

## Pricing

Screenshot requests are included at **no additional cost** beyond the standard JS rendering rate. Because screenshot generation requires `js_render=true`, all screenshot requests are billed at the JS rendering credit rate. You only pay extra for Premium Proxy when used.

<Tip>
  You can monitor your ZenRows usage in multiple ways to stay informed about your account activity and prevent unexpected overages.

  **Dashboard monitoring**: View real-time usage statistics, remaining requests, success rates, and request history on your [Analytics Page](https://app.zenrows.com/analytics/scraper-api). You can also set up usage alerts in your [notification settings](https://app.zenrows.com/account/notifications) to receive notifications when you approach your limits.

  **Programmatic monitoring**: For automated monitoring in your applications, call the `/v1/subscriptions/self/details` endpoint with your API key in the `X-API-Key` header. This returns real-time usage data that you can integrate into your monitoring systems. [Learn more about the usage endpoint](https://docs.zenrows.com/universal-scraper-api/features/other#plan-usage).

  **Response header monitoring**: Track your concurrency usage through response headers included with each request:

  * `Concurrency-Limit`: Your maximum concurrent requests
  * `Concurrency-Remaining`: Available concurrent request slots
  * `X-Request-Cost`: Cost of the current request
</Tip>

## FAQ (Frequently Asked Questions)

<Accordion title="Is js_render=true required for screenshots?">
  Yes. Screenshot generation requires a full browser render. You must include `js_render=true` in every screenshot request. Requests without it will not return a valid image.
</Accordion>

<Accordion title="Do screenshots cost more credits?">
  Screenshot requests are billed at the JS rendering credit rate because `js_render=true` is required. The screenshot parameters themselves do not add an extra cost beyond that.
</Accordion>

<Accordion title="Can I capture a screenshot of a specific element on the page?">
  Yes. Use `screenshot_selector=<CSS Selector>` to capture only the element matched by the selector. Note that `screenshot_selector` and `screenshot_fullpage` are mutually exclusive and cannot be used together.
</Accordion>

<Accordion title="What image formats are supported?">
  PNG and JPEG are supported via the `screenshot_format` parameter. PNG is the default and is best for high-fidelity captures. JPEG offers smaller file sizes and is recommended for full-page screenshots or high-volume pipelines where storage and bandwidth matter.
</Accordion>

<Accordion title="Can I use screenshots with the Scraping Browser?">
  No, the `screenshot` parameters are features of the Universal Scraper API. In Scraping Browser (CDP/Playwright) sessions, you can capture screenshots directly using Playwright's built-in `page.screenshot()` method.
</Accordion>

<Accordion title="Can I get the screenshot as base64 instead of binary?">
  Yes. Add `json_response=true` to your request and the screenshot will be returned base64-encoded inside a JSON object. This is useful for workflows that expect structured API responses rather than raw binary streams.
</Accordion>
