# Bulk Website Screenshot & PDF Generator (`datascraperes/website-screenshot-pdf`) Actor

Capture full-page website screenshots or PDFs from up to 1,000 public URLs. Normalize URLs, wait for dynamic content, hide popups, and pay $1 per 1,000 processed URLs.

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

## Pricing

$1.00 / 1,000 processed urls

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

Capture full-page website screenshots or printable PDFs from public URLs in bulk. Enter one or up to 1,000 URLs, choose the output format, and receive **one result row with a download link for every processed URL**.

### What this Actor does

This Actor opens public web pages, waits for the selected page state, and creates either a full-page PNG screenshot or an A4 PDF. It cleans common URL formatting mistakes, removes equivalent duplicates, preserves redirects and query strings, and records the result for each URL in the default Dataset.

You can wait for dynamic content, scroll pages to trigger lazy-loaded sections, hide page elements such as cookie banners or popups with CSS selectors, and protect a batch with configurable file-size and page-height limits.

### Use cases

- Monitor website changes with repeatable visual captures.
- Review landing pages, layouts, and responsive designs.
- Create SEO, content, compliance, or client-report evidence.
- Archive public articles, documentation, and reports as images or PDFs.
- Collect visual proof for website issues and content approvals.
- Generate previews for large lists of public web pages.

### How to use

1. Open the Actor in Apify Console.
2. Enter one or more public website URLs in the **URLs** field.
3. Select PNG or PDF and adjust the optional capture settings if needed.
4. Click **Start** and open the Dataset when the run finishes.

For the quickest test, use the prefilled `https://example.com/` URL and the default PNG settings.

### Input

`urls` is required and accepts one to 1,000 URL strings. The Actor accepts `http://`, `https://`, URLs without a scheme, and protocol-relative URLs. Spaces are trimmed, missing `https://` is added, hostnames are normalized, unsafe spaces are encoded, and equivalent duplicates are processed only once.

The default output is a PNG screenshot. Set `format` to `pdf` for an A4 document. Dynamic pages can use `waitUntil: "networkidle"`, an additional `delay`, or `scrollToBottom: true`. Use `selectorsToHide` for comma-separated CSS selectors such as `.cookie-banner, #consent-modal`.

The default file-size limit is 20 MiB and the default rendered page-height limit is 25,000 pixels. You can configure `maxArtifactSizeMb` from 1 to 50 MiB and `maxPageHeightPx` from 1,000 to 100,000 pixels. This is the exact input used for the real output item below:

```json
{
  "urls": [
    "https://example.com/"
  ],
  "format": "png",
  "waitUntil": "load",
  "delay": 0,
  "viewportWidth": 1280,
  "scrollToBottom": false,
  "delayAfterScrolling": 2500,
  "waitUntilNetworkIdleAfterScroll": false,
  "waitUntilNetworkIdleAfterScrollTimeout": 30000,
  "selectorsToHide": "",
  "maxArtifactSizeMb": 20,
  "maxPageHeightPx": 25000,
  "proxyConfiguration": {}
}
```

Other available settings are `waitUntil`, `delay`, `waitUntilNetworkIdleAfterScroll`, `waitUntilNetworkIdleAfterScrollTimeout`, `proxyConfiguration`, `maxArtifactSizeMb`, and `maxPageHeightPx`. Their defaults and valid ranges are shown in the Apify input form and generated API examples.

### Output

The default Dataset contains one item for every normalized, unique URL that the Actor processes. Successful captures include a direct `screenshotUrl` download link and a `screenshotKey` identifying the stored file. PNG captures are full-page images; PDFs use an A4 print layout and may paginate differently from a PNG. This is the complete Dataset item from a real successful run:

```json
{
  "startUrl": "https://example.com/",
  "url": "https://example.com/",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/D7ZccdBkT0dq85bgq/records/screenshot-example.com-b559c7edd3fb.png?signature=bDZoPhmifPuzQ4yprLML",
  "screenshotKey": "screenshot-example.com-b559c7edd3fb.png",
  "format": "png",
  "status": "success",
  "timestamp": "2026-08-23T21:36:19.192242+02:00",
  "errorMessage": null,
  "warnings": []
}
```

Important fields are:

- `startUrl`: the normalized URL used to start the capture.
- `url`: the final URL after redirects.
- `screenshotUrl`: the download link when a file was created.
- `format`: `png` or `pdf`.
- `status`: `success`, `blocked`, or `error`.
- `errorMessage`: the reason for an unsuccessful capture, when applicable.
- `warnings`: non-fatal notices such as detected access challenges or invalid selectors.

Navigation and capture problems are retried automatically. A failed URL is reported in the Dataset and does not stop the remaining URLs unless the run spending limit is reached.

### Pricing

The Actor charges **$0.001 for each processed URL**, equivalent to **$1 per 1,000 processed URLs**.

One normalized, unique URL that is processed and receives a Dataset row creates one `screenshot-result` charge. Successful captures, blocked pages, navigation errors, and capture-limit errors are charged because the URL was processed. Duplicate URLs removed during normalization and invalid input rejected before processing are not charged. There is no separate start charge configured for this Actor.

### API and integrations

The Apify Console generates ready-to-use examples for Python, JavaScript, cURL, and other supported clients directly from the Actor input schema. Because the other settings have defaults, the generated client example may contain only the required `urls` list. Apify applies the documented defaults when optional fields are omitted.

To send custom settings, include the optional fields you want to change. This Python example uses valid values for every available input:

```python
run_input = {
    "urls": ["https://example.com/"],
    "format": "png",
    "waitUntil": "load",
    "delay": 0,
    "viewportWidth": 1280,
    "scrollToBottom": False,
    "delayAfterScrolling": 2500,
    "waitUntilNetworkIdleAfterScroll": False,
    "waitUntilNetworkIdleAfterScrollTimeout": 30000,
    "selectorsToHide": "",
    "maxArtifactSizeMb": 20,
    "maxPageHeightPx": 25000,
    "proxyConfiguration": {},
}
```

Runs can also be started from Apify schedules, webhooks, tasks, and external applications using the Apify API. Results are available through the run's default Dataset and the stored PNG or PDF files through their `screenshotUrl` links.

### Related Actors

