# Website Screenshot & PDF: full page, mobile, element, WebP (`angadseth/website-screenshot`) Actor

Screenshots (PNG, JPEG, WebP) and PDFs of any list of URLs. Full page or viewport, a CSS element or a clip, desktop/tablet/iPhone/Android presets, dark mode, cookie-banner and ad hiding, lazy-load scrolling. Each file gets a link, final URL, title, HTTP status and size.

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

## Pricing

$2.00 / 1,000 screenshot or pdfs

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, element, WebP

Give it a list of URLs. For each page you get a **PNG, JPEG or WebP screenshot** and/or a **PDF**, saved to the run's key-value store, plus one dataset record per file. Each record has the **file link**, the final URL after redirects, the page title, the HTTP status, the image size in pixels, the file size, the format, the device and a timestamp.

A page that fails does not crash the run and is not charged. You get the reason for each failed page in the `FAILED` and `SUMMARY` records.

### Who uses it

- **SEO and marketing agencies**: client reports, competitor homepages, landing-page archives, before/after shots.
- **Monitoring and archiving**: schedule a daily run to keep a visual history of pages, or keep PDFs as evidence.
- **AI agents**: an agent that needs to see a page calls this Actor through the Apify MCP server and gets an image link back.
- **Thumbnails and previews**: link previews, directories, galleries, social-card sized clips.

### Features

| Option | What it does |
|---|---|
| Output | Screenshot, PDF, or both for each page |
| Format | PNG (lossless), JPEG or WebP with a quality setting |
| Area | Full page (default), visible viewport, **one element by CSS selector**, or a **clip rectangle** |
| Devices | Desktop 1920x1080, Laptop 1440x900, Tablet (iPad Pro 11, @2x), iPhone 15 Pro (@3x), Android Pixel 7 (@2.625x), or custom width, height and scale factor |
| Waiting | `load`, `domcontentloaded` or `networkidle`, extra delay, wait for a selector. A page that never gets to the chosen state is still captured, with a warning |
| Lazy content | Scrolls through the page before a full-page shot or PDF so lazy images load, then goes back to the top |
| Clean shots | Hides cookie banners from common consent tools (CSS only, **never clicks accept**), hides your own selectors, blocks ads and trackers (optional), injects custom CSS, reduces motion |
| Look | Dark mode (`prefers-color-scheme: dark`), language/locale, custom user agent |
| PDF | A4, Letter, Legal, A3, A5, Tabloid; landscape; background colours; margins; scale; on-screen or print stylesheet |
| Reliability | Per-page timeout, retries in a fresh tab, browser restarted if it crashes, optional Apify Proxy, 1 to 10 pages at a time |

### Example inputs

Full-page PNG of two sites on desktop (the default):

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

iPhone screenshots in dark mode as small WebP files, ads blocked:

```json
{
  "urls": ["https://github.com", "https://www.bbc.com/news"],
  "device": "iphone",
  "format": "webp",
  "quality": 75,
  "darkMode": true,
  "blockAds": true
}
```

A 1200x630 social-card image at Retina sharpness:

```json
{
  "urls": ["https://stripe.com"],
  "clip": { "x": 0, "y": 0, "width": 1200, "height": 630 },
  "deviceScaleFactor": 2,
  "format": "jpeg"
}
```

Only the pricing table, after it has rendered:

```json
{ "urls": ["https://example.com/pricing"], "selector": "#pricing", "waitForSelector": "#pricing table" }
```

Screenshot and PDF for archiving, A4 with 1 cm margins and the site's print layout:

```json
{ "urls": ["https://en.wikipedia.org/wiki/Screenshot"], "output": "both", "pdfFormat": "A4", "pdfMargin": "1cm", "pdfMedia": "print" }
```

### Output

One record per saved file (a page with "Screenshot and PDF" gives two records). This is a real record from a test run:

