# Website Screenshot API: Full Page, Mobile and PDF (`joesimo/website-screenshot`) Actor

Take screenshots of any list of URLs as PNG, JPEG or PDF, at screen size or full page. Desktop, laptop, tablet or mobile view, cookie banners and ads hidden, lazy images loaded. Each row links to the file. Failed pages are free.

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

## Pricing

from $4.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, mobile and PDF captures of any URL list

**Paste a list of URLs, get back a screenshot of each page** as PNG, JPEG or PDF, with a download link in every row. Pick desktop, laptop, tablet or mobile view, capture the first screen or the whole scrollable page, and get clean pictures: cookie banners and ads are hidden and lazy images are loaded before the shot.

- **Pay per screenshot, failures free:** $0.004 per screen-size screenshot, $0.008 per full page screenshot or PDF. Pages that answer 404 or 403, time out or do not exist are saved with a status and cost nothing.
- **Clean captures:** consent pop-ups of common cookie tools (OneTrust, Cookiebot, Didomi, Usercentrics and more) are hidden with CSS (nothing is clicked or accepted), about 50 ad and tracker hosts are blocked, and the page is scrolled so lazy images appear.
- **Batch ready:** hundreds of URLs per run, pasted as a list or a column from a spreadsheet, captured in parallel. Every file gets a readable name like `0001-wikipedia.org.png`.

### Quick start

1. Click **Try for free**, keep the prefilled URLs (or paste your own) and press **Start**.
2. Or call the API with an empty input `{}`. It runs this demo:

```json
{
    "urls": ["https://www.wikipedia.org", "https://www.python.org"]
}
```

This run took 23 seconds in the Apify cloud on Nov 1, 2026 and saved 2 screenshots, so it costs 2 x $0.004 = $0.008 plus the run start fee. One of the 2 rows, unchanged:

```json
{
    "input": "https://www.python.org",
    "url": "https://www.python.org/",
    "finalUrl": "https://www.python.org/",
    "status": "ok",
    "httpStatus": 200,
    "title": "Welcome to Python.org",
    "screenshotUrl": "https://api.apify.com/v2/key-value-stores/Wqejq03XHYIoBqI47/records/0002-python.org.png?signature=clCKPev8pOgNkNCILE8W",
    "screenshotKey": "0002-python.org.png",
    "format": "png",
    "device": "desktop",
    "width": 1366,
    "height": 768,
    "pageHeight": 2581,
    "truncated": false,
    "bytes": 147754,
    "loadTimeMs": 890,
    "error": null,
    "takenAt": "2026-11-02T03:12:43.022Z",
    "charged": true
}
```

For whole pages, add `"fullPage": true`. On the same day a full page JPEG run on 7 mixed URLs took 37 seconds: bbc.com/news (6,561 px tall), github.com (7,673 px), stripe.com and theverge.com (cut at the 10,000 px default and marked `truncated`) were saved and charged; a 404 page, a dead domain and "not a url" were saved with their status for free.

### Pricing

| Event | Price | When |
|---|---|---|
| Screenshot | $0.004 ($4 per 1,000) | One page captured at screen size, or one element, as PNG or JPEG |
| Full page screenshot | $0.008 ($8 per 1,000) | One whole scrollable page as PNG or JPEG, or one PDF |
| Run start | $0.00005 per GB of memory | Once per run |

Only rows with `status: ok` are charged, and the `charged` field shows which ones were. HTTP errors (the capture is still saved), failed loads, timeouts and invalid URLs are free. The run stops cleanly when it reaches the maximum cost per run you set.

### Use cases

- **Website archives and change tracking:** a dated picture of your pages or competitors' pages every day or week.
- **Agency and SEO reports:** before and after shots of client sites on desktop and mobile.
- **Directory and link preview thumbnails:** a screen-size JPEG of every site in a list.
- **QA and visual checks:** see how each page renders on a phone, a tablet and a large desktop.
- **Compliance and evidence:** a PDF of a page with links and selectable text, plus the time it was taken.
- **Feeding AI and vision models:** page images for classification or design analysis.

### Example inputs

Copy one of these into the **JSON** tab of the input form.

**1. Full page PNG of each page, desktop.**

```json
{
    "urls": ["https://www.bbc.com/news", "https://github.com", "https://stripe.com"],
    "fullPage": true
}
```

**2. Mobile view, first screen, small JPEG files.** The mobile preset is an iPhone-sized 390 x 844 screen at 3x pixel density.

```json
{
    "urls": ["https://www.python.org", "https://www.wikipedia.org"],
    "device": "mobile",
    "format": "jpeg",
    "jpegQuality": 70
}
```

**3. Paste a column from a spreadsheet.** One URL per line or separated by commas. Missing `https://` is added.

```json
{
    "urlsText": "url\nwikipedia.org\nhttps://www.python.org/\ngithub.com, bbc.com/news"
}
```