| Actor | Best for |
|---|---|
| [PDF Text Extractor - OCR, Markdown & JSON](https://apify.com/datascraperes/pdf-text-extractor) | Extract searchable text and structured content from public PDFs after creating document snapshots. |
| [Favicon Extractor](https://apify.com/datascraperes/favicon-extractor) | Collect lightweight website icons from the same URL list for directories, previews, and brand-asset workflows. |
| [Website Technology Lookup – CMS, Hosting & Tech Stack Data](https://apify.com/datascraperes/website-technology-lookup) | Add CMS, hosting, and technology context to pages included in a visual website review. |

### Limits and data quality

- A run accepts up to 1,000 URLs.
- Equivalent normalized duplicates are removed before processing.
- URLs are processed in normalized input order.
- The Actor is intended for public pages and does not log in or access private content.
- CAPTCHA, access challenges, and automated-traffic blocks are reported as `blocked`; the Actor does not attempt to bypass them.
- Very long pages can exceed `maxPageHeightPx`, and oversized PNG or PDF files can exceed `maxArtifactSizeMb`. In either case, the URL receives an `error` row and the batch continues.
- Pages that load content after scrolling may need `scrollToBottom`, a longer `delayAfterScrolling`, or a network-idle wait.
- PDF pagination can differ from the visual PNG because websites may apply print-specific styles.
- For most public pages, the default direct connection is sufficient. An Apify Proxy configuration can be supplied when a target site requires one.

### Frequently asked questions

#### What happens if I enter `example.com` without `https://`?

The Actor adds `https://` automatically. It also trims surrounding spaces and keeps the path, query string, and fragment.

#### Can I capture pages with lazy-loaded content?

Yes. Enable `scrollToBottom` and, if necessary, increase `delayAfterScrolling` or enable the network-idle wait after scrolling.

#### How can I hide a cookie banner or popup?

Enter its CSS selector in `selectorsToHide`, for example `.cookie-banner, #consent-modal`.

#### What is the difference between PNG and PDF?

PNG is a full-page visual image. PDF is an A4 printable document and can split long pages across multiple pages.

#### What happens when one URL fails?

The Actor writes an `error` row with the reason and continues with the remaining URLs. The processed URL still counts toward the price.

#### Where are the generated files?

The files are stored with the run and can be downloaded from the `screenshotUrl` field in the Dataset.

### Responsible use

Use this Actor only for lawful purposes and in accordance with applicable laws, privacy obligations, third-party rights, and the terms of the websites you access. Do not use it to access private content, bypass access controls, solve CAPTCHAs, or collect information without an appropriate purpose.

### Support

If you need help, open an issue in the Actor's **Issues** tab and include a reproducible input, the run ID, and the relevant Dataset row or error message. Do not include API tokens, passwords, private URLs, or other sensitive information.

# Actor input Schema

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

HTTP or HTTPS URLs to capture. One dataset item is produced for each accepted URL.

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

PNG captures the rendered page. PDF creates an A4 print document.

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

Navigation state to wait for before capturing.

## `delay` (type: `integer`):

Additional time to wait after the selected navigation state.

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

Browser viewport width in CSS pixels. The viewport height is fixed at 1080px.

## `scrollToBottom` (type: `boolean`):

Scrolls incrementally to trigger lazy-loaded content before capturing.

## `delayAfterScrolling` (type: `integer`):

Additional wait after the scrolling pass.

## `waitUntilNetworkIdleAfterScroll` (type: `boolean`):

Waits for network idle after scrolling, with the timeout below.

## `waitUntilNetworkIdleAfterScrollTimeout` (type: `integer`):

Maximum wait for network idle after scrolling.

## `selectorsToHide` (type: `string`):

Comma-separated CSS selectors to hide before capture, for example .cookie-banner,.modal.

## `maxArtifactSizeMb` (type: `integer`):

Maximum size of each PNG or PDF. If exceeded, the file is not stored and the URL is returned as an error.

## `maxPageHeightPx` (type: `integer`):

Maximum rendered document height before capture. If exceeded, the file is not stored and the URL is returned as an error.

## `proxyConfiguration` (type: `object`):

Optional Apify Proxy configuration. Leave empty to connect directly.

## Actor input object example

```json
{
  "urls": [
    "https://example.com/"
  ],
  "format": "png",
  "waitUntil": "load",
  "delay": 0,
  "viewportWidth": 1280,
  "scrollToBottom": false,
  "delayAfterScrolling": 2500,
  "waitUntilNetworkIdleAfterScroll": false,
  "waitUntilNetworkIdleAfterScrollTimeout": 30000,
  "selectorsToHide": "",
  "maxArtifactSizeMb": 20,
  "maxPageHeightPx": 25000,
  "proxyConfiguration": {}
}
```

# Actor output Schema

## `results` (type: `string`):

One result row per URL processed.

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

Captured PNG or PDF files stored in the default Key-Value Store.

# 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": [
        "https://example.com/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datascraperes/website-screenshot-pdf").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": ["https://example.com/"] }

# Run the Actor and wait for it to finish
run = client.actor("datascraperes/website-screenshot-pdf").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": [
    "https://example.com/"
  ]
}' |
apify call datascraperes/website-screenshot-pdf --silent --output-dataset

```

## MCP server setup

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

```

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/D2Taqj7QkZyLveWUH/builds/G530LmZ4GT9mzZzgl/openapi.json
