# Website Screenshot — full page, no cookie popups, $5 per 1,000 (`theaisololab/website-screenshot`) Actor

Full-page website screenshots in bulk: desktop, tablet or mobile, cookie pop-ups hidden, lazy images loaded, optional PDF. $5 per 1,000 screenshots; failed pages are free.

- **URL**: https://apify.com/theaisololab/website-screenshot.md
- **Developed by:** [AI Solo Lab](https://apify.com/theaisololab) (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 $5.00 / 1,000 screenshot takens

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

## Website Screenshot — full page, no cookie popups, $5 per 1,000

Paste a list of URLs and get a clean screenshot of each page: full page or just the screen, desktop, laptop, tablet or mobile, JPEG or PNG, with an optional PDF. Cookie and consent pop-ups are hidden and lazy images are loaded before the capture. You pay a fixed price per screenshot instead of compute time, and failed pages are free.

- **$5 per 1,000 screenshots** ($0.005 each). Error pages (4xx/5xx), anti-bot walls and invalid URLs are never charged.
- **Clean shots:** known consent platforms (OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast and 20+ more) are hidden, or their "accept" button is clicked if you prefer.
- **Lazy content loaded:** the page is scrolled through before the capture, so images below the fold appear.
- **Device presets:** desktop 1440×900, laptop 1280×800, iPad Mini, iPhone 13 — or your own width and height.
- **Public links:** every file gets a link you can open or embed without an API token.

### What people use it for

- **Visual archives and monitoring** — keep a dated picture of your own pages, competitors' pricing pages or landing pages.
- **SEO and agency reports** — full-page shots of client sites on desktop and mobile, in bulk.
- **Link previews and thumbnails** — viewport-only JPEGs for directories, newsletters and dashboards.
- **QA of many pages** — check that hundreds of pages render after a release, without opening each one.
- **Datasets for AI vision models** — consistent screenshots with page title, size and status code.
- **AI agents** — call it from Claude, Cursor or any MCP client through the [Apify MCP server](https://mcp.apify.com); every row has a one-sentence `summary` written for LLMs and a public `screenshotUrl`.

### Input

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

| Field | What it does | Default |
|---|---|---|
| `urls` | Full URLs or bare domains (`example.com` → `https://example.com/`). Duplicates are removed. Up to 10,000 per run. | — |
| `device` | `desktop` (1440×900), `laptop` (1280×800), `tablet` (iPad Mini) or `mobile` (iPhone 13). | `desktop` |
| `width`, `height` | Override the viewport in CSS pixels (320-3840 × 320-2160). The row then says `device: "custom"`. | — |
| `fullPage` | Whole page (up to 20,000 px tall) or only the visible screen. | `true` |
| `format` | `jpeg` or `png`. | `jpeg` |
| `quality` | JPEG quality, 30-100. | `80` |
| `waitUntil` | `load`, `domcontentloaded` (faster) or `networkidle` (heavy apps). | `load` |
| `delaySecs` | Extra wait after loading and scrolling, 0-30 s. | `1` |
| `scrollToBottom` | Scroll through the page first so lazy images load. | `true` |
| `cookieBanners` | `hide` consent pop-ups, `accept` them (click "accept", then hide what's left) or `leave` them. | `hide` |
| `hideSelectors` | Extra CSS selectors to hide (chat widgets, ads...). | `[]` |
| `elementSelector` | Capture only the first element matching this CSS selector, e.g. `#pricing`. | — |
| `pdf` | Also save an A4 PDF of each page (charged separately). | `false` |
| `maxConcurrency` | Pages at the same time. Empty = automatic: about 3 per CPU (2 at 2 GB, 3 at 4 GB). | automatic |
| `navigationTimeoutSecs` | How long to wait for a page to load, 10-120 s. | `30` |
| `proxyConfiguration` | Optional proxy, for sites that block data-centre IPs. | no proxy |

### Output

One row per URL (a real row from a test run; only the store id and signature in `screenshotUrl` are shortened):

```json
{
  "url": "https://en.wikipedia.org/wiki/Web_scraping",
  "finalUrl": "https://en.wikipedia.org/wiki/Web_scraping",
  "statusCode": 200,
  "title": "Web scraping - Wikipedia",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/en-wikipedia-org-wiki-web-scraping-0dbff88b.jpg?signature=<signature>",
  "screenshotKey": "en-wikipedia-org-wiki-web-scraping-0dbff88b.jpg",
  "format": "jpeg",
  "device": "desktop",
  "viewport": {
    "width": 1440,
    "height": 900,
    "deviceScaleFactor": 1
  },
  "fullPage": true,
  "widthPx": 1440,
  "heightPx": 8988,
  "truncated": false,
  "bytes": 1989690,
  "pdfUrl": null,
  "pdfKey": null,
  "cookieBanner": "none-found",
  "loadMs": 3999,
  "blocked": false,
  "partial": false,
  "summary": "en.wikipedia.org/wiki/Web_scraping: 1,440×8,988 px full-page JPEG (1.9 MB), no cookie banner found.",
  "ok": true,
  "error": null,
  "capturedAt": "2026-09-28T19:54:08+00:00"
}
```

The image itself is in the run's key-value store, under `screenshotKey`; `screenshotUrl` is its public link. `widthPx` and `heightPx` are the image size in real pixels (CSS pixels × the device's pixel ratio, so an iPhone 13 shot is 1,170 px wide). `cookieBanner` is `hidden`, `accepted`, `none-found` or `left`. Rows with `ok: false` are free: `error` says why (`HTTP 404`, `net::ERR_NAME_NOT_RESOLVED`, `blocked by Cloudflare bot protection`...). `partial: true` means the page didn't finish loading in time but something rendered: that image is saved, and not charged.

### How it works

Each URL opens in a fresh headless Chromium context (no cookies shared between pages). The Actor waits for the page to load, scrolls through it in small steps (at most 8 seconds) so lazy images load, hides consent pop-ups and your extra selectors, waits the extra delay and captures the screenshot. Pages that answer with an error status or a bot-protection challenge (Cloudflare, AWS WAF, DataDome, Imperva...) are reported and not captured.

**Limits, stated plainly:**

- Full-page screenshots stop at **20,000 px** tall; longer pages are cut and marked `truncated: true`.
- Pages behind a login or a strong anti-bot wall are not captured (and not charged). A proxy helps with sites that only block data-centre IPs.
- Pages are opened with "reduced motion" requested, so sites show their static version: animations are stopped, and video frames, canvas animations and cross-origin iframes (embedded maps, some ads) may render blank or as a still.
- Consent pop-ups are recognised by their known platforms plus a generic rule for fixed boxes named "cookie" or "consent". An unusual custom banner can still show; add its selector to `hideSelectors`.
- Pages whose content scrolls inside an inner box (not the page itself) are captured at the height of the window.

### Pricing

Pay per event: **$5 per 1,000 screenshots** ($0.005 per screenshot of a page that loaded), and **$0.005 per PDF** when you turn PDFs on. Failed, blocked and partial pages are never charged. Each run also has a start fee of $0.0005 per GB of memory — $0.002 at the default 4 GB — because starting a headless browser's container takes 15-20 seconds, which we pay for. You can cap spending per run in the run options — the Actor stops cleanly when it's reached.

**Compared to a free screenshot Actor:** free Actors bill you for compute time, which depends on how heavy each page is and on the memory you pick. Here the price per screenshot is fixed, so 10,000 screenshots cost $50 plus the start fee — you can compute it before you start.

### FAQ

**Is this legal?** Taking screenshots of public web pages is the same as visiting them in a browser. The Actor doesn't log in, doesn't solve captchas and doesn't bypass paywalls. What you do with the images is up to you — respect copyright and the sites' terms.

**Can I get the images without the API token?** Yes: `screenshotUrl` and `pdfUrl` are public links to the files in the run's storage. They stay available as long as the run's storage is kept (see Apify's data retention for your plan).

**Why was a page not charged?** Its `error` says why: an error status, a bot wall, a timeout, or an invalid URL. Only saved screenshots of pages that loaded are charged.

**Can I capture only part of the page?** Use `elementSelector` (e.g. `#pricing`) for one element, or set `fullPage` to `false` for just the first screen.

### More tools from theaisololab

- [WHOIS Domain Lookup](https://apify.com/theaisololab/whois-domain-lookup) — registrar, expiry dates, DNS and email provider, $0.50 per 1,000 domains.
- [Tech Stack Detector](https://apify.com/theaisololab/tech-stack-detector) — technologies behind any website, $0.01 per domain.
- [Google Ads Transparency Scraper](https://apify.com/theaisololab/google-ads-transparency) — every Google ad a company runs.

### Changelog

- **0.1** — first release.

This Actor is independent and not affiliated with any of the websites it captures.

# Actor input Schema

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

Full URLs (https://example.com/pricing) or bare domains (example.com → https://). Duplicates are removed. Up to 10,000 per run.

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

Screen to emulate: desktop (1440×900), laptop (1280×800), tablet (iPad Mini) or mobile (iPhone 13).

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

Optional. Overrides the device's width in CSS pixels, for example 1920.

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

Optional. Overrides the device's height in CSS pixels, for example 1080.

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

Capture the whole page (up to 20,000 px tall) instead of only the visible screen.

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

JPEG (smaller files) or PNG (lossless).

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

JPEG only, from 30 to 100. 80 is a good balance of size and sharpness.

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

When the page counts as loaded: the load event (default), the HTML only (faster) or no network activity for 0.5 s (slower, for heavy apps).

## `delaySecs` (type: `number`):

Extra wait after the page loaded and was scrolled, for animations or late content, for example 2.

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

Scroll through the page before the capture so lazy-loaded images appear.

## `cookieBanners` (type: `string`):

Hide known cookie/consent pop-ups, click their 'accept' button (then hide what's left), or leave the page as it is.

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

Extra CSS selectors to hide before the capture, for example chat widgets (#intercom-container) or ads (.ad-banner).

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

Optional CSS selector, for example #pricing. Captures only the first matching element instead of the page.

## `pdf` (type: `boolean`):

Also save an A4 PDF of each page (charged separately, only when saved).

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

Pages captured at the same time. Leave empty for automatic: about 3 per CPU (Apify gives 1 CPU per 4 GB of memory, so 2 at 2 GB and 3 at 4 GB). If you set it, your value is used.

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

How long to wait for a page to load, for example 30. If it times out but something rendered, that is saved as a free partial result.

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

Optional. Use a proxy for sites that block data-centre IPs.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://en.wikipedia.org/wiki/Web_scraping"
  ],
  "device": "desktop",
  "fullPage": true,
  "format": "jpeg",
  "quality": 80,
  "waitUntil": "load",
  "delaySecs": 1,
  "scrollToBottom": true,
  "cookieBanners": "hide",
  "hideSelectors": [],
  "pdf": false,
  "navigationTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per URL: a public link to the screenshot (and PDF), image size, page title, cookie-banner handling and a one-sentence summary.

# 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"
    ]
};

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

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

```

## MCP server setup

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