# Website Screenshot API: Full Page, Mobile & Bulk Capture (`plainrows/website-screenshot`) Actor

Take website screenshots in bulk: full page or viewport, desktop, tablet or mobile size, PNG, JPEG, WebP or PDF, dark mode, cookie banners hidden. Get a public image link, HTTP status and page title for each URL. Pay only per successful screenshot.

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

## Pricing

from $1.80 / 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.
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, Mobile & Bulk Capture

Take **website screenshots in bulk** from a list of URLs: **full-page or viewport**, **desktop, laptop, tablet or mobile** size, **PNG, JPEG, WebP or PDF**, retina scale, **dark mode**, with **cookie banners and ads hidden**. Each URL returns a public link to the image plus its HTTP status, page title and final URL after redirects.

A real Chromium browser renders every page on Apify, no API key or setup needed. **You pay for screenshots taken, plus a small start fee per run**: unreachable sites, HTTP error pages, blank pages and invalid URLs are not charged.

### Typical uses

- **Website monitoring and archiving**: schedule daily captures of your pages or competitors' home pages and keep a visual history.
- **SEO and marketing reports**: thumbnails of landing pages, SERP competitors or client sites, in bulk.
- **QA and responsive checks**: the same URLs on desktop, tablet and mobile, light and dark mode.
- **Link previews and directories**: generate thumbnails for a list of websites.
- **AI agents and automations**: give an agent eyes on a web page through one API call or MCP.

### What you get for each URL

| Field | Description |
|---|---|
| `url`, `finalUrl` | The URL you submitted and the address after redirects |
| `success`, `errorCode`, `error` | Whether the screenshot was taken (and billed); otherwise why not: `DNS_NOT_RESOLVED`, `TIMEOUT`, `HTTP_ERROR`, `BLANK_PAGE`, `SSL_ERROR`, `SELECTOR_NOT_FOUND`, `INVALID_URL`, `BLOCKED_ADDRESS`... |
| `screenshotUrl`, `screenshotKey` | Link to the image file and its key in the run's key-value store |
| `format`, `width`, `height`, `bytes` | Image format and real pixel size and file size |
| `statusCode`, `title` | HTTP status and page title |
| `fullPage`, `pageHeight`, `truncated` | Full-page mode, full page height (CSS px), and whether a very long page was cut at the height limit |
| `device`, `viewportWidth`, `viewportHeight`, `deviceScaleFactor`, `darkMode` | Rendering settings used |
| `cookieBannerHidden` | A known consent banner was found and hidden |
| `waitTimedOut` | The page was still loading at the wait limit; the screenshot was taken anyway |
| `pdfUrl`, `pdfKey` | A4 PDF of the page when `savePdf` is on |
| `takenAt` | When the screenshot was taken (UTC) |

Every input URL that is processed gets exactly one row, so you can match results to your list. URLs left out by the run's maximum cost, the free-plan limit or the 5,000-URL cap get no row; the run's OUTPUT counts them (`skippedBudgetLimit`, `urlsSkippedFreePlan`, `urlsOverLimit`). Missing values are `null`.

### Input

```json
{
  "urls": ["https://example.com", "https://www.wikipedia.org", "apify.com/store"],
  "device": "desktop",
  "fullPage": false,
  "format": "png",
  "blockCookieBanners": true,
  "blockAds": true,
  "darkMode": false,
  "delayMs": 500
}
```

- **urls**: up to 5,000 per run; `example.com` is read as `https://example.com`. Duplicates are removed.
- **device**: `desktop` (1440 x 900), `laptop` (1366 x 768), `tablet` (820 x 1180, touch, mobile user agent), `mobile` (390 x 844, touch, mobile user agent) or `custom` with **width**, **height** and **isMobile**.
- **fullPage**: capture the whole page; it is scrolled first so lazy images load. Pages taller than **maxHeight** (default 10,000 px) are cut and flagged `truncated`; images are capped at 25 megapixels.
- **format**: `png`, `jpeg` or `webp`, with **quality** 1-100 for JPEG and WebP. **deviceScaleFactor** 2 or 3 for retina images. **savePdf** also saves an A4 PDF.
- **Waiting**: `waitUntil` (`load` by default, `networkidle`, or `domcontentloaded`), **delayMs** extra wait, **waitForSelector** to wait for an element, **timeoutSecs** (default 30). Web fonts and visible images are awaited automatically (up to 3 s).
- **Clean-up**: **blockCookieBanners** and **blockAds** (on by default), **hideSelectors** for anything else (chat widgets, newsletter pop-ups).

### Output example

Real row from a run on 2026-10-07 (desktop viewport, default settings):

