# Website Screenshot API: Full-Page, Mobile & PDF (`datawright-labs/website-screenshot`) Actor

Capture full-page or viewport screenshots of any list of URLs as PNG, JPEG or PDF. Desktop, laptop, tablet and mobile presets, dark mode, wait-for-selector, and built-in ad and cookie-banner blocking. Returns a shareable image URL per page.

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

## Pricing

from $1.20 / 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

Capture **screenshots of any list of URLs** as **PNG, JPEG or PDF**: **full-page** or viewport only, on **desktop, laptop, tablet and mobile** presets or a custom size, with **dark mode**, **wait-for-selector**, and built-in **cookie banner and ad blocking** so your captures look clean. Every screenshot is stored in the run's key-value store and returned with a **shareable URL** in the dataset.

### What does this website screenshot tool do?

- Bulk screenshots: paste hundreds of URLs, get one image per URL per viewport.
- **Viewport presets**: Desktop 1920×1080, Laptop 1366×768, Tablet 810×1080 (2× retina), Mobile 390×844 (iPhone 13, 3× retina, mobile user agent), or a custom width × height, with an optional pixel-density override (1x–3x).
- **Full-page screenshots** of the entire scrollable page, with optional **auto-scroll** so lazy-loaded images appear.
- **Formats**: PNG (lossless), JPEG (adjustable quality) or **PDF** (paper size or one long full-page PDF).
- **Hide cookie banners** using community filter lists plus built-in rules for common consent platforms (OneTrust, Cookiebot, Usercentrics, Quantcast, Didomi, TrustArc, CookieYes and others).
- **Block ads and trackers** for faster, cleaner captures.
- **Dark mode** (`prefers-color-scheme: dark`), **wait for a CSS selector**, extra delay, and **hide any element** by CSS selector (chat widgets, popups).
- Parallel capture, automatic **retries**, and a clear **error per URL** (DNS failure, timeout, selector not found) instead of a failed run.
- Optional **proxy** support, e.g. to capture country-specific versions of a page.

### Use cases

- **Visual archiving & compliance**: keep dated screenshots or PDFs of web pages, ads or terms pages.
- **SEO & marketing reports**: thumbnails of landing pages, competitor pages or SERP destinations.
- **QA & responsive design checks**: see each page on desktop, tablet and mobile at once.
- **Link previews & directories**: generate thumbnails for a list of websites.
- **Monitoring**: schedule daily captures of pages you care about.

### Input

| Field | Description | Default |
|---|---|---|
| `urls` | URLs to capture | `["https://example.com"]` |
| `viewports` | `desktop`, `laptop`, `tablet`, `mobile`, `custom` | `["desktop"]` |
| `fullPage` | Capture the full scrollable page | `false` |
| `format` | `png`, `jpeg` or `pdf` | `png` |
| `darkMode` | Emulate dark color scheme | `false` |
| `waitUntil` | `load`, `domcontentloaded`, `networkidle` | `load` |
| `waitForSelector` | Wait for an element before capture | – |
| `delayMs` | Extra wait in ms | `1000` |
| `scrollToBottom` | Trigger lazy loading | `false` |
| `blockCookieBanners` / `blockAds` | Clean-up options | `true` / `true` |
| `hideSelectors` | Extra elements to hide | – |
| `proxyConfiguration` | Optional proxy | none |

Example input:

```json
{
  "urls": ["https://apify.com", "https://example.com"],
  "viewports": ["desktop", "mobile"],
  "fullPage": true,
  "format": "png",
  "scrollToBottom": true,
  "blockCookieBanners": true
}
```

### Output

Each capture is saved to the run's default key-value store, and the dataset gets one row per URL × viewport:

```json
{
  "url": "https://example.com/",
  "finalUrl": "https://example.com/",
  "status": "ok",
  "httpStatus": 200,
  "pageTitle": "Example Domain",
  "viewport": "desktop",
  "width": 1920,
  "height": 1080,
  "deviceScaleFactor": 1,
  "fullPage": false,
  "format": "png",
  "darkMode": false,
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/example.com-desktop-1a2b3c4d.png",
  "key": "example.com-desktop-1a2b3c4d.png",
  "fileSizeKb": 79,
  "durationMs": 1830,
  "attempts": 1,
  "takenAt": "2026-10-19T03:51:02.000Z"
}
```

`screenshotUrl` opens the image directly in a browser (if your account restricts storage access, the URL includes a signature). Failed captures are kept with `status: "error"`, an `errorType` and an `error` message.

Files follow your account's data retention for run storages. Download or copy them elsewhere (e.g. with the Google Drive, S3 or Dropbox integrations) if you need them long term.

