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

Screenshot any URL as PNG, JPEG, WebP or PDF: full page or viewport, desktop, tablet or mobile, or one element by CSS selector. Hides cookie banners, loads lazy images, retries slow pages. Returns a public file link per URL. $3 per 1,000 screenshots; failed URLs are free.

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

## Pricing

from $3.00 / 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.

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, WebP & PDF

**Website Screenshot API** captures any web page as a PNG, JPEG, WebP or PDF file. Paste URLs, get back a public link to each screenshot plus its status, title, size and load time, as JSON, CSV or Excel:

- ✅ **Full-page or viewport** screenshots, or **one element** by CSS selector.
- ✅ **PNG, JPEG, WebP or PDF**, with adjustable JPEG/WebP quality.
- ✅ **Device presets**: desktop (1920x1080), tablet (iPad) and mobile (iPhone, with mobile user agent and touch), or any custom width and height.
- ✅ **Cookie banners hidden**: OneTrust, Cookiebot, Usercentrics, Didomi, Quantcast and dozens more.
- ✅ **Lazy content**: optional scroll-through so lazy images and sections render before a full-page capture.
- ✅ **Reliable**: a page that times out is retried once with a lighter load condition, and one bad URL never fails the run.
- ✅ **Fast**: one shared browser, a fresh context per page, pages captured in parallel.
- ✅ **Pay only for screenshots that work.** Failed URLs are recorded with the reason, for free.

### Start in one minute

Click **Start** with the prefilled input:

```json
{
  "urls": ["https://apify.com"]
}
```

You get: A desktop (1920x1080) PNG of apify.com's visible viewport, with `screenshotUrl`, `title`, `width`, `height` and `loadTimeMs`.

**Cost:** $0.003: 1 screenshot × $0.003, plus the $0.00005 actor-start fee.

### Use with an AI assistant

