# Website Screenshot & PDF: Full Page, Mobile, Batch URLs (`private_image_hg9/website-screenshot-pdf`) Actor

Full-page or viewport screenshots (PNG, JPEG) and PDFs of any list of web pages. Desktop, tablet and phone sizes, cookie banners hidden, lazy images loaded. You pay only for pages captured cleanly; errors, 404s and bot checks are free.

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

## Pricing

$5.00 / 1,000 page captureds

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, Mobile, Batch URLs

Give it a list of web pages and get back a clean screenshot (PNG or JPEG) or a PDF of each one. It handles full pages, viewports, phone and tablet sizes, dark mode, or a single element. Cookie banners and sign-up pop-ups are hidden and lazy images are loaded before the picture is taken.

**You pay only for pages captured cleanly.** A page that fails to load, answers with an error (404, 500) or shows a bot check still gets a row explaining why, plus the file when there is one, and none of those are charged.

### What you can do with it

- **Archive and monitor pages:** competitor pricing, landing pages, search results you're allowed to keep, terms and policies, before and after a release.
- **Visual checks:** see how a site looks on desktop, iPad and phones in one run.
- **Thumbnails and previews:** link previews, directories, portfolio and client reports.
- **PDFs of articles and docs:** with selectable text, in A4, Letter and other paper sizes.
- **Feed AI tools:** send page screenshots to vision models, which often read a layout better than raw HTML.

### Why this one

| | This Actor | Typical screenshot Actor |
|---|---|---|
| Price | $5 per 1,000 clean captures, compute included | your own compute on top, or a per-capture price that also charges failures |
| Failed pages, 404s, bot checks | not charged | charged or billed as compute |
| Cookie banners | hidden (about 50 consent tools plus home-made banners) | often cover the page |
| Sign-up and discount pop-ups | hidden, with the dark layer behind them | often cover the page |
| Lazy images | scrolls first so they load | often blank |
| Very long pages | cut at a height you choose, and the row says so | huge files or crashes |
| Pages that never stop loading | captured when the timeout runs out, with a note | run fails |

### Input

The only required field is **Page addresses**. Everything else has sensible defaults.

```json
{
  "urls": ["https://apify.com", "example.com/pricing"],
  "format": "png",
  "fullPage": true,
  "device": "desktop"
}
```

| Field | What it does | Default |
|---|---|---|
| `urls` | Pages to capture. `example.com` gets `https://`. Up to 10,000 per run. Repeats are captured once. | required |
| `format` | `png`, `jpeg` (smaller files) or `pdf` | `png` |
| `fullPage` | Whole page top to bottom, or just the screen | `true` |
| `device` | `desktop` 1440x900, `desktop-hd` 1920x1080, `laptop` 1280x800, `tablet` (iPad Air), `iphone` (iPhone 15), `android` (Pixel 8). Tablet and phone presets use the mobile layout, touch and the device's pixel density. | `desktop` |
| `hideCookieBanners` | Hide cookie and consent pop-ups. Nothing is clicked or accepted. | `true` |
| `hidePopups` | Hide sign-up, discount and newsletter pop-ups and Google's sign-in prompt | `true` |
| `scrollToLoad` | Scroll down first so lazy images appear (full page only) | `true` |
| `delaySeconds` | Extra wait after loading, for animations and late content | `1` |
| `waitUntil` | `load`, `domcontentloaded` (fastest) or `networkidle` (for apps) | `load` |
| `waitForSelector` | Wait for this CSS selector before capturing | none |
| `selector` | Capture only the first visible element matching this CSS selector | none |
| `hideSelectors` | CSS selectors to hide, such as chat widgets or promo bars | none |
| `viewportWidth`, `viewportHeight` | Custom screen size in pixels (0 keeps the preset) | `0` |
| `deviceScaleFactor` | `2` for a sharp retina image (0 keeps the preset) | `0` |
| `maxHeight` | Long pages are cut here; `truncated` says when | `16000` |
| `jpegQuality` | 10 to 100 | `80` |
| `colorScheme` | `light`, `dark` or `no-preference` | `light` |
| `pdfPaperFormat`, `pdfLandscape`, `pdfMedia` | PDF paper size, orientation, and screen look or the site's print styles | `A4`, `false`, `screen` |
| `pageTimeoutSecs` | Most time on one page | `45` |
| `maxConcurrency` | Pages open at once. 0 sets it from the run's memory (2 at the default 4 GB, 4 at 8 GB). | `0` |
| `proxyConfiguration` | Optional Apify Proxy for sites that turn away data-center visitors | off |