```json
{
  "url": "https://www.wikipedia.org/",
  "success": true,
  "errorCode": null,
  "error": null,
  "finalUrl": "https://www.wikipedia.org/",
  "statusCode": 200,
  "title": "Wikipedia",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/kJl6N78QocoRdJrdP/records/screenshot-wikipedia-org-72e64cab.png?signature=XISlxJNp7GoeBgskiliU",
  "screenshotKey": "screenshot-wikipedia-org-72e64cab.png",
  "format": "png",
  "width": 1440,
  "height": 900,
  "bytes": 152786,
  "fullPage": false,
  "pageHeight": null,
  "truncated": false,
  "device": "desktop",
  "viewportWidth": 1440,
  "viewportHeight": 900,
  "deviceScaleFactor": 1,
  "darkMode": false,
  "cookieBannerHidden": false,
  "waitTimedOut": false,
  "pdfUrl": null,
  "pdfKey": null,
  "takenAt": "2026-10-07T15:36:35.500Z",
  "schemaVersion": "1.0"
}
```

Files are stored in the run's key-value store. The links work without an API token for as long as Apify keeps the run's storage (see your plan's data retention): download the files you want to keep, or send them to your own storage with an integration.

### Pricing

Pay per screenshot taken, no subscription and no proxy fees. See the **Pricing** tab for current prices: one event per **screenshot taken**, cheaper on higher Apify plans. Full page, mobile, retina, dark mode, WebP and the optional PDF are included in that price: there is no add-on per option. A small start fee is charged per run ($0.002 per GB of memory, $0.004 at the default 2 GB). Pages that fail (timeouts, error pages) are free; if a run keeps failing on them, it stops early and says so.

Free: URLs that fail (domain not found, timeout, connection or certificate errors), pages answering an HTTP error (404, 403, 500...: the error page is still captured), blank pages (often bot challenges), invalid or duplicate URLs. The run never spends more than the maximum cost you set.

**Free Apify plan:** up to 5 URLs per run, so you can check the output. A paid Apify plan removes this limit.

### Use it from code, automations or AI agents

**API (one call, results returned directly):**

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

**n8n, Make, Zapier:** use the Apify integration, pick `plainrows/website-screenshot`, then send `screenshotUrl` to Slack, Google Drive, Notion or your database.

**AI agents (MCP):** add `https://mcp.apify.com?tools=plainrows/website-screenshot` to Claude, Cursor or any MCP client. The agent gets a typed screenshot tool and pays per screenshot.

### What this is not

- **No login, no proxies, no anti-bot bypass.** Pages are loaded from Apify's servers without proxies. Sites behind a bot challenge (some large news and e-commerce sites) may return their challenge page: when it answers an HTTP error or renders blank, it is free; a challenge page answered with a success code can still be captured and billed.
- **Cookie banners are hidden, not accepted.** The banners of the common consent platforms (OneTrust, Cookiebot, Didomi, Quantcast, Usercentrics, TrustArc, Sourcepoint, consentmanager, CookieYes, Complianz, Osano and others) are hidden with CSS. Home-made banners with unusual markup may remain: add them to `hideSelectors`. Content that waits for consent (some embedded videos or maps) may stay empty.
- **Ad blocking is a short list** of the main ad and analytics networks, not a full ad blocker. Blocked ad slots can show as empty boxes.
- Private and internal addresses (localhost, private IP ranges, cloud metadata) are refused.
- Not a visual diff or monitoring service by itself: combine it with a schedule and your own storage.

### Run summary

Each run stores a summary in the key-value store (`OUTPUT`): screenshots taken, failed URLs by error code, HTTP error pages, blank pages, invalid and duplicate URLs, and anything skipped because of the free-plan or budget limit.

### FAQ

**How do I take screenshots of many websites at once?**
Paste up to 5,000 URLs, pick the device and format, and run: each URL returns a public link to the image, plus its HTTP status, page title and final URL.

**Can I capture the full page or a mobile view?**
Yes: **fullPage** scrolls and captures the whole page (up to **maxHeight**), and **device** offers desktop, laptop, tablet, mobile or a custom size.

**Can it hide cookie banners and ads?**
Yes, on by default: banners of the common consent platforms are hidden (not accepted), and the main ad networks are blocked. Use **hideSelectors** for anything else.

**Can I get a PDF?**
Yes: **savePdf** also saves an A4 PDF of each page.

**Does it work on pages behind a login or a bot challenge?**
No: no login, no proxies and no anti-bot bypass.

### More PlainRows tools

Same pay-per-result pricing, same clean JSON, built to chain together in n8n, Make, Zapier or AI agents.

- **SEO and keywords:** [Keyword Search Volume, CPC & Difficulty](https://apify.com/plainrows/keyword-search-volume) · [Keyword Ideas Generator](https://apify.com/plainrows/keyword-ideas-generator) · [Google Autocomplete & People Also Ask](https://apify.com/plainrows/google-autocomplete-questions) · [Google Trends Explorer](https://apify.com/plainrows/google-trends-explorer) · [Website Organic Traffic & Top Keywords](https://apify.com/plainrows/domain-seo-overview) · [Bulk Domain Authority Checker](https://apify.com/plainrows/domain-authority-checker) · [Backlink Checker](https://apify.com/plainrows/backlink-checker) · [Broken Link Checker](https://apify.com/plainrows/broken-link-checker) · [AI Search Visibility Tracker (ChatGPT, Gemini, AI Mode)](https://apify.com/plainrows/ai-search-brand-visibility) · [Google Maps Rank Tracker (Geo-Grid Local SEO)](https://apify.com/plainrows/google-maps-rank-tracker)
- **Leads and companies:** [Google Maps Scraper](https://apify.com/plainrows/google-maps-businesses) · [Website Technology Checker](https://apify.com/plainrows/website-tech-stack) · [ATS Jobs Scraper (Workday, Greenhouse, Lever, Ashby)](https://apify.com/plainrows/ats-job-postings) · [Google Jobs Scraper](https://apify.com/plainrows/google-jobs-scraper) · [Google Ads Scraper (Transparency Center)](https://apify.com/plainrows/google-ads-transparency) · [Company Registry Lookup (SIRENE, LEI, Brreg)](https://apify.com/plainrows/company-registry-lookup) · [Public Tenders Search (EU TED & UK)](https://apify.com/plainrows/public-tenders-search)
- **E-commerce and travel:** [Amazon Product Search Scraper](https://apify.com/plainrows/amazon-product-search) · [Google Shopping Prices Scraper](https://apify.com/plainrows/google-shopping-prices) · [Google Hotels Prices Scraper](https://apify.com/plainrows/google-hotels-prices) · [Tripadvisor Reviews Scraper](https://apify.com/plainrows/tripadvisor-reviews)
- **Content and media:** [Google News Scraper](https://apify.com/plainrows/google-news-scraper) · [YouTube Search Scraper](https://apify.com/plainrows/youtube-search-scraper) · [YouTube Comments Scraper](https://apify.com/plainrows/youtube-comments-scraper) · [Google Images Scraper](https://apify.com/plainrows/google-images-scraper) · [Google Maps Reviews Scraper](https://apify.com/plainrows/google-maps-reviews) · [App Store & Google Play Reviews Scraper](https://apify.com/plainrows/app-reviews-scraper)

### Support

Missing an option or found a site that renders badly? Open an issue on this page with the URL and your settings. Issues are read and answered.

# Actor input Schema

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

Web pages to capture, one per line. "example.com" is read as "https://example.com". Up to 5,000 URLs per run; duplicates are removed.

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

Screen size used to render the page. Tablet and mobile use a mobile browser user agent and touch, so sites serve their mobile layout.

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

Capture the whole scrollable page instead of only the visible screen. The page is scrolled first so lazy-loaded images appear.

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

PNG is pixel-perfect; JPEG and WebP files are several times smaller.

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

Compression quality for JPEG and WebP (ignored for PNG).

## `blockCookieBanners` (type: `boolean`):

Hide consent pop-ups of the common consent platforms (OneTrust, Cookiebot, Didomi, Quantcast, Usercentrics, TrustArc and others). Banners are hidden, not accepted.

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

Block requests to the main ad and analytics networks: faster pages, cleaner screenshots. Ad slots may show as empty boxes.

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

Render with prefers-color-scheme: dark, for sites that offer a dark theme.

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

Additional wait after the page has loaded (fonts and visible images are already awaited), for animations, sliders and late content.

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

When the page counts as loaded. The page load event is awaited at most 10 s and network idle at most 15 s; after that the screenshot is taken anyway and waitTimedOut is true.

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

Optional. Wait until this element is visible, e.g. "#main" or ".product-grid". If it never appears, the URL fails and is not charged.

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

Optional. Elements to hide before the capture: chat widgets, ads, popups, e.g. "#intercom-container", ".newsletter-popup".

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

Maximum time to load a page. Slow or unreachable pages fail (free) after this.

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

Viewport width when Device is "Custom size".

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

Viewport height when Device is "Custom size".

## `isMobile` (type: `boolean`):

With "Custom size": use a mobile user agent and touch.

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

1 = standard, 2 = retina, 3 = high-end phones. 2 doubles width and height of the image (4 times the pixels) for sharp retina screenshots.

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

Longer pages are cut at this height (truncated is true). Images are also capped at 25 megapixels, so retina full-page captures are cut earlier.

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

Scroll through the page before a full-page capture so lazy-loaded images and sections render.

## `savePdf` (type: `boolean`):

Also save an A4 PDF of each page (screen styles, backgrounds included), linked in pdfUrl. Included in the price.

## `ignoreHttpsErrors` (type: `boolean`):

Capture sites with expired or self-signed certificates (staging servers).

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://www.wikipedia.org"
  ],
  "device": "desktop",
  "fullPage": false,
  "format": "png",
  "quality": 80,
  "blockCookieBanners": true,
  "blockAds": true,
  "darkMode": false,
  "delayMs": 500,
  "waitUntil": "load",
  "timeoutSecs": 30,
  "width": 1440,
  "height": 900,
  "isMobile": false,
  "deviceScaleFactor": 1,
  "maxHeight": 10000,
  "scrollToBottom": true,
  "savePdf": false,
  "ignoreHttpsErrors": false
}
```

# Actor output Schema

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

No description

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

No description

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

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

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

```

## MCP server setup

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