# Website Screenshot Generator — Full Page, Pay Only If Usable (`wheaten_steelpan/website-screenshot`) Actor

Blank, blocked, bot-checked and 404 pages are reported with the reason and never charged — you pay only for images you can use. Full-page captures that reach the bottom: lazy content loaded, cookie banners removed, sticky headers stopped from repeating. Batch many URLs per run.

- **URL**: https://apify.com/wheaten\_steelpan/website-screenshot.md
- **Developed by:** [Vanja V](https://apify.com/wheaten_steelpan) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 usable screenshots

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Website Screenshot Generator — Full Page, Pay Only If Usable

Full-page screenshots of any list of URLs. Lazy content is loaded before the capture, cookie
banners are removed, and sticky headers are stopped from repeating down the image.

**You are charged for images you can use.** When a page comes back blank, blocked, bot-checked,
behind a login wall or as a 404, you get the reason in the output row and that URL costs nothing.

### What you pay for

One flat price per usable screenshot. No free-tier surcharge, no per-row fee, no charge for
anything the run could not capture.

| outcome | charged |
|---|---|
| a real screenshot of a real page | **yes** |
| the site returned 4xx or 5xx | no |
| the page rendered blank or nearly empty | no |
| a bot check or CAPTCHA came back instead of the page | no |
| a consent or paywall overlay survived removal and still covers the page | no |
| a login wall with nothing behind it | no |
| the page painted almost nothing | no |
| the URL timed out, failed to load, or the domain does not exist | no |
| your CSS selector was not on the page | no |
| the run budget ran out before that URL started | no |

Every one of those reasons is written into the results table, the gallery and the run summary.
The detector fails open on purpose: a signal we could not measure never withholds payment.

### What you get

The run opens on **Screenshots** — a gallery of every capture in the run, click any image for the
full-size version. Anything that was not charged for carries an amber border and says why in
plain words. The gallery link is signed and opens with no login, so you can send it to a client
as it is.

Also in every run:

- **Image files** — the PNG/JPEG/WebP records themselves, named `001-example-com.png` and so on.
- **Results table** — one row per URL with a direct image link, page title, pixel size, file size,
  timing, whether it was charged for, and if not, why.
- **Run summary JSON** — captured, charged, not charged, failed and skipped counts, plus the
  settings the run used.

Image links are signed URLs. They open with no Apify account, so they can go straight into a
report, a sheet, or another system.

### Input

```json
{
  "urls": [
    "https://www.gov.uk",
    "https://vercel.com"
  ],
  "fullPage": true,
  "format": "png"
}
```

`urls` is the only field without a working default — a first run never fails because something
was left blank.

### Options

**Page preparation** — remove cookie and consent banners (on), load lazy content before capturing
(on), stop sticky headers repeating (on), block ad networks (off).

**Image** — full page or viewport, PNG / JPEG / WebP, viewport width and height, pixel density up
to 3x, JPEG/WebP quality, maximum page height, transparent background.

**Part of a page** — capture one CSS selector such as `main` or `#pricing`, or a fixed region in
page coordinates such as `{"x":0,"y":0,"width":1200,"height":630}` for a social preview.

**Loading and timeouts** — what counts as loaded (`load`, `domcontentloaded`, `networkidle`,
`commit`), wait for a selector, a fixed extra delay, per-URL time limit, ignore certificate errors.

**Batch** — URLs at a time, a run budget that stops starting new work rather than overrunning,
and retries per URL. A domain that does not exist is never retried.

**Advanced** — colour scheme, locale, time zone, user agent, page preparation budget.

### What this cannot do

Read this before you buy. Every limit here is one we measured.

- **Sites that block datacenter traffic will not be captured.** This Actor runs from Apify's data
  centre with no residential proxy option. Cloudflare-protected sites — Stack Overflow is the
  standing example — return a bot check instead of the page. You get `http-403` or `bot-check` as
  the reason and **you are not charged**, but you also do not get the screenshot.
- **A few consent dialogs cannot be removed without breaking the site.** Sourcepoint keeps its
  state on the page's root element; removing it blanks the whole site, so it is left alone.
  `theguardian.com` is the known case: the article renders and the capture is useful, with the
  dialog still over part of it. Most CMPs (57 selector families) are removed cleanly.
- **We remove banners, we never click them.** Clicking "Accept all" would consent to tracking on
  your behalf. A site that renders nothing at all until consent is given comes back with the
  reason, unbilled.
- **Very tall pages are clipped, and say so.** The default ceiling is 12,000 pixels and the maximum
  is 30,000; browsers cannot reliably capture much beyond 16,000. A clipped row is marked
  `truncated`. Nothing is ever silently cut.
- **No logged-in pages.** There is no cookie, session or credential input. Anything behind a login
  comes back as `login-wall` and is not charged.
- **No interaction before the capture.** No clicking, typing, scrolling to a specific element or
  dismissing modals beyond consent handling. You can wait for a selector and add a fixed delay.
- **Images only.** No PDF export, no HTML archive, no text extraction.
- **One run is one moment.** There is no change tracking or visual diff between runs.
- **Apify stops any run at 5 minutes.** The run budget defaults to 4 minutes and stops starting new
  URLs before that. For large batches, split them across runs or raise the budget and memory.
- **Concurrency 2 is the measured default.** It is sized for 2 GB of memory. Raising it without
  raising memory makes captures slower and more likely to time out.

### Pricing

**$0.02 per usable screenshot.** One price for every buyer on every plan. Apify bills its own
compute on top, at cost.

A measured six-URL run — four capturable, two not — costs **$0.08** in screenshots plus
**$0.012 to $0.022** in Apify compute, and finishes in about seventy seconds. The two that
failed cost nothing.

### Notes

- Set `format` to `jpeg` for long pages — a full-page PNG of a tall site can reach several
  megabytes, and JPEG or WebP cuts that sharply.
- Use `width: 390` for a mobile-width layout.
- `blockAds` is off by default: a cookie banner is an artefact of our visit, and an ad is part of
  the page as published. Turn it on for a cleaner marketing shot.

# Actor input Schema

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

One URL per line. http:// or https:// only. A URL that cannot be read becomes its own row and does not stop the rest of the batch.

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

On: the entire page, top to bottom, with lazy content loaded first. Off: just the visible area, exactly as a visitor sees it above the fold.

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

PNG is lossless and the safest default. JPEG and WebP are much smaller on long pages.

## `blockConsent` (type: `boolean`):

Removes the banner rather than clicking it, so nothing consents to tracking on your behalf, and it works in any language. If a site refuses to render anything until consent is given, you get the reason and are not charged.

## `lazyLoad` (type: `boolean`):

Scrolls the page to trigger images and sections that only load when they come into view, waits for them to settle, then scrolls back to the top. Full-page captures only.

## `hideStickyElements` (type: `boolean`):

Pins a fixed header at the top so it appears once instead of riding down the image, and hides floating chat bubbles, back-to-top buttons and sticky footers. Full-page captures only — on a viewport capture these are what a visitor actually sees, so they are left alone.

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

Off by default. A cookie banner is an artefact of our visit, so removing it makes the image more faithful; an ad is part of the page as published. Turn this on for a cleaner marketing shot.

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

Browser width in pixels. 1280 is a typical desktop; 390 gives a mobile-width layout.

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

Browser height in pixels. On a full-page capture this only sets the window; the image is as tall as the page.

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

1 is normal. 2 produces a retina-resolution image at roughly four times the file size.

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

1 to 100. Ignored for PNG, which has no lossy quality setting.

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

Pages taller than this are clipped to it and the row is marked as clipped — never silently truncated. Browsers cannot reliably capture beyond about 16,000 pixels.

## `omitBackground` (type: `boolean`):

Leaves the page background transparent where the site does not paint one. PNG and WebP only.

## `selector` (type: `string`):

Capture just this element, for example "main" or "#pricing". The run fails for that URL, without charge, if the selector is not on the page.

## `clip` (type: `object`):

A region in page coordinates, for example {"x":0,"y":0,"width":1200,"height":630} for a social preview. Works below the fold too.

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

When to consider the page loaded. "load" suits almost everything. "networkidle" waits for traffic to stop, which is slower but better for heavy apps.

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

A CSS selector to wait for before capturing, for example ".product-grid". Leave blank to skip.

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

A fixed pause after loading, before capturing. Useful for an animation that has to finish.

## `timeoutMs` (type: `integer`):

A URL that takes longer than this is abandoned, reported as a timeout, and not charged. 60 seconds suits Apify's data centre, where ad-heavy pages reach load more slowly than they do on a home connection.

## `ignoreHTTPSErrors` (type: `boolean`):

Captures sites with an expired or self-signed certificate, which otherwise fail to load.

## `concurrency` (type: `integer`):

2 is sized for the default 2 GB of memory and measured to fit it. Raise it only if you also raise the actor's memory — 3 needs more than 2 GB.

## `runBudgetMs` (type: `integer`):

The whole run stops starting new URLs once this is spent, rather than overrunning. Anything not started is reported and not charged.

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

Retries a timeout or a dropped connection. A domain that does not exist is never retried, because that only burns the run budget.

## `colorScheme` (type: `string`):

Which theme the site is asked to render in, for sites that offer both.

## `locale` (type: `string`):

Browser language, for example en-US or de-DE. Affects which language a multilingual site serves.

## `timezoneId` (type: `string`):

IANA time zone, for example Europe/Berlin. Leave blank for the server's own.

## `userAgent` (type: `string`):

Override the browser's user agent string. Leave blank for the default.

## `prepareTimeoutMs` (type: `integer`):

How long consent removal, lazy-load scrolling and sticky handling may take before the capture goes ahead with whatever is ready. Lowering it speeds up heavy pages.

## Actor input object example

```json
{
  "urls": [
    "https://www.gov.uk",
    "https://vercel.com",
    "https://example.com",
    "https://stackoverflow.com",
    "https://this-domain-does-not-exist-zzz9911.com"
  ],
  "fullPage": true,
  "format": "png",
  "blockConsent": true,
  "lazyLoad": true,
  "hideStickyElements": true,
  "blockAds": false,
  "width": 1280,
  "height": 800,
  "deviceScaleFactor": 1,
  "quality": 80,
  "maxFullPageHeight": 12000,
  "omitBackground": false,
  "selector": "",
  "clip": {},
  "waitUntil": "load",
  "waitForSelector": "",
  "delayMs": 0,
  "timeoutMs": 60000,
  "ignoreHTTPSErrors": false,
  "concurrency": 2,
  "runBudgetMs": 240000,
  "maxRetries": 1,
  "colorScheme": "light",
  "locale": "en-US",
  "timezoneId": "",
  "userAgent": "",
  "prepareTimeoutMs": 10000
}
```

# Actor output Schema

## `gallery` (type: `string`):

Every capture from this run as a grid. Click an image to open it full size. Links are signed and open with no login, so the page can be shared as it is. Anything that could not be captured is listed underneath with the reason and a note that it was not charged.

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

The raw PNG/JPEG/WebP records, named 001-example-com.png and so on, in the run's key-value store.

## `data` (type: `string`):

One row per URL: the signed image link, page title, size, timing, whether it was charged for, and if not, why.

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

Counts for the whole run — captured, charged, not charged, failed, skipped — plus the settings used.

# 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://www.gov.uk",
        "https://vercel.com",
        "https://example.com",
        "https://stackoverflow.com",
        "https://this-domain-does-not-exist-zzz9911.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("wheaten_steelpan/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://www.gov.uk",
        "https://vercel.com",
        "https://example.com",
        "https://stackoverflow.com",
        "https://this-domain-does-not-exist-zzz9911.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("wheaten_steelpan/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://www.gov.uk",
    "https://vercel.com",
    "https://example.com",
    "https://stackoverflow.com",
    "https://this-domain-does-not-exist-zzz9911.com"
  ]
}' |
apify call wheaten_steelpan/website-screenshot --silent --output-dataset

```

## MCP server setup

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