# Bulk Website Screenshot - Full Page PNG/JPEG from URL List (`tinyrex/bulk-website-screenshot`) Actor

Screenshot many URLs in one run: full-page or viewport, PNG/JPEG, desktop/mobile, cookie banners hidden, public image links. $0.002/screenshot ($2/1k), no compute fees; failed URLs free.

- **URL**: https://apify.com/tinyrex/bulk-website-screenshot.md
- **Developed by:** [TinyRex](https://apify.com/tinyrex) (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 $1.60 / 1,000 screenshot saveds

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

## Bulk Website Screenshot: full-page PNG/JPEG screenshots from a URL list

**Take screenshots of hundreds of web pages in one run** for **$0.002 per screenshot ($2 per 1,000), with no compute fees on top**. Paste a list of URLs and get one PNG or JPEG per page, full-page or viewport-only, on a desktop, laptop, tablet or mobile viewport. Cookie banners are hidden automatically. **Unreachable pages, timeouts and HTTP errors are free.**

### What you get from Bulk Website Screenshot

- **One image per URL**: PNG (lossless) or JPEG (3-10x smaller), saved in the run's key-value store with a ready-to-open public `screenshotUrl` in the dataset.
- **Full-page or viewport**: full-page shots scroll first so lazy images load, and are capped at a max height you choose so endless feeds don't create giant files.
- **Clean shots**: common consent popups (OneTrust, Cookiebot, Didomi, Quantcast, Usercentrics, TrustArc and generic cookie bars) are hidden with CSS, so nothing is clicked or accepted. Add your own selectors for chat widgets or promos.
- **Device presets**: Desktop 1920x1080, Laptop 1366x768, Tablet 768x1024, Mobile 390x844 (2x retina, mobile user agent) or any custom size.
- **A status row for every URL**: `statusCode`, `title`, `finalUrl` after redirects, image size and load time, plus a clear `error` when a page couldn't be captured.

### Sample output (JSON)

```json
{
  "input": "https://example.com",
  "url": "https://example.com/",
  "finalUrl": "https://example.com/",
  "statusCode": 200,
  "title": "Example Domain",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/MdP7oCEqlqnxkARdq/records/example-com-b559c7edd3.png?signature=...",
  "screenshotKey": "example-com-b559c7edd3.png",
  "format": "png",
  "device": "desktop",
  "width": 1920,
  "height": 1080,
  "fullPage": false,
  "bytes": 64221,
  "loadTimeMs": 1626,
  "charged": true,
  "error": null,
  "takenAt": "2026-10-17T07:30:00.000Z"
}
```

Export the dataset as **CSV, Excel or JSON**, or send it to Google Sheets, Google Drive, Make, Zapier, n8n, webhooks or the Apify API. The `screenshotUrl` column opens the image directly.

### How to configure Bulk Website Screenshot

1. Paste **URLs**, one per line. Bare domains like `example.com` work too.
2. Pick **Full page** or viewport-only, a **Device**, and **PNG or JPEG**.
3. Run. Each saved screenshot is one charge; everything that fails is free.

#### Example input

```json
{
  "urls": ["https://example.com", "https://apify.com"],
  "fullPage": true,
  "device": "desktop",
  "format": "jpeg",
  "jpegQuality": 80,
  "hideCookieBanners": true,
  "delaySecs": 1
}
```

| Setting | Default | Notes |
|---|---|---|
| urls | (required) | Pages you supply; duplicates removed |
| fullPage | false | Whole scrollable page, clipped at `maxFullPageHeight` (10,000 px) |
| device | desktop | desktop, laptop, tablet, mobile or custom (`viewportWidth` x `viewportHeight`) |
| format | png | `png` or `jpeg` (with `jpegQuality`) |
| hideCookieBanners | true | Hides consent popups with CSS; nothing is accepted |
| hideSelectors | \[] | Extra CSS selectors to hide |
| waitUntil | load | `domcontentloaded`, `load` or `networkidle` |
| delaySecs | 1 | Extra wait after load for animations |
| maxConcurrency | 3 | Pages in parallel (3 fits the default 2 GB memory) |
| pageTimeoutSecs | 30 | Page load timeout; slow third-party scripts don't block the shot once the page itself has loaded |
| maxScreenshots | 0 | Optional cap per run (0 = no cap) |
| proxyConfiguration | off | Optional Apify Proxy, e.g. to see a page from another country |

### Common use cases

- **Website monitoring and archiving**: schedule a daily run and keep dated snapshots of your own or competitors' landing pages.
- **SEO and agency reports**: before/after shots of every page in a sitemap during a redesign or migration.
- **Lead lists and directories**: add a homepage thumbnail to each company row in a CRM or spreadsheet.
- **QA**: check how pages look on mobile vs desktop in one batch.
- **Pipelines with TinyRex**: [Sitemap Scraper](https://apify.com/tinyrex/sitemap-scraper) gives you every URL, this Actor captures them, and [SEO On-Page Audit](https://apify.com/tinyrex/seo-on-page-audit) checks the tags.

### Pricing (failed = free)

Pay per event, platform usage included:

- **Screenshot** (`screenshot`): $0.002 per image saved, which is **$2 per 1,000 screenshots**. Bronze, Silver and Gold plans get tier discounts.
- **Free:** DNS errors, refused connections, timeouts, file downloads and pages that answer with HTTP 4xx/5xx (no image is taken).
- A tiny `apify-actor-start` event is charged once per run.

Set a max cost per run; the Actor stops gracefully when it's reached.

### Limitations

- Pages behind a login, paywall or bot wall (CAPTCHA) can't be captured. Try a proxy for sites that block datacenter IPs.
- Cookie hiding uses CSS for common providers; rare custom banners may still show. Add their selector to `hideSelectors`.
- Image links live as long as your plan keeps run storage (7 days on the free plan). Download them or send them to your own storage if you need them longer.
- Full-page shots of very long pages are clipped at `maxFullPageHeight`.

### FAQ: Bulk Website Screenshot

**How do I screenshot every page of a website?**
Run [Sitemap Scraper](https://apify.com/tinyrex/sitemap-scraper) to get all URLs, then pass its `url` field into `urls` (strings or `{ "url": "..." }` objects both work).

**Can I take a full-page screenshot of a long page?**
Yes. Turn on **Full page**. The Actor scrolls once to load lazy images and captures up to `maxFullPageHeight` pixels (default 10,000, max 30,000). Retina presets are capped at 16,000 image pixels tall, which is 8,000 CSS pixels on mobile and tablet, because Chromium can't render taller images.

**How do I get mobile screenshots?**
Set **Device** to `mobile` (390x844 at 2x, mobile user agent) or `tablet`. For both versions of each page, run twice with different devices.

**Do failed URLs cost anything?**
No. You only pay for screenshots that are actually saved. Errors still get a dataset row so you can see what went wrong.

**How do I save screenshots to Google Drive or S3?**
Use the dataset's `screenshotUrl` column in Make, Zapier or n8n to download each image and upload it, or use an Apify integration on run success.

**Does it work with AI agents / MCP?**
Yes. Connect Claude, Cursor, VS Code, n8n or any MCP client to `https://mcp.apify.com?tools=tinyrex/bulk-website-screenshot` and ask e.g. *"Take full-page screenshots of https://example.com and https://apify.com"*.

### Related actors

- [Sitemap Scraper](https://apify.com/tinyrex/sitemap-scraper): every URL from XML sitemaps, the ideal input list
- [SEO On-Page Audit](https://apify.com/tinyrex/seo-on-page-audit): title, meta, H1, canonical and schema for the same URLs
- [Broken Link Checker](https://apify.com/tinyrex/broken-link-checker): find 404s and redirect chains across a site
- [Tech Stack Detector](https://apify.com/tinyrex/tech-stack-detector): which CMS, analytics and frameworks each site uses

Built by **TinyRex**. Questions or feature requests? Open an issue on the Actor page.

# Actor input Schema

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

Pages to screenshot. Full URLs or bare domains (example.com becomes https://example.com). Duplicates are removed. One charge per screenshot saved; unreachable pages and HTTP errors are free.

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

Capture the whole scrollable page instead of only the visible viewport. Very long pages are cut at the max height below.

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

Viewport preset. 'custom' uses the width and height below.

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

Only used when Device is 'custom'.

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

Only used when Device is 'custom'.

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

PNG is lossless; JPEG files are 3-10x smaller.

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

1-100, only for JPEG.

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

Full-page screenshots are clipped to this height so endless pages don't produce huge files.

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

Hide common cookie/consent popups (OneTrust, Cookiebot, Didomi, Quantcast, Usercentrics and generic ones) with CSS before the shot. Nothing is clicked or accepted.

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

Optional selectors to hide before the screenshot, e.g. chat widgets: #intercom-container, .drift-frame-controller

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

Which page event to wait for before the shot. 'load' works for most sites; 'networkidle' waits for late-loading content but is slower.

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

Wait this long after the page loads, e.g. for animations or lazy images.

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

For full-page shots: scroll down once before capturing so lazy-loaded images appear.

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

How many pages are captured at the same time. 3 is a good fit for the default 2 GB memory. Heavy full-page shots on 1 GB can time out; raise memory to go faster.

## `pageTimeoutSecs` (type: `integer`):

Give up on a page after this long (free).

## `maxScreenshots` (type: `integer`):

Optional cap on how many screenshots one run saves (0 = no cap).

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

Optional proxy, e.g. to see a page from another country or for sites that block datacenter IPs.

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://apify.com"
  ],
  "fullPage": false,
  "device": "desktop",
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "format": "png",
  "jpegQuality": 80,
  "maxFullPageHeight": 10000,
  "hideCookieBanners": true,
  "hideSelectors": [],
  "waitUntil": "load",
  "delaySecs": 1,
  "scrollToBottom": true,
  "maxConcurrency": 3,
  "pageTimeoutSecs": 30,
  "maxScreenshots": 0,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per URL with the screenshot link.

## `images` (type: `string`):

Key-value store with the PNG/JPEG files.

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

Totals for the 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"
    ]
};

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

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

```

## MCP server setup

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