# Website Screenshot API: Full Page PNG, JPEG & PDF (`actose/website-screenshot-pdf`) Actor

Bulk website screenshots and HTML to PDF: full-page PNG, JPEG or PDF, element capture, mobile/retina, wait for selector, cookie banners hidden, page text for LLMs. Direct file links. No API key, no login. MCP-ready for AI agents. Pay per result, errors are free. $4.80 per 1,000 screenshots.

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

## Pricing

from $4.08 / 1,000 screenshot or pdf delivereds

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

## Website Screenshot API: Full Page PNG, JPEG & PDF

**Price: $4.80 per 1,000 screenshots ($0.0048 per file) + $0.001 per run.** You pay only for files actually delivered. Failed pages, timeouts, blocked sites and HTTP error pages are free. A run that produces no file costs nothing.

This Actor captures any public web page, or your own raw HTML, as a **PNG**, **JPEG** or **PDF** with a real Chromium browser. You get full-page or viewport captures, single-element captures, mobile device emulation, wait-for-selector and automatic cookie banner hiding. Send one URL or thousands in one run. No API key, no login, no monthly rental.

Every file is saved in the run's key-value store. The dataset gets one row per file with a **direct download link** (`fileUrl`), the page title, the HTTP status and the file size. With `extractText` on, each row also includes the **clean visible text of the page**, ready for LLMs and RAG.

### What it does

- **PNG, JPEG and PDF**: pick one or more formats. The page loads once, and every format comes from that one load.
- **Full-page screenshots**: the page is scrolled first so lazy-loaded images appear. Very tall pages are cropped at `maxPageHeight`.
- **Element capture**: `elementSelector` captures only the matching element, e.g. `#pricing`.
- **Wait for an element**: `waitForSelector` waits for a chart, a map or app content before capturing.
- **Cookie banners hidden**: OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast, Sourcepoint, Complianz, CookieYes and many more are hidden with CSS. Nothing is clicked or accepted. Add your own elements with `hideSelectors`.
- **HTML to PDF / PNG**: paste HTML (`html`) or send a batch (`htmlPages`) for invoices, reports, certificates and social cards.
- **Screen & device**: custom viewport, retina (2x/3x), dark mode, iPhone/Pixel/iPad emulation.
- **PDF options**: paper size, landscape, margins, backgrounds, screen or print CSS, or **one long page without page breaks**.
- **LLM-ready text** (`extractText`): the visible page text in `pageText`, free of charge.
- **Scheduled runs** (`onlyNew`): skip pages you already captured in earlier runs, so a growing URL list only costs you for new pages.
- **Reliable**: automatic retries on timeouts, network errors and HTTP 429/5xx. One failing page never stops the batch. Failed rows have `status: "failed"` and a readable `errorMessage`, and they are free.

### How much does it cost?

| Event | Price | When |
|---|---|---|
| `screenshot` | $0.0048 | One file (PNG, JPEG or PDF) saved and listed in the dataset |
| `actor-start` | $0.001 | Once per run, charged only with the first delivered file |

Examples:

- **1,000 URLs in PNG = $4.80** + $0.001 = **$4.801**
- 1 URL in PNG + PDF = 2 × $0.0048 + $0.001 = $0.0106
- 100 HTML invoices to PDF = $0.481

Platform usage (compute) is included. Errors and empty runs are free. If you set a maximum cost per run, the Actor stops cleanly when it reaches that limit. It never delivers files beyond your budget.

### Input example

```json
{
  "urls": ["https://example.com", "https://apify.com"],
  "formats": ["png", "pdf"],
  "fullPage": true,
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "waitUntil": "load",
  "waitForSelector": "",
  "delayMs": 1000,
  "hideCookieBanners": true,
  "pdfFormat": "A4",
  "extractText": false,
  "onlyNew": false
}
```

HTML to PDF in batch:

```json
{
  "htmlPages": [
    {"name": "invoice-001", "html": "<html><body><h1>Invoice #001</h1><p>Total: $120</p></body></html>"},
    {"name": "invoice-002", "html": "<html><body><h1>Invoice #002</h1><p>Total: $80</p></body></html>"}
  ],
  "formats": ["pdf"],
  "pdfMargin": "15mm"
}
```