### Output

The files go in the run's key-value store, and the dataset has one row per page:

```json
{
  "url": "example.com/pricing",
  "requestedUrl": "https://example.com/pricing",
  "finalUrl": "https://www.example.com/pricing",
  "status": "ok",
  "httpStatus": 200,
  "pageTitle": "Pricing | Example",
  "format": "png",
  "device": "desktop",
  "fileUrl": "https://api.apify.com/v2/key-value-stores/.../records/0001-example-com-pricing.png",
  "fileKey": "0001-example-com-pricing.png",
  "width": 1440,
  "height": 6120,
  "pdfPages": null,
  "fullPage": true,
  "truncated": false,
  "pageHeight": 6120,
  "bytes": 1843921,
  "seconds": 4.2,
  "note": null,
  "error": null,
  "capturedAt": "2026-11-03T18:00:00+00:00"
}
```

`status` is one of:

- `ok`: captured cleanly. **The only charged status.**
- `error_page`: the page answered with an error such as 404 or 500. The file is saved so you can see it.
- `blocked`: the site showed a bot check, refused the visit (403, 429) or sent it to a consent page on another domain. The file is saved. Try again with a proxy.
- `failed`: nothing could be captured, for example the domain doesn't exist, the server doesn't answer, or the element in `selector` isn't on the page. `error` says which.
- `invalid_url`: the entry isn't a public web address.

A `SUMMARY` record in the key-value store counts each status, what was charged and whether your spending limit stopped the run.

### Pricing

**$5 per 1,000 pages captured cleanly** ($0.005 each), whatever the size, format or device. Compute is included, so nothing else is charged per page. For big batches, give the run 8 GB or more of memory: it opens more pages at once and finishes sooner at the same price. If you set a maximum cost for a run, the Actor stops starting new pages before it would go over.

### Good to know

- Only public pages: there's no login or cookie input, and local or internal network addresses are refused.
- Some sites block visitors from data centers. Those rows come back as `blocked` at no charge; Apify Proxy often gets them through.
- Pages are captured as they load in a real Chromium browser. Video frames, maps and canvas content show what was drawn at that moment.
- Very tall pages are cut at `maxHeight` (16,000 px by default) so files stay usable. Raise it to 30,000 if you need more.
- You're responsible for having the right to capture and keep the pages you list.

### More tools from the same developer

