# Website Screenshot & PDF (`cyber1nj3ct0r/website-screenshot`) Actor

Take screenshots of web pages, or save them as PDF. Full page or visible area, desktop, tablet or phone size, PNG, JPEG or WebP. Hide elements by CSS selector, scroll first so lazy images load. One file and one result row per page.

- **URL**: https://apify.com/cyber1nj3ct0r/website-screenshot.md
- **Developed by:** [Sanira Botheju](https://apify.com/cyber1nj3ct0r) (community)
- **Categories:** Developer tools, Automation, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 screenshots

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Website Screenshot & PDF do?

Website Screenshot & PDF opens each web page you list in a real browser (headless Chrome) and saves it as an **image (PNG, JPEG or WebP) or a PDF**. You get one file and one result row per page, with a link to the file, the HTTP status of the page, its title, and the size of the file.

- Full page from top to bottom, or only the part you see without scrolling
- Desktop, tablet or phone screen, with your own width and height for desktop, and a pixel density of 1 to 3
- Scrolls down the page once before capturing, so images that load only when you reach them are in the picture
- Hides the elements you name by CSS selector, for example a banner, a chat bubble or a pop-up
- Waits for the page to load, for the network to go quiet, or for a time you set
- A page that is slow, missing or blocked becomes a result with a clear error code instead of stopping the run

### What data do you get?

| Field | Example |
|---|---|
| Page (`url`) | `https://crawlee.dev` |
| Final address (`finalUrl`) | `https://crawlee.dev/` |
| HTTP status (`httpStatus`) | `200` |
| Title (`title`) | `Crawlee · Build reliable crawlers. Fast.` |
| File link (`fileUrl`) and name (`fileKey`) | `002-crawlee.dev.png` |
| Format, width and height | `png`, `1280` x `2874` pixels |
| Size of the file (`bytes`) | `321952` |
| Time (`timeMs`) | `6269` |
| Warnings and error | `[]`, `null` |

The files are saved in the run's key-value store under readable names such as `001-apify.com.png`, in the order of your list.

### How to take a screenshot of a web page

1. Under **Web addresses**, add the pages, paste a list with **Bulk edit**, or link a text file that lists them.
2. Choose the **File format** and whether to capture the whole page.
3. Press **Start**.
4. Open the **Captured pages** table, click the link in the **File** column, or download all files from the key-value store.

### How much does it cost to take screenshots?

You pay per page: **$3.50 per 1,000 screenshots**. Apify subscribers on the Silver plan pay $3.00 and on the Gold plan $2.50 per 1,000. Each run also has a start fee of $0.00005 per GB of memory ($0.0001 at the default 2 GB). The price does not depend on how tall the page is or how long it takes.

| Pages | Cost |
|---|---|
| 10 | $0.035 |
| 100 | $0.35 |
| 1,000 | $3.50 |
| 10,000 | $35.00 |

Every page in your list counts as one result, including a page that could not be captured: the result then holds the error. Duplicate addresses in your list are captured, and paid, once. Apify's free plan includes $5 of credit each month, which covers about 1,400 screenshots. Set a maximum cost for the run in Apify Console and the tool stops there and keeps what it has captured.

### Input

Only **Web addresses** is required. The other settings:

| Field | What it does |
|---|---|
| `format` | `png` (default), `jpeg`, `webp` or `pdf` |
| `fullPage` | Whole page (default) or only the visible area; PDFs always hold the whole page |
| `device` | `desktop` (uses your width and height, default 1280 x 800), `tablet` (820 x 1180) or `mobile` (390 x 844) |
| `deviceScaleFactor` | Pixel density 1 to 3; empty uses the screen's own (1 for desktop, 2 for tablet and phone) |
| `waitUntil` | `load` (default), `domcontentloaded` (faster) or `networkidle2` (waits until the page stops fetching data) |
| `delayMs` | Extra wait in milliseconds before capturing |
| `scrollToLoad` | Scroll through the page first so lazy images load (default on) |
| `blockTrackers` | Skip well-known analytics and advertising hosts (default on, see the FAQ) |
| `hideSelectors` | CSS selectors of elements to hide |
| `quality` | JPEG and WebP quality, 1 to 100 (default 80) |
| `pdfFormat`, `printBackground` | PDF paper size (`A4` or `Letter`) and whether backgrounds are printed |
| `maxHeight` | Cuts a full-page image at this height in pixels (default 16,000) |
| `timeoutSecs` | How long to wait for a page to load (default 45) |
| `concurrency` | Pages at the same time, 1 to 5 (default 2) |

```json
{
    "urls": [{ "url": "https://crawlee.dev" }],
    "format": "jpeg",
    "fullPage": true,
    "device": "mobile",
    "hideSelectors": ["#cookie-banner", ".chat-widget"],
    "quality": 85
}
```

### Output example

One record per page:

```json
{
    "url": "https://crawlee.dev",
    "position": 1,
    "finalUrl": "https://crawlee.dev/",
    "httpStatus": 200,
    "title": "Crawlee · Build reliable crawlers. Fast.",
    "fileKey": "001-crawlee.dev.png",
    "fileUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/001-crawlee.dev.png",
    "format": "png",
    "width": 1280,
    "height": 2874,
    "pages": null,
    "bytes": 321952,
    "truncated": false,
    "skippedTrackers": 2,
    "timeMs": 3105,
    "capturedAt": "2026-10-16T08:30:00.000Z",
    "warnings": [],
    "error": null
}
```

A page that could not be captured has `error` with a code such as `DNS_NOT_FOUND`, `CONNECTION_REFUSED`, `TIMEOUT`, `TLS_CERTIFICATE_EXPIRED`, `TOO_MANY_REDIRECTS`, `NOT_A_WEB_PAGE` (a file download) or `BLOCKED_ADDRESS`, and no file. A page that answers with an error status, such as 404 or 500, **is** captured: the screenshot shows what a visitor sees, `httpStatus` holds the status and `warnings` says so. For a PDF, `pages` holds the number of pages and `width` and `height` are empty.

### What can you use it for?

- **Visual archives**: keep a picture of a page as it was on a given day, for records or evidence
- **Monitoring layouts**: put the tool on a schedule in Apify Console and compare the pictures of your own pages over time
- **Thumbnails and previews** of pages in a directory, a report or a dashboard
- **Saving pages as PDF**: articles, invoices, receipts and documentation
- **Checking how a page looks** on a desktop, a tablet and a phone before and after a release

### Use it from the API

```bash
curl -X POST "https://api.apify.com/v2/acts/cyber1nj3ct0r~website-screenshot/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": [{"url": "https://apify.com"}], "format": "png", "fullPage": false}'
```

The same works from Python, JavaScript, Make, Zapier and n8n through Apify's integrations. The result rows hold `fileUrl`; the files can also be fetched from the run's key-value store by `fileKey`.

### FAQ

#### Does it capture the whole page?

With **Capture the whole page** on, the image runs from the top of the page to its end, at the width of the screen, up to **Maximum page height** (16,000 pixels by default) and about 50 million pixels in total. A taller page is cut off and the result says `truncated: true`. A web app that scrolls inside a fixed-height area may come out only as tall as the window, because the page itself does not scroll. PDFs hold up to 200 pages.

#### A site blocks the tool or shows a robot check. What can I do?

The tool opens pages the way a visitor's browser does, says who it is in its User-Agent (Chrome's own name plus the tool's name and address), and does not try to get round blocks: no stealth tricks, no solving of CAPTCHAs, no proxies. If a site refuses it, you get the picture of what the site showed, often with `httpStatus` 403, or an error. Only capture pages you are allowed to open, and if the page is yours, allow the tool in your firewall.

#### What about cookie banners?

The tool never clicks, accepts or declines anything on a page. To keep a banner out of the picture, give its CSS selector under **Hide these elements**. With **Skip ads and trackers** on, some banners and widgets may not appear at all, because tag managers add them; that is a side effect, not something the tool aims at.

#### What does "Skip ads and trackers" do, and when should I turn it off?

It stops requests to well-known analytics, tag-manager and advertising hosts, such as Google Analytics, Google Tag Manager, Segment, Facebook and LinkedIn pixels and ad networks. They draw little a screenshot needs and on many sites they use more processing than the rest of the page, so pages capture faster. The page can look a little different: ad slots stay empty, and in one test a star counter that a tag manager adds to a documentation site's home page was missing. Turn it off to load the page exactly as a visitor's browser does. The list is short and written by hand; it does not catch every tracker.

#### Why does the picture look different from my own browser?

The browser runs without a screen on a server: it is not signed in, it has no cookies or saved settings, it may show the light colour scheme, and it has a basic set of fonts. A page that picks its layout by User-Agent instead of by screen width shows its desktop version even with the phone or tablet screen, because the tool does not pretend to be a phone browser. Videos are captured as a still image.

#### How do I capture pages behind a login?

You cannot: the tool opens public pages and has no way to log in or send cookies.

#### Does it follow links or crawl a site?

No. Only the addresses you list are opened, once each, with whatever each page loads to display itself.

#### How much memory does it need?

The default of 2 GB is meant for 2 to 5 pages at a time. In tests on a Windows PC with large pages, 2 pages at a time peaked at about 0.8 to 1.3 GB and 5 pages at about 1.1 to 1.8 GB. Very tall pages, a high pixel density or a PDF of a long page need more. If pages come back with the error `BROWSER_CRASHED`, give the run more memory or lower **Pages at the same time**.

#### Is it allowed to take screenshots of web pages?

The tool opens each page once, like a visitor. You are responsible for capturing only pages you are allowed to, and for what you do with the pictures. It does not open private network addresses, such as `localhost` or `192.168.x.x`; those pages get the error `BLOCKED_ADDRESS`.

#### Something does not work

Open an issue on the **Issues** tab with the address of the page and your settings. Every report is read and answered.

# Actor input Schema

## `urls` (type: `array`):

The pages to capture, for example <code>https://www.example.com/pricing</code>. Add them one by one, paste many at once with <b>Bulk edit</b>, or link a text file that lists them. Only these pages are opened (plus what they load to display themselves); no links are followed. Duplicates are captured once.

## `format` (type: `string`):

<b>PNG</b> is lossless and best for text and screens. <b>JPEG</b> and <b>WebP</b> make smaller files (set the quality under More options). <b>PDF</b> prints the page onto paper-sized pages, like Print to PDF in a browser, and keeps the text selectable.

## `fullPage` (type: `boolean`):

On: the image shows the page from top to bottom, up to the maximum height set under More options. Off: only the part you see without scrolling. Has no effect on PDF, which always holds the whole page.

## `device` (type: `string`):

<b>Desktop</b> uses the width and height set below. <b>Tablet</b> (820 x 1180, double pixel density) and <b>Phone</b> (390 x 844, double pixel density) use their own sizes and touch-screen settings, so responsive pages show their tablet or phone layout. The tool does not pose as a tablet or phone in its User-Agent, so a site that picks its layout from the User-Agent instead of the screen width still shows its desktop version.

## `viewportWidth` (type: `integer`):

Width of the browser window in pixels. Used when Screen is Desktop. A full-page image has this width.

## `viewportHeight` (type: `integer`):

Height of the browser window in pixels. Used when Screen is Desktop. It sets the height of an image that does not capture the whole page, and what <code>100vh</code> means on the page.

## `waitUntil` (type: `string`):

When the page counts as loaded. <b>Page loaded</b> waits for the page and its images. <b>DOM ready</b> is faster but may catch images half loaded. <b>Network almost idle</b> also waits until the page has stopped fetching data (at most two requests in flight for half a second); it is the most complete for pages that build themselves with JavaScript, but sites that keep polling a server may need the whole page timeout.

## `delayMs` (type: `integer`):

Extra time to wait after the page has loaded, for animations, fade-ins and late scripts to finish. 0 means no extra wait.

## `scrollToLoad` (type: `boolean`):

Many pages load their images only when you scroll to them. On: the tool scrolls down the page once, then back to the top, before it captures (full-page images and PDFs). Turn it off to capture faster, or for pages that react badly to scrolling.

## `blockTrackers` (type: `boolean`):

On: requests to well-known analytics, tag-manager and advertising hosts (Google Analytics, Google Tag Manager, Segment, Facebook and LinkedIn pixels, ad networks and similar) are not made. These scripts draw little a screenshot needs and on many sites they use more processing than the rest of the page, so pages load and capture faster. The page can look slightly different: ad slots stay empty, and a widget that a tag manager would have added may be missing. Turn it off to load the page exactly as a visitor's browser does. The result's <code>skippedTrackers</code> says how many requests were skipped.

## `hideSelectors` (type: `array`):

CSS selectors of elements to hide before capturing, for example <code>#cookie-banner</code> or <code>.chat-widget</code>. The tool never clicks or accepts anything on a page by itself. A selector that matches nothing, or is not valid, is reported in the result's <code>warnings</code>.

## `quality` (type: `integer`):

From 1 (smallest file) to 100 (best picture). Used for JPEG and WebP; PNG is always lossless.

## `deviceScaleFactor` (type: `integer`):

How many image pixels make up one screen pixel: 1 is a normal screen, 2 and 3 are sharp ("retina") screens and give images that are 2 or 3 times as wide and tall. Leave empty to use the setting of the chosen screen (1 for Desktop, 2 for Tablet and Phone). Very large images are shortened, see Maximum page height.

## `pdfFormat` (type: `string`):

Paper size of the PDF pages.

## `printBackground` (type: `boolean`):

On: background colours and images are part of the PDF, as on screen. Off: they are left out, as in a browser's print dialog by default.

## `maxHeight` (type: `integer`):

A full-page image is cut off at this height, in screen pixels, so that endless pages cannot make huge files. The result says <code>truncated: true</code> when this happened. Images are also limited to about 50 million pixels in total, which matters mainly with a high pixel density.

## `timeoutSecs` (type: `integer`):

How long to wait for a page to load. If the page itself has arrived but is still loading some extra resource when the time is up, it is captured as it is and the result carries a warning. If nothing arrives, the result carries the error TIMEOUT.

## `concurrency` (type: `integer`):

How many pages are captured in parallel. Higher is faster for long lists and needs more memory: the default of 2 GB is meant for normal pages at up to 5 at a time; very tall pages, a high pixel density or long PDFs need more, or fewer pages at the same time. At most two pages of the same website are open at once.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://crawlee.dev"
    }
  ],
  "format": "png",
  "fullPage": true,
  "device": "desktop",
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "waitUntil": "load",
  "delayMs": 0,
  "scrollToLoad": true,
  "blockTrackers": true,
  "quality": 80,
  "pdfFormat": "A4",
  "printBackground": true,
  "maxHeight": 16000,
  "timeoutSecs": 45,
  "concurrency": 2
}
```

# Actor output Schema

## `pages` (type: `string`):

One record per page with the link to its file, the HTTP status, the page title, the size of the file and any error.

## `files` (type: `string`):

The screenshots and PDFs themselves, in the run's key-value store.

## `summary` (type: `string`):

Counts for the run: pages given, captured and failed, and the total size of the files.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        {
            "url": "https://apify.com"
        },
        {
            "url": "https://crawlee.dev"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("cyber1nj3ct0r/website-screenshot").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "urls": [
        { "url": "https://apify.com" },
        { "url": "https://crawlee.dev" },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("cyber1nj3ct0r/website-screenshot").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://crawlee.dev"
    }
  ]
}' |
apify call cyber1nj3ct0r/website-screenshot --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cyber1nj3ct0r/website-screenshot"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hC15mBfQbm7C8YurT/builds/p3szyVBQvkfLL2CZ9/openapi.json