```json
{
  "url": "https://en.wikipedia.org/wiki/Screenshot",
  "finalUrl": "https://en.wikipedia.org/wiki/Screenshot",
  "title": "Screenshot - Wikipedia",
  "httpStatus": 200,
  "type": "screenshot",
  "format": "webp",
  "fileUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/en-wikipedia-org-wiki-screenshot-0ef58d5d.webp",
  "key": "en-wikipedia-org-wiki-screenshot-0ef58d5d.webp",
  "storeId": "<storeId>",
  "fileSizeBytes": 300526,
  "width": 1179,
  "height": 6966,
  "sizeUnit": "px",
  "pages": null,
  "captureArea": "fullPage",
  "pageWidth": 393,
  "pageHeight": 2322,
  "truncated": false,
  "device": "iphone",
  "viewportWidth": 393,
  "viewportHeight": 852,
  "deviceScaleFactor": 3,
  "isMobile": true,
  "darkMode": false,
  "loadTimeMs": 1148,
  "cookieBannersHidden": 0,
  "blockedRequests": null,
  "attempts": 1,
  "warnings": [],
  "error": null,
  "capturedAt": "2026-11-05T16:11:54.520Z"
}
```

| Field | What it is |
|---|---|
| `fileUrl`, `key`, `storeId` | Link to the file in the run's key-value store, its key and the store ID. On Apify the link is signed when your storage is private, so it opens without a token |
| `url`, `finalUrl`, `title`, `httpStatus` | The page you asked for, where it ended up after redirects, its title and the HTTP status (error pages are captured too, with a warning) |
| `type`, `format` | `screenshot` or `pdf`; `png`, `jpeg`, `webp` or `pdf` |
| `width`, `height`, `sizeUnit` | Image size in real pixels (read from the file), or the PDF page size in points |
| `pages` | Number of PDF pages |
| `captureArea`, `pageWidth`, `pageHeight`, `truncated` | What was captured, the page size in CSS pixels, and whether the image was cut at Max page height |
| `device`, `viewportWidth`, `viewportHeight`, `deviceScaleFactor`, `isMobile`, `darkMode` | The device used |
| `loadTimeMs`, `cookieBannersHidden`, `blockedRequests`, `attempts`, `warnings` | How the capture went |

Run a local copy and `fileUrl` is a `file://` path to the file in local storage instead.

`SUMMARY` (key-value store) has the counts, total bytes, the device, warnings and every failed URL with its reason. `FAILED` has a full record for each failed page. Turn on **Add failed pages to the dataset** to get them in the dataset as well; each one then counts as a result.

### Pricing

You pay per file saved: one screenshot or one PDF is one result. Failed pages cost nothing. Your URL list caps the cost of a run: at most one result per page, or two with "Screenshot and PDF".

### Limits

- WebP images are at most 16,383 px on each side. Longer pages are cut at that height, with a warning. Use PNG or JPEG for very long pages.
- Full-page shots stop at **Max page height** (default 20,000 CSS px) so endless-scroll pages do not make giant files.
- Pages behind a login, a captcha or bot protection are captured as they look to a visitor who is not logged in. The Actor does not log in or solve captchas.
- Some pages scroll inside an inner box instead of the page itself. A full-page shot of those shows the visible window.
- The cookie-banner hider covers the common consent tools and banners that mention cookies or consent. A rare custom banner may stay; add its selector to **Hide elements**.

### Schedules, webhooks and integrations

- **Visual monitoring**: save the input as a Task and add a Schedule (for example daily). Every run keeps its own files.
- **Google Sheets, Slack, Zapier, Make, n8n**: send the records (with the image links) wherever you need them from the Integrations tab.
- **Webhooks**: get a call when a run finishes, then read the dataset or the files through the API.
- **MCP / AI agents**: the Actor works as a tool in the Apify MCP server, so an agent can ask for "a mobile screenshot of this page" and get a link back.

### FAQ