### Output example

One dataset item per file:

```json
{
  "url": "https://example.com",
  "sourceType": "url",
  "name": "example.com/",
  "status": "success",
  "format": "png",
  "fullPage": true,
  "elementSelector": null,
  "device": null,
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "fileKey": "0001-example-com.png",
  "fileUrl": "https://api.apify.com/v2/key-value-stores/aBcD1234/records/0001-example-com.png",
  "contentType": "image/png",
  "fileSizeBytes": 21873,
  "finalUrl": "https://example.com/",
  "pageTitle": "Example Domain",
  "httpStatus": 200,
  "capturedAt": "2026-10-15T09:12:44+00:00",
  "durationMs": 2310,
  "errorMessage": null,
  "pageText": "Example Domain\nThis domain is for use in illustrative examples in documents...",
  "pageTextLength": 127
}
```

`pageText` and `pageTextLength` are `null` unless `extractText` is on.

A failed page (free):

```json
{
  "url": "https://example.com/missing",
  "status": "failed",
  "format": "png",
  "fileUrl": null,
  "errorMessage": "HTTP 404 returned by the page."
}
```

### Main input fields

| Field | Type | Default | Description |
|---|---|---|---|
| `urls` | string\[] | – | Pages to capture (`https://` added if missing) |
| `html` / `htmlPages` | string / object\[] | – | Raw HTML to render (`{name, html}` objects for batches) |
| `formats` | `png` | `jpeg` | `pdf` \[] | `["png"]` | One file per format per page |
| `fullPage` | boolean | `true` | Whole scrollable page or viewport only |
| `elementSelector` | string | – | Capture only this element (PNG/JPEG) |
| `viewportWidth` / `viewportHeight` | integer | 1280 / 800 | Browser size in CSS px |
| `deviceScaleFactor` | 1–3 | 1 | Retina density |
| `device` | string | `desktop` | iPhone 13, iPhone 14 Pro Max, Pixel 7, Galaxy S9+, iPad Mini, iPad Pro 11 |
| `colorScheme` | `light` | `dark` | `light` | Preferred color scheme |
| `waitUntil` | `domcontentloaded` | `load` | `networkidle` | `load` | Load condition |
| `waitForSelector` | string | – | Wait until this element is visible |
| `delayMs` | integer | 1000 | Extra wait before capture |
| `hideCookieBanners` | boolean | `true` | Hide consent pop-ups with CSS |
| `hideSelectors` | string\[] | – | Extra elements to hide |
| `pdfFormat`, `pdfLandscape`, `pdfMargin`, `pdfPrintBackground`, `pdfUseScreenMedia`, `pdfSinglePage` | – | A4, false, 0, true, false, false | PDF layout |
| `maxPageHeight` | integer | 20000 | Crop limit for full-page captures |
| `captureErrorPages` | boolean | `false` | Also capture HTTP 4xx/5xx pages (charged) |
| `navigationTimeoutSecs`, `maxRetries`, `maxConcurrency` | integer | 60, 2, 2 | Reliability and speed |
| `onlyNew` | boolean | `false` | Skip pages already captured in earlier runs (same format) |
| `extractText` | boolean | `false` | Add the visible page text (`pageText`) for LLMs |

### Use with AI agents (MCP)