**4. PDF of each page in A4.**

```json
{
    "urls": ["https://www.python.org/about/"],
    "format": "pdf",
    "pdfPageFormat": "A4"
}
```

**5. One element only, after it appears.** The capture is the element's box, billed as a screen-size screenshot.

```json
{
    "urls": ["https://github.com"],
    "selector": "header",
    "waitForSelector": "header"
}
```

**6. Custom screen size, dark mode, hide your own pop-up.**

```json
{
    "urls": ["https://github.com"],
    "viewportWidth": 1600,
    "viewportHeight": 1000,
    "darkMode": true,
    "hideSelectors": [".newsletter-modal"]
}
```

### Input

| Field | Description |
|---|---|
| `urls` | URLs to capture. `example.com` works, `https://` is added. |
| `urlsText` | Bulk paste: one URL per line, or separated by commas, spaces or semicolons. |
| `device` | `desktop` (1366 x 768, default), `desktop-hd` (1920 x 1080), `laptop` (1280 x 800), `tablet` (820 x 1180, 2x) or `mobile` (390 x 844, 3x). |
| `format` | `png` (default), `jpeg` or `pdf`. |
| `fullPage` | Capture the whole scrollable page instead of the first screen (off by default). |
| `maxHeight` | Full page captures stop at this height (default 10,000 px) and are marked `truncated`. |
| `jpegQuality` | 10 to 100 (default 80). |
| `viewportWidth` / `viewportHeight` / `deviceScaleFactor` | Override the device preset. |
| `hideCookieBanners` | Hide consent pop-ups with CSS (on by default). |
| `blockAds` | Block common ad and tracker hosts (on by default). |
| `scrollToLoad` | Scroll the page before a full page capture so lazy images load (on by default). |
| `darkMode` | Ask the site for its dark theme. |
| `hideSelectors` | Extra CSS selectors to hide, for example a chat widget. |
| `selector` | Capture only the first element matching this CSS selector. |
| `waitForSelector` | Wait for this element before capturing. |
| `waitUntil` | `load` (default), `domcontentloaded` or `networkidle`. |
| `delaySecs` | Extra wait before the capture, for animations (default 0). |
| `pdfPageFormat` | A4 (default), Letter, Legal or A3. |
| `timeoutSecs` | Page load timeout (default 30 seconds). |
| `maxConcurrency` | Pages in parallel. Automatic by default, based on memory. |
| `maxItems` | Stop after this many URLs (0 = no limit). |
| `dedupe` | Capture each URL once (on by default). |

### Output

One dataset row per URL, in the order the pages finish. The **Overview** view in the Console shows the screenshot right in the table. Key fields:

- `screenshotUrl`: a direct, signed link to the file that opens without an Apify token.
- `screenshotKey`: the file name in the run's key-value store.
- `status`: `ok`, `http_error` (the site answered 4xx or 5xx, the capture is saved but free), `failed` (DNS, connection, timeout or a crashed page) or `invalid_input`.
- `width`, `height`, `pageHeight`, `truncated`: what was captured and how tall the page really is.
- `title`, `finalUrl`, `httpStatus`, `bytes`, `loadTimeMs`, `takenAt`, `error`, `charged`.

The `OUTPUT` record of each run has a summary: files saved and charged, status counts, total megabytes and the options used.

**Download all files:** open the run's **Storage > Key-value store** tab, or list them with the API: `GET https://api.apify.com/v2/key-value-stores/{storeId}/keys`. Files are kept for your plan's data retention period, so copy what you need to keep.

### Use with the API, Make, Zapier or n8n

Call the Actor with the Apify API or a client library, for example with `curl`:

```bash
curl -X POST "https://api.apify.com/v2/acts/joesimo~website-screenshot/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://www.wikipedia.org"], "fullPage": true}'
```

The response is the list of rows, each with its `screenshotUrl`. The Actor also works from Make, Zapier and n8n through their Apify integrations, and as a tool through the Apify MCP server.

### FAQ

**Do I pay for pages that fail?**
No. Only `status: ok` rows are charged. A 404 or 403 page is still captured, so you can see what the site showed, but it is free.

**Why is a site marked `http_error` with a 403?**
Some large sites block cloud servers with bot protection. The Actor does not bypass it. In our tests on 20 big brand homepages, 3 answered 403 (nytimes.com, reddit.com, etsy.com).

**Does it log in or accept cookies?**
No. It captures what an anonymous visitor sees. Cookie banners are hidden with CSS, never accepted.

**How tall can a full page screenshot be?**
Up to 16,000 px (5,333 px on the 3x mobile preset), because browsers cannot paint more in one image. The default stops at 10,000 px.