**Is this legal?** The Actor opens public web pages the way a normal browser does and saves what a visitor would see. It does not log in, solve captchas or get around paywalls or bot protection. Cookie banners are only hidden from the image; nothing is clicked or accepted for you. You are responsible for how you use the captures and for respecting the sites' terms and copyright.

**Why does my full-page shot look cut off?** The page was taller than **Max page height** (the record says `truncated: true`), or it is a WebP over 16,383 px. Raise the limit or use PNG.

**Images or sections are missing.** Keep **Scroll to load lazy content** on, try **Wait until: networkidle**, add an **Extra delay**, or wait for a specific element with **Wait for element**.

**A site shows a different page or blocks the run.** Some sites show other content to data-centre visitors. Turn on Apify Proxy (residential, or a country) in **Proxy**.

**How do I download all the files at once?** Open the run's key-value store in the Console, or list the keys through the API (`/v2/key-value-stores/{storeId}/keys`) and fetch each `fileUrl`.

**Something broke?** Open an issue on the Issues tab with the URL and your input, and it will be fixed quickly.

### More Actors by angadseth

- [GeM Tenders Scraper (India Government e-Marketplace Bids)](https://apify.com/angadseth/gem-tenders-scraper): Get live GeM bids and reverse auctions from India's Government e-Marketplace
- [India eProcurement Tenders Scraper (CPPP + 30 State Portals)](https://apify.com/angadseth/india-eprocurement-tenders): Live government tenders from India's central eProcure (CPPP), central PSU, defence and 30+ state NIC eProcurement portals in one run.
- [Apple App Store Scraper: apps, ratings and reviews](https://apify.com/angadseth/app-store-scraper): Get Apple App Store apps, ratings and customer reviews from many countries in one run
- [ATS Jobs Feed: Greenhouse, Lever, Ashby, Workday + 5 more](https://apify.com/angadseth/ats-jobs-feed): Get every open job from a company's own careers board
- [Bluesky Scraper: Posts, Profiles, Followers and Feeds](https://apify.com/angadseth/bluesky-scraper): Scrape Bluesky without a login
- [Website Contact Enricher: Emails, Phones, Socials per Domain](https://apify.com/angadseth/website-contact-enricher): One clean lead row per company domain
- [Remote Jobs Aggregator: RemoteOK, Jobicy, Arbeitnow + 2 more](https://apify.com/angadseth/remote-jobs-aggregator): Remote jobs from RemoteOK, Jobicy, Arbeitnow, Working Nomads and 4 Day Week in one clean feed.
- [PDF & Document Text Extractor: PDF, DOCX, PPTX, XLSX to Text](https://apify.com/angadseth/pdf-text-extractor): Turn public document URLs (PDF, DOCX, PPTX, XLSX, CSV, HTML, TXT) into clean text

# Actor input Schema

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

Pages to capture, one per line, e.g. https://example.com. A missing https:// is added. Repeated URLs are captured once.

## `output` (type: `string`):

A screenshot, a PDF, or both for every page. Each saved file is one result.

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

PNG is sharp and lossless. JPEG and WebP are much smaller; set their quality below. WebP images can be at most 16,383 px tall.

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

1 to 100. Ignored for PNG.

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

Screen size, pixel density, touch and user agent of a real device. The viewport fields below override the size and density of any preset.

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

Overrides the device width. Leave empty to use the device preset.

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

Overrides the device height (the visible area; a full-page shot is taller). Leave empty to use the device preset.

## `deviceScaleFactor` (type: `number`):

Pixel density, e.g. 2 for a Retina-sharp image twice the size. Leave empty to use the device preset.

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

Capture the whole scrollable page. Off = only the visible viewport.

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

Full-page shots stop at this height (CSS px), so endless pages do not make giant files. The record says truncated: true when the page was cut.

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

Screenshot one element instead of the page, e.g. "#pricing" or "main h1". The first visible match is used. A page with no match is reported as failed (and not charged).

## `clip` (type: `object`):

Capture a fixed rectangle of the page in CSS pixels from the top-left corner, e.g. {"x": 0, "y": 0, "width": 1200, "height": 630} for a social-card sized image. Ignored when an element selector is set.

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

When the page counts as loaded. If a page never gets there (busy sites never go network-quiet), it is still captured once the time runs out, with a warning.

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

Wait this long after loading, before capturing, e.g. for animations or charts.

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

Wait until this element is visible before capturing, e.g. ".chart canvas". If it never appears, the page is captured anyway with a warning.

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

Before a full-page shot or PDF, scroll down the page step by step so lazy images and sections load, then go back to the top.

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

Hide cookie and consent pop-ups of common consent tools (OneTrust, Cookiebot, Didomi, Quantcast, Usercentrics and more) with CSS. Nothing is ever clicked, so no consent is given on your behalf.

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

Elements to remove before capturing, one CSS selector per line, e.g. ".chat-widget" or "#newsletter-popup".

## `blockAds` (type: `boolean`):

Do not load requests to a built-in list of about 90 ad and tracking domains. Pages load faster and ad slots stay empty.

## `darkMode` (type: `boolean`):

Tell the page the device prefers a dark colour scheme (prefers-color-scheme: dark). Sites that support dark mode show it.

## `customCss` (type: `string`):

CSS added to every page before capturing, e.g. "header { position: static !important; }".

## `reducedMotion` (type: `boolean`):

Ask pages to turn off animations (prefers-reduced-motion) and freeze CSS animations at capture time, for sharper and repeatable shots.

## `userAgent` (type: `string`):

Custom user agent string. Leave empty to use the device preset (desktop presets use current Chrome).

## `locale` (type: `string`):

Browser language, e.g. "de-DE" or "hi-IN"; sites that adapt to the language show it. Default en-US.

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

Paper size of the PDF pages.

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

Landscape pages instead of portrait.

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

Keep background colours and images in the PDF, like on screen.

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

Margin on all four sides, e.g. "1cm", "10mm", "0.5in" or "20px". 0 = edge to edge.

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

"As on screen" makes the PDF look like the website. "Print" uses the site's own print layout, often simpler and without menus.

## `pdfScale` (type: `number`):

Zoom of the page content in the PDF, 0.1 to 2.

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

The most time one attempt at one page may take, from opening to saving the file.

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

How many more times to try a page that fails (in a fresh browser tab, with a new proxy session if a proxy is used). Pages that do not exist are not retried.

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

How many pages to capture in parallel. 3 is safe at 2 GB memory; give more memory before going higher.

## `includeFailedInDataset` (type: `boolean`):

Off (default): failed pages are listed in the FAILED and SUMMARY records of the key-value store and are not charged. On: they are also added to the dataset with an error field, and each counts as a result.

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

Optional. Use Apify Proxy (for example residential, or a country) when a site shows a different page to data-centre visitors.

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://apify.com"
  ],
  "output": "screenshot",
  "format": "png",
  "quality": 80,
  "device": "desktop",
  "fullPage": true,
  "maxPageHeight": 20000,
  "waitUntil": "load",
  "delayMs": 500,
  "scrollToBottom": true,
  "hideCookieBanners": true,
  "blockAds": false,
  "darkMode": false,
  "reducedMotion": true,
  "pdfFormat": "A4",
  "pdfLandscape": false,
  "pdfPrintBackground": true,
  "pdfMargin": "0px",
  "pdfMedia": "screen",
  "pdfScale": 1,
  "timeoutSecs": 60,
  "maxRetries": 2,
  "maxConcurrency": 3,
  "includeFailedInDataset": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One record per saved file with its link, final URL, title, HTTP status, size and device, as JSON, CSV or Excel.

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

All screenshots and PDFs of this run, stored as records in the run's key-value store.

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

Counts, failed URLs with the reason, and warnings from this run.

# 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"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("angadseth/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://example.com",
        "https://apify.com",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

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

```

## MCP server setup

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