This Actor works as a tool for Claude, Cursor, ChatGPT and other AI agents through the [Apify MCP server](https://mcp.apify.com). An agent sends a list of URLs and gets back JSON rows, each with a direct `fileUrl` to the image or PDF. With `extractText: true`, it also gets the page's visible text in `pageText`, so the agent can read the page and keep a visual record from a single call.

### Integrations

- **API**: run it with `POST https://api.apify.com/v2/acts/<this-actor>/run-sync-get-dataset-items?token=...` and get the rows (with file links) in the response.
- **Make, Zapier, n8n**: use the Apify app/node, then pass `fileUrl` to Google Drive, Slack, email or S3.
- **Google Sheets**: export the dataset, or schedule a run and sync the rows. `fileUrl` opens the file directly.
- **Schedules + `onlyNew`**: capture only newly added pages each day, for example new product or article URLs.

### Use cases

- **Website monitoring & archiving**: daily full-page snapshots of your pages, competitors' pricing pages or landing pages.
- **SEO & marketing reports**: captures of landing pages, ads and campaign proof for clients.
- **HTML to PDF**: invoices, receipts, reports, certificates and contracts generated from templates.
- **Social images & thumbnails**: render an HTML card at 1200×630 and get a PNG.
- **QA & visual regression**: desktop, mobile and dark-mode captures of every page of a site.
- **AI agents & RAG**: a screenshot plus clean page text in one call.
- **Compliance & legal evidence**: timestamped captures with HTTP status and final URL.

### FAQ

**How do I download the files?**
Open `fileUrl` from each dataset row, or open the run's *Key-value store* tab. Through the API, use `GET /v2/key-value-stores/{storeId}/records/{fileKey}`.

**Are failed pages charged?**
No. You pay only for files saved and listed with `status: "success"`. The $0.001 run fee is charged with the first delivered file. A run where every page fails costs nothing.

**Can I get a PNG and a PDF of the same page?**
Yes: `"formats": ["png", "pdf"]`. The page loads once and you pay for 2 files.

**How does `onlyNew` work?**
Each URL (or HTML document) and format captured successfully is remembered in your named key-value store `website-screenshot-pdf-state`. Later runs with `onlyNew` on skip them without loading or charging them. Leave it off when you want a fresh snapshot of the same pages each run. To start over, delete that store.

**Does it accept cookie banners or log in?**
No. Banners are only hidden visually. The Actor never logs in, never solves captchas and never bypasses anti-bot protections. It captures what a regular visitor sees.

**A site returns 403 or a captcha page. What can I do?**
Some sites block automated browsers. The capture is reported as failed and is free. Turn on `captureErrorPages` if you want an image of the error page anyway (charged).

**Images are missing from my full-page capture.**
Keep `scrollToBottom` on, increase `delayMs`, or use `waitUntil: "networkidle"`.

**My raw HTML has broken images or styles.**
Use absolute URLs (`https://...`) for images, fonts and stylesheets, or inline them (data URIs, `<style>`).

**How long are files kept?**
Files follow your Apify storage retention. Unnamed run storages are kept according to your plan's data retention. Download or move any files you need to keep.

### Limits

- Public pages only: no login, no captcha solving, no anti-bot bypass, no proxy. Sites that block data-center browsers will fail (for free).
- Full-page captures are cropped at `maxPageHeight` (default 20,000 px, max 50,000 px). Infinite-scroll feeds only show what loaded.
- Single-page PDFs are limited to 19,200 px in height (the Chromium page-size limit).
- `elementSelector` applies to PNG/JPEG only. PDFs always contain the whole document.
- Cookie banners are hidden using a list of known selectors. Uncommon custom banners may remain, so add them with `hideSelectors`.
- Rendering uses Chromium, so pages that rely on Safari- or Firefox-specific behavior may look slightly different. Device emulation changes the viewport and user agent, not the engine.
- `pageText` is capped at 100,000 characters (`pageTextLength` gives the full length).
- `fileUrl` links work without a token unless your Apify account restricts access to storages. In that case, append `?token=YOUR_TOKEN`.

# Actor input Schema

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

Web pages to capture, one per line. 'https://' is added if missing. Only public http/https pages.

## `html` (type: `string`):

Paste a full HTML document to render it instead of (or in addition to) URLs — e.g. an invoice or report to turn into a PDF. Use absolute URLs for images and stylesheets.

## `htmlName` (type: `string`):

Used to build the file name of the raw HTML capture.

## `htmlPages` (type: `array`):

For batch HTML-to-PDF/PNG: a JSON array of objects {"name": "invoice-001", "html": "<html>...</html>"} (plain strings are accepted too).

## `formats` (type: `array`):

One file is produced per format for every page (the page is loaded only once). Each file is one billed capture.

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

Capture the whole scrollable page instead of only the visible viewport (PNG/JPEG).

## `elementSelector` (type: `string`):

If set, PNG/JPEG captures contain only the first element matching this selector, e.g. '#pricing' or 'main'. Ignored for PDF.

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

1–100. Lower means smaller files.

## `maxPageHeight` (type: `integer`):

Full-page captures taller than this are cropped (infinite-scroll pages would otherwise never end).

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

Browser window width in CSS pixels. Ignored if a device is selected.

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

Browser window height in CSS pixels (= image height when 'Full page' is off). Ignored if a device is selected.

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

1 = normal, 2 = retina (twice the pixels, sharper and bigger files), 3 = max.

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

Mobile/tablet emulation (viewport, pixel density, user agent, touch). Leave empty for a desktop browser with the viewport above.

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

Sites that support it will render in light or dark mode.

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

When the page counts as loaded. 'Network idle' is best for heavy JavaScript apps but slower.

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

Wait until this element is visible before capturing, e.g. '.chart canvas' or '#content'. If it never appears, the capture fails and is not charged.

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

Additional wait after loading, for animations and late content.

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

Scroll through the page before a full-page capture or PDF so lazy-loaded images appear.

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

Hide common cookie/consent pop-ups (OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast, and more) with CSS. Nothing is clicked or accepted.

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

Extra elements to hide: chat widgets, newsletter pop-ups, sticky headers...

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

Paper size for PDF output.

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

Landscape orientation for PDF.

## `pdfPrintBackground` (type: `boolean`):

Include background colors and images in the PDF.

## `pdfUseScreenMedia` (type: `boolean`):

Render the PDF with the on-screen CSS instead of the site's print CSS (looks more like the website).

## `pdfSinglePage` (type: `boolean`):

Produce a single tall PDF page as wide as the viewport, like a full-page screenshot but with selectable text. Ignores paper size.

## `pdfMargin` (type: `string`):

Margin on every side, with a CSS unit: '0', '10mm', '0.5in', '20px'.

## `captureErrorPages` (type: `boolean`):

By default pages answering with HTTP 4xx/5xx are reported as failed (not charged). Enable to capture them anyway (charged).

## `navigationTimeoutSecs` (type: `integer`):

Maximum time for loading a page and for waiting for the element.

## `maxRetries` (type: `integer`):

How many times a failed page is retried (timeouts, network errors, HTTP 429/5xx).

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

Pages processed at the same time. 2 is safe with the default 1 GB of memory; give the run 2 GB or more before going higher.

## `onlyNew` (type: `boolean`):

Skip URLs/HTML documents already captured successfully (same format) in a previous run with this option on. Remembered in the named key-value store 'website-screenshot-pdf-state'. Skipped files are not loaded and not charged. Leave off for monitoring snapshots of the same pages.

## `extractText` (type: `boolean`):

Also return the visible text of the page in 'pageText' (clean plain text, up to 100,000 characters), ready for LLMs, RAG and AI agents. No extra charge.

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://apify.com"
  ],
  "htmlName": "html",
  "formats": [
    "png"
  ],
  "fullPage": true,
  "jpegQuality": 80,
  "maxPageHeight": 20000,
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "deviceScaleFactor": 1,
  "device": "desktop",
  "colorScheme": "light",
  "waitUntil": "load",
  "delayMs": 1000,
  "scrollToBottom": true,
  "hideCookieBanners": true,
  "hideSelectors": [],
  "pdfFormat": "A4",
  "pdfLandscape": false,
  "pdfPrintBackground": true,
  "pdfUseScreenMedia": false,
  "pdfSinglePage": false,
  "pdfMargin": "0",
  "captureErrorPages": false,
  "navigationTimeoutSecs": 60,
  "maxRetries": 2,
  "maxConcurrency": 2,
  "onlyNew": false,
  "extractText": false
}
```

# Actor output Schema

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

All results, one item per record (dataset).

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

Files produced by the run (key-value store).

## `runPage` (type: `string`):

No description

## `overview` (type: `string`):

Main results as a table (dataset view).

# 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",
        "https://apify.com"
    ],
    "formats": [
        "png"
    ],
    "hideSelectors": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("actose/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",
        "https://apify.com",
    ],
    "formats": ["png"],
    "hideSelectors": [],
}

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

```

## MCP server setup

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