**Is a full page screenshot of a long page slow?**
Most pages take 2 to 10 seconds. Very long pages with heavy animation can take 20 to 30 seconds. Raise the memory to 4 GB for faster runs on big lists.

### Honest limits

- **No login, no captcha solving, no bot protection bypass.** Private pages and sites that block cloud servers return `http_error` or `failed` for free.
- **Hidden with CSS, not removed:** a few custom pop-ups are not covered by the built-in list. Add their selectors to `hideSelectors`.
- **Video and audio are not loaded,** so video players show a placeholder.
- **Fixed headers** appear once at the top of full page captures, as in a browser.

### Responsible use

Capture pages you have a right to view and use. Screenshots can include personal data or copyrighted material shown on a page; you are responsible for how you store and share them.

### Support

Found a page that renders wrong or a pop-up that is not hidden? Open an issue on the Actor's Issues tab with the URL. Contact: joesimo@mail.grokbot.com

More examples and the docs for all 7 of our Actors: [github.com/Joe-Simo/apify-actors](https://github.com/Joe-Simo/apify-actors/tree/main/website-screenshot). Store page: https://apify.com/joesimo/website-screenshot

# Actor input Schema

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

Pages to capture. Full URLs or bare domains (https:// is added). One screenshot per URL.

## `urlsText` (type: `string`):

Paste many URLs at once, separated by new lines, commas or spaces. Merged with the list above.

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

Screen size and type. Desktop 1366x768, Full HD 1920x1080, Laptop 1280x800, Tablet 820x1180 at 2x, Mobile 390x844 at 3x (iPhone size, mobile user agent).

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

PNG is lossless, JPEG is 2 to 5 times smaller. PDF gives a printable document of the whole page with links and selectable text and is billed as Full page screenshot.

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

Capture the whole scrollable page, up to Max page height. Off (default) captures the first screen the visitor sees. Full page captures are billed as Full page screenshot, see Pricing.

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

Hide consent pop-ups of OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast, TrustArc and about 30 other tools with CSS. Nothing is clicked or accepted.

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

Skip requests to about 50 ad, tracking and analytics networks. Pages load faster and look cleaner.

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

10 to 100. Used only for JPEG.

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

Full page captures stop at this height, so endless feeds do not produce giant files. Taller pages are cut and marked truncated. On mobile (3x) the limit is 5,333 px because browsers cannot paint more than about 16,000 device pixels at once.

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

Override the device width in CSS pixels (240 to 3840).

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

Override the device height in CSS pixels (240 to 2160). This is the size of a viewport-only capture.

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

Override the device pixel ratio: 1, 2 (retina) or 3. Higher values make sharper and larger files.

## `delaySecs` (type: `integer`):

Extra wait after the page loads and settles, for sliders, charts and late content. Usually not needed: the Actor already waits for the load event and a short network quiet period.

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

Load event (default, capped at 12 seconds so pages with endless trackers still get captured), DOM ready (fastest) or network idle (slowest, for apps that fetch data after load).

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

Optional CSS selector to wait for before the capture, for example .price or #chart.

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

Optional CSS selector. The capture is cropped to the first matching element, for example header or #pricing.

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

CSS selectors to hide before the capture, for example chat widgets or newsletter pop-ups.

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

Scroll down the page before a full page capture so lazy-loaded images appear.

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

Ask the page for its dark color scheme (works on sites that support prefers-color-scheme).

## `pdfPageFormat` (type: `string`):

Used only for PDF.

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

Give up on a page after this long. Timed out pages are free.

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

Pages captured in parallel. Default depends on memory: screen-size captures run 2 at 1 GB, 4 at 2 GB, 8 at 4 GB; full page and PDF captures run 1 at 1 GB, 2 at 2 GB, 4 at 4 GB, 8 above. Tall pages need about 500 MB each.

## `maxItems` (type: `integer`):

Stop after this many URLs. 0 means no limit.

## `dedupe` (type: `boolean`):

Capture each URL once even if it is listed several times.

## Actor input object example

```json
{
  "urls": [
    "https://www.wikipedia.org",
    "https://www.python.org",
    "https://www.bbc.com/news"
  ],
  "device": "desktop",
  "format": "png",
  "fullPage": false,
  "hideCookieBanners": true,
  "blockAds": true,
  "jpegQuality": 80,
  "maxHeight": 10000,
  "delaySecs": 0,
  "waitUntil": "load",
  "scrollToLoad": true,
  "darkMode": false,
  "pdfPageFormat": "A4",
  "timeoutSecs": 30,
  "maxItems": 0,
  "dedupe": true
}
```

# Actor output Schema

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

One item per URL: status, page title, size and a direct link to the screenshot file.

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

All PNG, JPEG or PDF files of the run, one record per URL.

## `runSummary` (type: `string`):

Counts by status, screenshots charged, total megabytes and the options used.

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

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

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

```

## MCP server setup

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