### Example tasks

Copy one of these into the JSON tab of the input (or save it as a Task) to get started quickly.

**Full-page desktop + mobile screenshots with cookie banners removed**

```json
{
  "urls": [
    "https://apify.com",
    "https://example.com"
  ],
  "viewports": [
    "desktop",
    "mobile"
  ],
  "fullPage": true,
  "blockCookieBanners": true
}
```

**Save web pages as A4 PDFs**

```json
{
  "urls": [
    "https://en.wikipedia.org/wiki/Web_scraping"
  ],
  "format": "pdf",
  "pdfPaperFormat": "A4"
}
```

**Dark-mode JPEG thumbnails of a list of sites**

```json
{
  "urls": [
    "https://github.com",
    "https://vercel.com"
  ],
  "viewports": [
    "laptop"
  ],
  "format": "jpeg",
  "jpegQuality": 70,
  "darkMode": true
}
```

### How much does the website screenshot API cost?

You pay per successful capture; failed captures are free.

| Job | Cost |
|---|---|
| 1 run start (default 2 GB memory) | $0.003 (charged once per run, $0.0015 per GB) |
| 100 viewport screenshots (PNG/JPEG) | **$0.15** |
| 1,000 viewport screenshots | **$1.50** |
| 1,000 full-page screenshots or PDFs | **$5** |
| 1,000 URLs × desktop + mobile viewport | **$3** |

- Apify's **free plan includes $5 of monthly credit**: about **3,000 viewport screenshots a month for free**.
- Paid Apify plans get automatic discounts: **Silver -10%**, **Gold and above -20%**.
- Batch many URLs in one run: the start fee is paid once per run, not per URL.
- Set **Maximum cost per run** to hard-cap spend.

### Website screenshot API vs. the alternatives

| | This Actor | Running Puppeteer/Playwright yourself | Screenshot API SaaS |
|---|---|---|---|
| Bulk: hundreds of URLs per call | ✅ | DIY queue + retries | usually one URL per call |
| Full-page, viewport and PDF | ✅ | ✅ | ✅ |
| Cookie-banner + ad blocking built in | ✅ | DIY | sometimes, often paid tier |
| Mobile (iPhone 3×), tablet, laptop, custom presets | ✅ | DIY | ✅ |
| Hosted image URL per capture | ✅ | DIY storage | ✅ |
| Cost model | $1.50 per 1,000, no subscription | servers + your time | monthly plan |

### Use it as an API (Python, JavaScript, cURL, MCP)

Every Apify Actor is also a REST API, so you can call this website screenshot API from your own code, a no-code tool or an AI agent.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("datawright-labs/website-screenshot").call(run_input={"urls": ["https://example.com"], "fullPage": true})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

#### JavaScript / Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('datawright-labs/website-screenshot').call({"urls": ["https://example.com"], "fullPage": true});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### cURL (run and get results in one request)

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

#### AI agents (MCP)

Add `https://mcp.apify.com/?tools=datawright-labs/website-screenshot` to Claude, Cursor or any MCP client and the agent can run it as a tool.

Results can also go straight to **Google Sheets, Slack, Make, Zapier, n8n, Airbyte or a webhook** via Apify integrations, and you can run it on a **Schedule**.

### FAQ

#### Are all cookie banners removed?

Most common ones are, but not every site. Banners that are part of the page's own code can still slip through; add their selector to `hideSelectors`.

#### Why does dark mode not change some sites?

Dark mode emulates the browser's `prefers-color-scheme: dark` setting. Only sites that ship a dark theme respond to it.

#### Can I capture pages behind a login?

Not in this version.

#### Why is my full-page screenshot cut off or missing images?

Turn on `scrollToBottom` and increase `delayMs` so lazy-loaded content can load. Very long pages are cut at `maxFullPageHeight` (default 15,000 CSS px, and at most 24,000 device pixels, i.e. 8,000 CSS px with the 3x mobile preset) to avoid browser crashes; such rows have `fullPageTruncated: true`. Set the pixel density to 1 to capture more of a long page on mobile.

#### Can I take screenshots on a schedule?

Yes. Use Apify Schedules and integrations to send the images to Slack, Google Drive, S3 or a webhook.

#### Is there a free website screenshot API?

Apify's free plan includes $5 of monthly credit, which covers about 3,000 screenshots with this Actor, and you call it over a normal REST API (see below).

#### How do I take full-page screenshots of many URLs at once?

Paste the URLs, set `fullPage: true` and turn on `scrollToBottom` for lazy-loaded pages. Each capture is saved with a shareable URL in the dataset.