Connect the [Apify MCP server](https://mcp.apify.com) to Claude, ChatGPT, Cursor or any MCP client (`https://mcp.apify.com?tools=cprussin/website-screenshot` loads only this actor), then paste:

```text
Use the Apify actor cprussin/website-screenshot to take full-page mobile screenshots of https://apify.com and https://apify.com/pricing, and give me the image links.
```

### Recipes

#### Full-page mobile PDFs

Whole pages as PDFs on a phone viewport, after lazy content loads.

```json
{
  "urls": ["https://apify.com", "https://apify.com/pricing"],
  "format": "pdf",
  "fullPage": true,
  "device": "mobile",
  "scrollToBottom": true
}
```

#### Social preview images

1200x630 JPEGs, the usual link-preview size.

```json
{
  "urls": ["https://apify.com"],
  "width": 1200,
  "height": 630,
  "format": "jpeg",
  "quality": 85
}
```

#### Just one element

Capture only the element that matches a CSS selector.

```json
{
  "urls": ["https://example.com"],
  "selector": "h1"
}
```

#### Pages that load late

Wait for the network to go quiet, then 1 second more.

```json
{
  "urls": ["https://apify.com"],
  "waitUntil": "networkidle",
  "delayMs": 1000,
  "fullPage": true
}
```

### Who uses a website screenshot API?

- **Developers**: thumbnails, link previews and OG images for apps and dashboards.
- **QA and design teams**: visual checks of pages on desktop, tablet and mobile.
- **SEO and marketing**: archive competitor landing pages, pricing pages and ads.
- **Compliance and legal**: timestamped PDF or image proof of what a page showed.
- **AI agents**: give a vision model a picture of any page through the Apify API or MCP server.

### How does the website screenshot actor work?

1. Add one or more URLs and pick a format, device and options.
2. The actor opens each URL in headless Chromium, waits for the page to load (and for your selector, if set), hides cookie banners and optionally scrolls through the page.
3. It saves the screenshot or PDF to the run's key-value store and writes one dataset item per URL with a public link to the file.
4. If a page doesn't finish loading in time, it's retried once with a lighter load condition (Network idle → Load → DOM ready). If it still fails, you get an item with the error and aren't charged.

Only the URLs you give are loaded. The actor doesn't crawl or follow links.

### How do I set up website screenshots?

| Field                | Description                                               | Example                            |
| -------------------- | --------------------------------------------------------- | ---------------------------------- |
| `urls`               | Pages to capture (`https://` is added if missing)         | `["https://apify.com"]`            |
| `startUrls`          | Same, in Apify request-list format (combined with `urls`) | `[{ "url": "https://apify.com" }]` |
| `format`             | `png`, `jpeg`, `webp` or `pdf`                            | `"pdf"`                            |
| `fullPage`           | Whole scrollable page instead of the viewport             | `true`                             |
| `device`             | `desktop`, `tablet` or `mobile`                           | `"mobile"`                         |
| `width` / `height`   | Custom viewport size in px (overrides the device preset)  | `1440` / `900`                     |
| `quality`            | JPEG/WebP quality, 1-100 (default 80)                     | `70`                               |
| `waitUntil`          | `load` (default), `domcontentloaded` or `networkidle`     | `"networkidle"`                    |
| `delayMs`            | Extra wait after load, in ms                              | `1000`                             |
| `waitForSelector`    | CSS selector to wait for before capturing                 | `"#main"`                          |
| `selector`           | Capture only this element                                 | `".pricing-table"`                 |
| `hideCookieBanners`  | Hide common cookie-consent banners (default on)           | `true`                             |
| `scrollToBottom`     | Scroll through the page first so lazy content loads       | `true`                             |
| `timeoutSecs`        | Max load time per URL (default 30)                        | `60`                               |
| `maxConcurrency`     | Pages captured in parallel (default 3)                    | `5`                                |
| `proxyConfiguration` | Optional Apify Proxy, e.g. for geo-specific pages         | `{ "useApifyProxy": true }`        |

### What data do you get for each screenshot?

```json
{
  "url": "https://apify.com/",
  "finalUrl": "https://apify.com/",
  "status": 200,
  "screenshotKey": "screenshot-0001-apify-com.png",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/aBcD1234eFgH5678/records/screenshot-0001-apify-com.png",
  "format": "png",
  "device": "desktop",
  "width": 1920,
  "height": 1080,
  "bytes": 202501,
  "title": "Apify: Marketplace of ready-to-run tools for AI",
  "loadTimeMs": 2310,
  "waitUntil": "load",
  "error": null,
  "capturedAt": "2026-10-02T00:00:00.000Z"
}
```

- `screenshotUrl` is a direct link to the file; `screenshotKey` is its key in the run's default key-value store.
- `width`/`height` are the image size in pixels (tablet and mobile render at 2x, so a 390 px mobile viewport gives a 780 px wide image). For PDFs they are the page size in CSS px.
- `waitUntil` is the load condition that worked; it's lighter than requested when the first attempt timed out.
- A failed URL has `error` set (e.g. `net::ERR_NAME_NOT_RESOLVED` or a timeout), no file, and isn't billed.
- Pages that return 404 or 500 are still captured (that's what the page shows); check `status`.

### How much does a website screenshot cost?

Pay-per-event, only for successful screenshots:

| Event      | Price      |
| ---------- | ---------- |
| Screenshot | **$0.003** |

That's **$3 per 1,000 screenshots or PDFs**, any format or size. Failed URLs are free. The default input (one screenshot of apify.com) costs $0.003. If you set a **maximum cost per run**, the actor stops cleanly when it reaches it.

### Tips for website screenshots

- **Full-page screenshots of modern sites:** turn on `scrollToBottom` so lazy-loaded images appear, and add `delayMs` (500-2000) for animations.
- **Slow or chatty pages:** `load` is the best default. `networkidle` waits for all network activity to stop, which some sites never do; the actor then falls back to `load` automatically.
- **Smaller files:** use `jpeg` or `webp` with `quality` 60-80. WebP pages taller than 16,383 px are saved as PNG (a WebP format limit).
- **Thumbnails:** capture the viewport only (`fullPage: false`) with a small custom `width`/`height`.
- **Many URLs:** raise `maxConcurrency` together with the run's memory (about 1 GB per 2-3 parallel pages).
- **Scheduled monitoring:** schedule the actor and compare `bytes` or the images between runs, or send the links to Slack or Google Drive with Apify integrations.

### Website screenshot FAQ

**How is this different from the free screenshot actor?** It's built for reliability and volume: a timed-out page is retried with a lighter load condition, one failed URL never fails the run, every result says why it failed, and you're only charged for screenshots that worked. It also does full-page PDFs, WebP, device presets, element capture and cookie-banner hiding.

**Can I screenshot a page behind a login?** No. The actor opens each URL as a logged-out visitor.

**Why is a cookie banner still visible?** Banners are hidden with CSS by matching known consent tools. Unusual or custom banners may stay visible. Nothing is clicked, so no consent is given on your behalf.

**Why did a page time out?** Some sites load slowly or block datacenter traffic. Increase `timeoutSecs`, use `waitUntil: "domcontentloaded"`, or enable Apify Proxy.

**How long are the files kept?** In the run's default key-value store, for your account's data retention period. Download them or copy them elsewhere if you need them longer.

**Can I use it through the API or with AI agents?** Yes. Call it through the Apify API, the Apify MCP server or any Apify integration, then fetch the image from `screenshotUrl`.

**Disclaimer:** You are responsible for having the right to capture and use screenshots of the pages you request, and for complying with each site's terms and applicable laws.

### Related actors

- [PDF to Markdown Converter](https://apify.com/cprussin/document-to-markdown?fpr=to54nm): PDF, Word, PowerPoint, Excel and EPUB to Markdown or RAG chunks.
- [Video Frame Extractor](https://apify.com/cprussin/video-frame-extractor?fpr=to54nm): Thumbnails, scene keyframes, contact sheets and GIFs from video files.
- [Google Ads Transparency Scraper](https://apify.com/cprussin/google-ads-transparency?fpr=to54nm): Competitor ads from the Google Ads Transparency Center by advertiser or domain.

# Actor input Schema

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

Pages to capture, one per line, e.g. <code>https://apify.com</code>. <code>https://</code> is added when missing. Only these URLs are loaded; no links are followed. Each successful screenshot is billed as one event; failed URLs are free.

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

Optional alternative to URLs, in Apify's request-list format (e.g. from another actor or a file). Combined with URLs.

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

Image format, or PDF (a vector PDF of the page with backgrounds).

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

Capture the whole scrollable page instead of just the viewport. For PDF, renders the whole page as one tall page.

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

Viewport preset. Desktop: 1920x1080. Tablet: 820x1180 at 2x (iPad). Mobile: 390x844 at 2x (iPhone), with a mobile user agent and touch.

## `width` (type: `integer`):

Overrides the device preset's viewport width.

## `height` (type: `integer`):

Overrides the device preset's viewport height.

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

JPEG and WebP quality, 1-100. Lower is smaller.

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

When the page counts as loaded. If it times out, the actor retries once with the next lighter option (Network idle → Load → DOM ready → first response).

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

Wait this long after the page loads, e.g. for animations or late content.

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

Optional CSS selector to wait for before capturing, e.g. <code>#main</code>. The URL fails if it doesn't appear within the timeout.

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

Optional CSS selector: capture only the first matching element (e.g. <code>header</code> or <code>.pricing-table</code>) instead of the page. Ignored for PDF.

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

Hide common cookie-consent banners (OneTrust, Cookiebot, Usercentrics, Didomi, Quantcast and more) with CSS. Best-effort; nothing is clicked.

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

Scroll through the page before capturing so lazy-loaded images and sections render. Useful with Full page.

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

Max time to load each page (and to wait for selectors).

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

Pages captured in parallel. 3 fits the default 2 GB memory; raise memory for more.

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

Optional Apify Proxy, e.g. for sites that block datacenter IPs or to capture a page from another country. Off by default.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com"
  ],
  "format": "png",
  "fullPage": false,
  "device": "desktop",
  "quality": 80,
  "waitUntil": "load",
  "delayMs": 0,
  "hideCookieBanners": true,
  "scrollToBottom": false,
  "timeoutSecs": 30,
  "maxConcurrency": 3
}
```

# Actor output Schema

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

No description

# 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"
    ]
};

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

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

```

## MCP server setup

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