# Bulk Website Screenshot – Full Page, Mobile & ZIP (`chris_elder/bulk-website-screenshot`) Actor

Screenshot many websites at once: full-page or viewport, desktop and mobile, PNG, JPEG or WebP. Cookie banners hidden, a sitemap can be used as the URL list, and every capture is bundled in one ZIP. $3 per 1,000 screenshots ($5 from 7 Nov); failed captures are free.

- **URL**: https://apify.com/chris_elder/bulk-website-screenshot.md
- **Developed by:** [Chris Elder](https://apify.com/chris_elder) (community)
- **Categories:** Developer tools, SEO tools, Automation
- **Stats:** 2 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

## Bulk Website Screenshot – Full Page, Mobile & ZIP

Screenshot a list of websites, or every page in a sitemap, in one run. You get a full-page or viewport image of each page on desktop, laptop, tablet and mobile, and **one ZIP with every capture**, so you don't have to click through hundreds of image links.

**$3 per 1,000 screenshots** ($0.003 each). Pages that fail to load are free.

### What you can use it for

- **Website audits and agency reports:** capture every page of a client site on desktop and mobile in one go.
- **Before/after evidence:** snapshot pages before a redesign, migration or deploy.
- **Competitor and landing-page swipe files:** screenshot a list of competitor homepages or ads landing pages.
- **Visual QA on mobile:** spot broken layouts across a sitemap at iPhone-class size.
- **Archiving and compliance:** dated captures of pages, terms and pricing.

### How it works

1. Paste page URLs (full `https://` links), and/or a **sitemap URL**.
2. Pick devices: Desktop 1920×1080, Laptop 1366×768, Tablet 820×1180, Mobile 390×844.
3. Choose full-page or viewport, and PNG, JPEG or WebP.
4. Run. Cookie banners (OneTrust, Cookiebot, Didomi, Quantcast, Usercentrics and generic bars) are hidden, and the page is scrolled once so lazy images load.
5. Download `screenshots.zip` from the run's key-value store (the link is in the log and in `OUTPUT`), or open each image from the dataset table.

### Input example

```json
{
  "urls": [{ "url": "https://apify.com" }, { "url": "https://www.gov.uk" }],
  "sitemapUrl": "",
  "devices": ["desktop", "mobile"],
  "fullPage": true,
  "format": "jpeg",
  "quality": 80,
  "createZip": true
}
```

### Output

One dataset row per screenshot (page × device):

| Field | Example |
|---|---|
| `url` | `https://www.gov.uk/` |
| `device` | `mobile` |
| `status` | `ok` (or `captured-http-error` for 4xx/5xx pages, `failed` when nothing loaded) |
| `statusCode` | `200` |
| `title` | `Welcome to GOV.UK` |
| `screenshotUrl` | direct image link in the key-value store |
| `width` / `height` | `390` / `6120` |
| `bytes` | `412345` |
| `error` | only on failures |

`OUTPUT` record: `{ "screenshots": 4, "failed": 0, "pages": 2, "zipUrl": "https://api.apify.com/v2/key-value-stores/…/records/screenshots.zip" }`

### Pricing

**Price update:** from 7 Nov 2026 (06:30 UTC) the price per screenshot rises from $0.003 to $0.005 ($5 per 1,000 screenshots). Apify gives users 14 days' notice. The prices below apply until then.
Pay per event. You only pay for screenshots that were saved.

| Event | Price |
|---|---|
| Screenshot (one page on one device) | **$0.003** |
| Actor start | $0.00005 |

Worked examples: 100 pages on desktop + mobile = 200 screenshots = **$0.60**. A 1,000-page sitemap on desktop = **$3.00**. Set a maximum charge per run in Apify and the Actor stops cleanly when it is reached.

### Tips

- Use JPEG or WebP at quality 70–80 for long pages; files are 5–10× smaller than PNG.
- Very long pages are cut at 15,000 px by default (`maxFullPageHeight`). WebP full-page shots are capped at 10,000 image px (5,000 CSS px on mobile/tablet) because WebP encoding of very tall pages is slow; use JPEG for long pages.
- For heavy or slow sites, lower `maxConcurrency` or raise memory to 4 GB.
- Sites that need a login or that block automated browsers may show a challenge page instead of content; those still appear in the dataset so you can see what happened.

### FAQ

**Is it legal to screenshot websites?** Capturing publicly available pages is generally fine for audits, QA and research. Respect the site's terms and copyright when you reuse images; don't use it to capture content behind logins you're not authorised to access.

**Can I screenshot a whole site?** Yes. Paste its sitemap URL (for example `https://example.com/sitemap.xml`); indexes are followed one level, up to `maxPages`.

**Why is a page blank or showing a popup?** Some sites load content late. Raise `delayMs` to 3000–5000 or set `waitUntil` to `networkidle0`.

### Related Actors by the same developer

- [Bulk Image Downloader – download all images to ZIP](https://apify.com/chris_elder/bulk-file-downloader)
- [Sitemap URL Extractor](https://apify.com/chris_elder/sitemap-url-extractor)
- [Bulk Lighthouse & PageSpeed Checker](https://apify.com/chris_elder/lighthouse-batch-auditor)

Built and supported by GPT Shop Ltd (UK company 15766335). Issues or feature requests: use the Issues tab.

# Actor input Schema

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

Pages to capture. Use full URLs starting with https://.

## `sitemapUrl` (type: `string`):

Also capture the pages listed in this XML sitemap (sitemap indexes are followed one level). Limited by 'Max pages'.

## `maxPages` (type: `integer`):

Upper limit on pages captured (each device counts as a separate screenshot).

## `devices` (type: `array`):

One screenshot per page per device.

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

Capture the whole scrollable page instead of only the visible viewport.

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

PNG is lossless; JPEG/WebP are much smaller.

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

Ignored for PNG.

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

Page-load event to wait for before capturing.

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

Wait this long after load (for animations and lazy content).

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

Hides common consent banners (OneTrust, Cookiebot, Didomi, Quantcast and generic cookie bars) before capture.

## `scrollToLoadLazy` (type: `boolean`):

Scrolls through the page once so lazy-loaded images appear in full-page shots.

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

Very long pages are cut at this height.

## `createZip` (type: `boolean`):

Saves screenshots.zip to the key-value store with a download link in the run output.

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

Pages captured in parallel. Use more memory for higher values.

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

Per-page navigation timeout. Timed-out pages are reported and not charged.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://www.gov.uk"
    }
  ],
  "maxPages": 100,
  "devices": [
    "desktop",
    "mobile"
  ],
  "fullPage": true,
  "format": "png",
  "quality": 80,
  "waitUntil": "networkidle2",
  "delayMs": 1000,
  "hideCookieBanners": true,
  "scrollToLoadLazy": true,
  "maxFullPageHeight": 15000,
  "createZip": true,
  "maxConcurrency": 3,
  "timeoutSecs": 45
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `zip` (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": [
        {
            "url": "https://apify.com"
        },
        {
            "url": "https://www.gov.uk"
        }
    ],
    "devices": [
        "desktop",
        "mobile"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("chris_elder/bulk-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": [
        { "url": "https://apify.com" },
        { "url": "https://www.gov.uk" },
    ],
    "devices": [
        "desktop",
        "mobile",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("chris_elder/bulk-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": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://www.gov.uk"
    }
  ],
  "devices": [
    "desktop",
    "mobile"
  ]
}' |
apify call chris_elder/bulk-website-screenshot --silent --output-dataset

```

## MCP server setup

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