# Website Screenshot & PDF — full page, element, print CSS (`opencrawl/website-screenshot-pdf`) Actor

Render any public URL in real Chromium: full-page PNG/JPEG, one element by CSS selector, or a print-quality PDF. Wait for JS, suppress consent banners, choose desktop/mobile and 2x retina, and get sha256 metadata per result. Optional proxy; pay per result.

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

## Pricing

$6.00 / 1,000 results

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?

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

## Website Screenshot & PDF — full page, element, print CSS

Turn any public URL into a **PNG or JPEG screenshot** — the whole page, the
viewport, or one element by CSS selector — or a **print-quality PDF**. Real
Chromium, so JavaScript apps render, and a short wait for the content you
actually want.

### What you get

One dataset item per URL, with the file in the run's key-value store:

```json
{
  "url": "https://example.com",
  "finalUrl": "https://example.com/",
  "statusCode": 200,
  "title": "Example Domain",
  "format": "png",
  "width": 1280,
  "height": 10036,
  "bytes": 86742,
  "sha256": "…",
  "key": "example-com-136e68.png",
  "billed": true,
  "fetchedAt": "2026-10-22T20:24:00.000Z",
  "elapsedMs": 1161
}
```

`billed` is `false` for 4xx/5xx pages: you still get the image (often the error
or challenge page), but it is not charged.

### What makes it different

- **Element capture** — screenshot one card, table, chart or map with
  `selector`, not the whole page.
- **True full page** — captures the entire scroll height, not just a scroll to
  the bottom.
- **Retina output** — `deviceScaleFactor` 2 or 3.
- **Wait for a selector** — `waitForSelector` for results that load after the
  page settles.
- **Consent suppression** — common cookie/GDPR/paywall overlays are hidden
  automatically, plus up to 20 custom `hideSelectors`.
- **Honest metadata** — final URL, HTTP status, title, bytes and sha256.
- **Optional Apify Proxy** — one session per URL for bot-protected sites.

### Input

| Field | Default | What it does |
|---|---|---|
| `startUrls` | — | Pages to render (1–50 per run) |
| `format` | `png` | `png`, `jpeg` or `pdf` |
| `fullPage` | `true` | Entire scrollable page, not just the viewport |
| `selector` | — | Capture only the first element matching this CSS selector |
| `viewportWidth` / `viewportHeight` | 1280 / 800 | Browser size; 390×844 for a phone layout |
| `deviceScaleFactor` | 1 | 2–3 for retina output |
| `waitUntil` | `networkidle` | `load`, `domcontentloaded`, `networkidle`, `commit` |
| `waitForSelector` | — | Wait for this selector before capturing |
| `delayMs` | 0 | Extra wait for animations/late paints |
| `hideBanners` | `true` | Hide common cookie/consent/paywall overlays |
| `hideSelectors` | — | Up to 20 selectors to hide |
| `pdfFormat` | `A4` | `A4` or `Letter` |
| `printBackground` | `true` | Include background colours in PDFs |
| `quality` | 80 | JPEG quality |
| `proxyConfiguration` | — | Optional Apify Proxy |
| `maxPages` / `timeoutSecs` | 10 / 30 | Run bounds |

### Use cases

- Visual regression and change monitoring with the scheduler
- Social previews and OG images for CMS content
- Archiving a receipt, invoice or dashboard as PDF
- Capturing a single chart or table for a report
- Rendering JS-heavy pages that plain HTTP fetchers return empty

### Pricing

Pay per result: **$0.006 per capture** (screenshots and PDFs the same). A 4xx/5xx
page is delivered but not charged. The Apify free tier still applies.

### Limits

- Public HTTP(S) pages only; private, loopback and link-local addresses are
  refused at the top level and for subresources.
- Sites behind aggressive bot checks may return the challenge page; the status
  code is recorded and the run does not crash. Optional Apify Proxy helps.
- Login-gated pages are out of scope. No captcha solving.
- PDFs follow the browser's print layout; heavily virtualised pages may not
  paginate perfectly.

# Actor input Schema

## `startUrls` (type: `array`):

Public pages to render. Each one becomes a dataset item (and one billed result).

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

png (lossless screenshot), jpeg (smaller, quality setting applies) or pdf (print layout).

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

Capture the entire scrollable page instead of the viewport (ignored for PDF and element captures).

## `selector` (type: `string`):

Screenshot only the first element matching this CSS selector, e.g. #main or article. Leave empty for the whole page.

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

Browser width in CSS pixels (200–3000). Use 390 for a phone layout.

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

Browser height in CSS pixels (200–3000).

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

1 = standard, 2 = retina-quality output (larger file).

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

Navigation readiness. networkidle is best for apps that fetch data after load.

## `waitForSelector` (type: `string`):

Wait until this selector exists before capturing, e.g. main .results.

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

Additional wait after navigation, for animations and late paints (0–10000).

## `hideBanners` (type: `boolean`):

Inject CSS that hides common cookie, consent, GDPR and paywall overlays before capture.

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

CSS selectors to hide before capture, e.g. .newsletter-popup or #chat-widget. Up to 20.

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

Optional Apify Proxy. Use it for bot-protected sites; each URL gets its own session. Leave empty for direct access.

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

Paper size for PDF output.

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

Include background colours and images in the PDF.

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

JPEG quality 30–100 (ignored for PNG/PDF).

## `maxPages` (type: `integer`):

Upper bound on URLs rendered in one run (1–50).

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

Per-URL timeout (5–120).

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://example.com"
    }
  ],
  "format": "png",
  "fullPage": true,
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "deviceScaleFactor": 1,
  "waitUntil": "networkidle",
  "delayMs": 0,
  "hideBanners": true,
  "pdfFormat": "A4",
  "printBackground": true,
  "quality": 80,
  "maxPages": 10,
  "timeoutSecs": 30
}
```

# Actor output Schema

## `captures` (type: `string`):

Metadata for every rendered URL: final URL, HTTP status, title, dimensions, byte size, sha256, key-value store key, billed flag and elapsed time. Failed URLs carry an error field instead.

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

PNG, JPEG or PDF files in the run's key-value store. The file name is the 'key' field of the matching dataset item.

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

// Run the Actor and wait for it to finish
const run = await client.actor("opencrawl/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 = { "startUrls": [{ "url": "https://example.com" }] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,opencrawl/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/KBiuftsuZTeqwQ9hn/builds/nFkGcT2ZPek4cNNed/openapi.json
