# Bulk Website Screenshot: Full-Page & Mobile (`blond_terrarium/bulk-website-screenshot`) Actor

Take reliable screenshots of any list of public URLs: full-page, viewport, mobile/tablet or a single element. Lazy-load scrolling, cookie-banner hiding, auto-retries. Pay only for successful screenshots; failed URLs are never charged.

- **URL**: https://apify.com/blond_terrarium/bulk-website-screenshot.md
- **Developed by:** [Mogul Tools](https://apify.com/blond_terrarium) (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.75 / 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

## Bulk Website Screenshot API: Full-Page, Mobile & Element Screenshots (Pay Only for Success)

Turn any list of public URLs into clean, full-page screenshots, with retries, lazy-load scrolling and cookie-banner hiding built in. **You're only charged for screenshots that actually worked.** Timeouts, DNS errors, HTTP 4xx/5xx and anti-bot challenge pages are logged in the dataset with the reason, and they're free.

Use it as a **website screenshot API**, a **bulk URL to PNG/JPEG converter**, a **full-page screenshot tool** for SEO and QA, or a **visual tool for AI agents** (via the Apify MCP server). Paste URLs, click Start, download the images.

### Quick start (about 1 minute)

1. Paste your URLs into **URLs** (one per line; `example.com` works too).
2. Pick a **Device / viewport** (desktop, laptop, tablet, mobile or custom) and keep **Full-page screenshot** on.
3. Click **Start**. Open the **Screenshots** view in the Output tab to preview, or export the list as CSV/Excel/JSON with direct image links.

### What can it do?

- 📸 **Full-page or viewport** screenshots of up to thousands of URLs per run
- 📱 **Device emulation**: desktop 1920×1080, laptop 1366×768, tablet, iPhone-size mobile (retina), or any custom size
- 🎯 **Element screenshots**: capture just `#pricing`, `header`, `main`, or any CSS selector
- 🍪 **Hides cookie/consent pop-ups** (OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast and more) with CSS. Nothing gets clicked or accepted for you
- 🖼️ **Lazy-loaded images** get triggered by auto-scrolling before the capture
- 🌙 Dark mode (`prefers-color-scheme: dark`), PNG or JPEG with a quality setting, and your own selectors to hide (chat widgets, sticky bars)
- 🔁 **Automatic retries** in a fresh browser context, with no retries wasted on permanent errors
- 🧾 **Honest output**: every input URL gets a row with the HTTP status, final URL after redirects, page title, size, attempts and the error reason if it failed

### Who uses it?

- **SEO & marketing teams**: archive landing pages and competitor homepages, and build visual reports
- **QA & developers**: visual checks across desktop and mobile, and before/after deploy snapshots
- **Agencies**: monthly client-site snapshots and proof of ad or page placement
- **AI agents & automations**: give an LLM a picture of a page. It works with the Apify API, MCP server, Make, Zapier and n8n

### Popular use cases

| Goal | Suggested settings |
|---|---|
| Competitor homepage archive (weekly) | `viewport: desktop`, `fullPage: true`, schedule the run in Apify |
| Mobile-friendliness check for a client list | `viewport: mobile`, `fullPage: false` |
| Pricing-page monitoring | `elementSelector: "#pricing"` (or your selector), `format: jpeg` |
| Lead-gen / cold-outreach visuals ("here's your site on mobile") | `viewport: mobile`, `format: jpeg`, `jpegQuality: 70` |
| Dark-mode QA | `darkMode: true` |
| Thumbnails for a link directory | `fullPage: false`, `format: jpeg`, `jpegQuality: 60` |

### How much does it cost?

Pay per successful screenshot: **$3.00 per 1,000** on the Free plan, $2.50 on Starter (Bronze), $1.75 on Scale (Silver), and $1.75 on Business (Gold). No platform-usage fees on top. Failed, blocked and error pages cost **$0**.

| Screenshots | Approx. price |
|---|---|
| 100 | $0.30 |
| 1,000 | $3.00 |
| 10,000 | $30.00 |

Tip: set **Max total charge** on the run to cap your spend. The Actor stops cleanly when it hits the cap.

### Input

| Field | Default | Notes |
|---|---|---|
| `urls` | – | List of URLs (`example.com` works too) |
| `viewport` | `desktop` | `desktop`, `laptop`, `tablet`, `mobile`, `custom` |
| `fullPage` | `true` | Whole page vs. visible area |
| `format` | `png` | `png` or `jpeg` (`jpegQuality` 1–100) |
| `elementSelector` | – | Capture a single element |
| `waitUntil` / `delayMs` | `load` / `1000` | Wait for slow pages and animations |
| `scrollToBottom` | `true` | Triggers lazy-loaded images |
| `hideCookieBanners` / `hideSelectors` | `true` / `[]` | Cleaner shots |
| `maxFullPageHeight` | `15000` | Very long pages are cut there (`truncated: true`) |
| `maxRetries` / `maxConcurrency` | `2` / `3` | Reliability vs. speed |
| `proxyConfiguration` | off | Optional Apify Proxy for geo views (billed by Apify separately) |

Example:

```json
{
  "urls": ["https://apify.com", "https://en.wikipedia.org/wiki/Web_scraping"],
  "viewport": "mobile",
  "fullPage": true,
  "format": "jpeg"
}
```

### Output

Images are saved to the run's **key-value store**. Each dataset row links to its image:

```json
{
  "url": "https://www.python.org",
  "finalUrl": "https://www.python.org/",
  "httpStatus": 200,
  "title": "Welcome to Python.org",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/00002-www-python-org.jpg",
  "format": "jpg", "viewport": "desktop", "width": 1920, "height": 2632,
  "truncated": false, "fileSizeBytes": 325632, "attempts": 1,
  "blocked": false, "charged": true, "error": null
}
```

Download everything as JSON, CSV or Excel, or open the **Screenshots** table view with image previews.

### Use it from code (API)

Run it synchronously and get the dataset back in one call:

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

Node.js (`apify-client`):

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('blond_terrarium/bulk-website-screenshot').call({ urls: ['https://example.com'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map(i => i.screenshotUrl));
```

Python (`apify-client`):

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("blond_terrarium/bulk-website-screenshot").call(run_input={"urls": ["https://example.com"]})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["url"], item["screenshotUrl"])
```

### Use it from AI agents (MCP)

Add the Apify MCP server (`https://mcp.apify.com`) to Claude, Cursor, ChatGPT or any MCP client and ask: *"Take a mobile screenshot of example.com with blond_terrarium/bulk-website-screenshot."* The agent gets back a `screenshotUrl` it can open or pass to a vision model. Set a **Max total charge** so an agent can never overspend.

### Integrations

Zapier, Make, n8n, Google Sheets, Slack, webhooks, and scheduled runs all work out of the box through Apify integrations. A common recipe: Google Sheet of URLs → this Actor (weekly schedule) → Google Drive/Slack with the image links.

### How it compares

| | This Actor | Typical free/DIY screenshot scripts |
|---|---|---|
| Pay only for successful screenshots | ✅ errors and blocked pages are $0 | ❌ you pay compute for failures too |
| Cookie banners hidden | ✅ major consent platforms | usually ❌ |
| Lazy-load scrolling before capture | ✅ | often ❌ (blank images) |
| One output row per input URL, with error reason | ✅ | partial |
| Device presets + element capture + dark mode | ✅ | varies |
| Predictable price per 1,000 | ✅ fixed per screenshot | depends on memory/runtime |

### FAQ

**Why did a URL fail?** Look at the `error` column. Common reasons are a non-existent domain, an HTTP error page, a site that blocks automated browsers, or a page that never finished loading. You weren't charged for any of these.

**How fast is it?** Typically a few seconds per page; raise **Parallel pages** (`maxConcurrency`) for big lists.

**How many URLs per run?** Thousands. For very large lists, split into batches or set **Max total charge** to cap spend.

**Can I get PDF or WebP?** PNG and JPEG today. Open an issue if you need another format.

**Can it screenshot pages behind a login?** No. This Actor is for public pages only. Please respect each website's terms of use.

**Does it accept cookies or click buttons?** No. Consent banners are only hidden visually.

**Internal or private addresses?** Blocked for safety (localhost, 10.x, 192.168.x and so on).

**Can I schedule it?** Yes. Save your input as a Task and add a Schedule (daily, weekly, monthly) in Apify.

**Something broken?** Open an issue on the Issues tab with the URL and settings. Fixes usually ship within a few days.

Related tools by the same developer: [Sitemap URL Extractor](https://apify.com/blond_terrarium/sitemap-url-extractor-pro) (get every URL of a site, then screenshot them here) and [Broken Link Checker](https://apify.com/blond_terrarium/broken-link-checker-pro).

# Actor input Schema

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

Public web pages to capture. 'example.com' is fine; https:// is added automatically. Duplicates are removed.

## `viewport` (type: `string`):

Screen size and device emulation.

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

Used only when viewport is 'custom'.

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

Used only when viewport is 'custom'.

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

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

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

PNG is lossless; JPEG files are much smaller.

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

Only for JPEG.

## `elementSelector` (type: `string`):

Capture only this element, e.g. '#pricing' or 'main'. Leave empty for the page.

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

Navigation event to wait for. A short network-idle wait is always attempted afterwards.

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

Time for animations, fonts and late content.

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

Recommended for full-page shots.

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

Hides common consent pop-ups with CSS (OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast...). Nothing is clicked or accepted.

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

E.g. chat widgets or sticky headers.

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

Emulates prefers-color-scheme: dark.

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

Very long pages are cut at this height (flagged as truncated) to keep files usable.

## `navigationTimeoutSecs` (type: `integer`):

Per attempt.

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

Extra attempts in a fresh browser context.

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

Higher is faster but needs more memory/CPU. 3 is tuned for the default 4 GB run.

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

Optional. Use Apify Proxy for geo-specific views. Proxy traffic is billed by Apify separately.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://en.wikipedia.org/wiki/Web_scraping"
  ],
  "viewport": "desktop",
  "fullPage": true,
  "format": "png",
  "jpegQuality": 80,
  "waitUntil": "load",
  "delayMs": 1000,
  "scrollToBottom": true,
  "hideCookieBanners": true,
  "hideSelectors": [],
  "darkMode": false,
  "maxFullPageHeight": 15000,
  "navigationTimeoutSecs": 45,
  "maxRetries": 2,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset results shown in the 'Screenshots' overview view, with an image preview and direct link per URL.

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

Screenshot image files (PNG/JPEG/WebP) stored in the default key-value store.

# 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://en.wikipedia.org/wiki/Web_scraping"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("blond_terrarium/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://apify.com",
        "https://en.wikipedia.org/wiki/Web_scraping",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("blond_terrarium/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://apify.com",
    "https://en.wikipedia.org/wiki/Web_scraping"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call blond_terrarium/bulk-website-screenshot --silent --output-dataset

```

## MCP server setup

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