- [Broken Link Checker: 404s, Redirects & Dead Links](https://apify.com/private_image_hg9/broken-link-checker)
- [SEO Audit Tool: On-Page Checks, Crawl & Broken Links](https://apify.com/private_image_hg9/seo-audit-onpage)
- [Sitemap URL Extractor: All Site URLs, Lastmod & News](https://apify.com/private_image_hg9/sitemap-url-extractor)
- [Bulk URL Status Checker: Redirect Chain & Response Time](https://apify.com/private_image_hg9/bulk-url-status-redirect-checker)
- [Wayback Machine Scraper: Snapshots, Changes & Page Text](https://apify.com/private_image_hg9/wayback-machine-snapshots)
- [Domain WHOIS, DNS & SSL Checker: Expiry, SPF & DMARC](https://apify.com/private_image_hg9/domain-whois-dns-ssl-checker)

# Actor input Schema

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

The pages to capture, one per line: "https://apify.com", "example.com/pricing". Addresses without http:// or https:// get https://. Up to 10,000 pages per run; repeated addresses are captured once.

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

PNG is sharp and lossless. JPEG files are much smaller. PDF prints the page to a document with selectable text.

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

Capture the whole page from top to bottom. Turn off to capture only what fits on the screen (the viewport).

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

Screen size and type. Tablet and phone presets use the device's pixel density, touch and mobile browser, so you get the mobile layout of the site.

## `hideCookieBanners` (type: `boolean`):

Hide cookie and consent pop-ups from the common consent tools (OneTrust, Cookiebot, Usercentrics, Didomi, Quantcast and about 40 more) and home-made ones, so they don't cover the page. Nothing is clicked or accepted.

## `hidePopups` (type: `boolean`):

Hide sign-up, discount and newsletter pop-ups, Google's sign-in prompt and the dark layer behind them, so the page underneath shows. Turn off to capture pages exactly as a first-time visitor sees them.

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

For full-page captures, scroll down the page first so lazy-loaded images and sections appear in the picture.

## `delaySeconds` (type: `integer`):

Seconds to wait after the page has loaded, for animations, sliders or late content.

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

When the page counts as loaded. Network idle waits for the page to stop fetching for half a second, which suits single-page apps. A page that never finishes loading is still captured when the page timeout runs out.

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

Optional CSS selector to wait for before capturing, e.g. "#chart canvas" or ".product-grid".

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

Optional CSS selector. When set, only the first visible matching element is captured, e.g. "#pricing" or "main article". Pages without it get status failed and are not charged.

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

CSS selectors of things to hide from the picture, such as chat widgets or promo bars: ".intercom-lightweight-app", "#promo-bar".

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

Overrides the device width. 0 keeps the preset.

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

Overrides the device height (the visible screen; full-page captures are taller). 0 keeps the preset.

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

2 gives a sharp retina image at twice the width and height. 0 keeps the device preset (1 for desktops).

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

Very long pages are cut at this height so files stay usable. The row's truncated field says when a page was cut.

## `jpegQuality` (type: `integer`):

10 to 100. Used only for JPEG.

## `colorScheme` (type: `string`):

Ask the site for its light or dark theme. Sites without a dark theme look the same either way.

## `pdfPaperFormat` (type: `string`):

Used only for PDF.

## `pdfLandscape` (type: `boolean`):

Print the PDF sideways.

## `pdfMedia` (type: `string`):

Screen keeps the page as you see it in a browser. Print uses the site's print styles, which usually drop menus and ads.

## `pageTimeoutSecs` (type: `integer`):

Most time spent on one page. A page that hasn't started loading by then is retried once, then reported as failed (not charged).

## `maxConcurrency` (type: `integer`):

How many pages are open at the same time. Leave at 0 to set it from the run's memory: 2 at the default 4 GB, 4 at 8 GB. Apify gives one CPU core per 4 GB, and more pages per core makes pages time out.

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

Optional. Use Apify Proxy for sites that turn away data-center visitors or show a different country's version. Off by default.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://www.wikipedia.org"
  ],
  "format": "png",
  "fullPage": true,
  "device": "desktop",
  "hideCookieBanners": true,
  "hidePopups": true,
  "scrollToLoad": true,
  "delaySeconds": 1,
  "waitUntil": "load",
  "viewportWidth": 0,
  "viewportHeight": 0,
  "deviceScaleFactor": 0,
  "maxHeight": 16000,
  "jpegQuality": 80,
  "colorScheme": "light",
  "pdfPaperFormat": "A4",
  "pdfLandscape": false,
  "pdfMedia": "screen",
  "pageTimeoutSecs": 45,
  "maxConcurrency": 0
}
```

# Actor output Schema

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

One row per page: a link to its file, the page title, size, and why it wasn't charged when it wasn't.

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

All screenshots and PDFs of the run.

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

Counts for the run: captured, charged, error pages, blocked and failed, and whether the spending cap was reached.

# 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://apify.com",
        "https://www.wikipedia.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("private_image_hg9/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://apify.com",
        "https://www.wikipedia.org",
    ] }

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

```

## MCP server setup

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