#### Can I convert a URL to PDF?

Yes. Set the format to `pdf` to get one PDF per page (paper size or one long full-page PDF).

### More tools from Datawright Labs

- [Bulk PageSpeed & Core Web Vitals Checker](https://apify.com/datawright-labs/pagespeed-auditor): audit PageSpeed / Lighthouse scores for many URLs.
- [Sitemap URL Extractor](https://apify.com/datawright-labs/sitemap-url-extractor): get every URL of a site from its sitemaps.
- [Google Autocomplete Keyword Scraper](https://apify.com/datawright-labs/autocomplete-keyword-scraper): long-tail keyword ideas from Google, YouTube and Bing.
- [Greenhouse, Lever & Ashby Jobs Scraper](https://apify.com/datawright-labs/ats-jobs-scraper): normalized job feeds from 5 ATS platforms.
- [Broken Link Checker](https://apify.com/datawright-labs/broken-link-checker): find broken links, images and redirects across a whole site.
- [App Store Top Charts & Rank Tracker](https://apify.com/datawright-labs/app-store-top-charts): daily top free/paid/grossing app rankings with rank changes.

Tip: get every page of a site with the **Sitemap URL Extractor**, then screenshot them all in one run.

Made by **Datawright Labs**: reliable, fairly priced web data tools. Questions or a missing feature? Open an issue on the Issues tab; we usually reply within a day.

# Actor input Schema

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

Pages to capture, one per line. URLs without a scheme get https:// added.

## `viewports` (type: `array`):

Each URL is captured once per selected viewport. desktop = 1920x1080, laptop = 1366x768, tablet = 810x1080 (iPad, 2x), mobile = 390x844 (iPhone 13, 3x, mobile user agent). Choose custom to use the width/height below.

## `customWidth` (type: `integer`):

Used with the custom viewport.

## `customHeight` (type: `integer`):

Used with the custom viewport.

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

0 = use the preset's density (tablet 2x, mobile 3x, others 1x). Set 1 for smaller files, 2 for retina-quality desktop captures.

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

Capture the whole scrollable page instead of just the visible viewport. For PDF this produces a single long page.

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

PNG (lossless), JPEG (smaller files) or PDF.

## `maxFullPageHeight` (type: `integer`):

Full-page captures of extremely long pages are cut at this height (CSS pixels) to avoid browser crashes. At 2x/3x pixel density the cap is also limited to 24,000 device pixels (e.g. 8,000 CSS px on the 3x mobile preset). Truncated rows get fullPageTruncated = true.

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

Only for JPEG.

## `pdfPaperFormat` (type: `string`):

Only for PDF without full-page mode.

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

Emulates prefers-color-scheme: dark. Only sites that support a dark theme will change.

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

Navigation event to wait for before capturing.

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

Optional. Wait until this element is visible before capturing, e.g. #main or .product-grid.

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

Extra wait after the page is ready, for animations and late content.

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

Scroll through the page before capturing so lazy-loaded images appear. Recommended with full-page capture.

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

Hide cookie/consent pop-ups using community filter lists plus built-in rules for common consent platforms. Most, not all, banners are removed.

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

Block ad and tracker requests (EasyList / EasyPrivacy based).

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

Extra elements to hide, e.g. chat widgets: #intercom-container

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

Max time for navigation, selector wait and capture.

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

Pages captured in parallel. Full-page and mobile (3x) captures of long pages use a lot of memory; raise memory before raising this.

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

Retries for timeouts and transient errors. DNS errors are not retried.

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

Optional. Use a proxy to capture geo-specific versions of pages or avoid blocking.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://example.com"
  ],
  "viewports": [
    "desktop"
  ],
  "customWidth": 0,
  "customHeight": 0,
  "deviceScaleFactor": 0,
  "fullPage": false,
  "format": "png",
  "maxFullPageHeight": 15000,
  "jpegQuality": 80,
  "pdfPaperFormat": "A4",
  "darkMode": false,
  "waitUntil": "load",
  "delayMs": 1000,
  "scrollToBottom": false,
  "blockCookieBanners": true,
  "blockAds": true,
  "hideSelectors": [],
  "timeoutSecs": 60,
  "maxConcurrency": 2,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `screenshots` (type: `string`):

Dataset rows with screenshot preview, file URL, viewport, HTTP status and errors.

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

All captured PNG/JPEG/PDF files in the default key-value store (keys also listed in the dataset 'key' column).

# 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",
        "https://example.com"
    ],
    "viewports": [
        "desktop"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

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

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

```

## MCP server setup

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