# Website Screenshot API — Clean, No Popups (`spellzarr/website-screenshot-api`) Actor

Clean, full-page screenshots of up to 500 websites per run. Cookie banners, popups and chat bubbles are hidden, lazy images are loaded, and endless pages are handled. Every link gets a clear result, and every failure is explained in plain words.

- **URL**: https://apify.com/spellzarr/website-screenshot-api.md
- **Developed by:** [Prathu Agarwal](https://apify.com/spellzarr) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

Take clean, complete screenshots of many websites in one run. Paste your links, press start, and get one image and one clear result row for every link. It is made for people who need good screenshots at scale: marketers, designers, QA testers, researchers, and anyone who keeps records of web pages.

**Cookie banners, popups and chat bubbles are hidden. Full pages are really full. Every failure comes with a reason in plain words.**

### Why it is better

- **Clean screenshots.** Cookie banners, newsletter popups and chat bubbles are hidden. You can also ask for a click on "Reject all". The Actor never clicks "Accept all".
- **Real full page.** Tall pages are taken slice by slice and joined, so there are no repeated headers. Pages that scroll inside a box are unrolled too.
- **Lazy images loaded.** The page is scrolled slowly first, so pictures that load late are in the image.
- **Endless page guard.** Pages that never stop loading are detected. You choose: keep the top part, or skip the page.
- **All languages and emojis.** Hindi, Arabic, Chinese, Japanese, Korean, Thai, Hebrew and more, plus colour emojis.
- **Clear reasons.** If a page fails, the row says what happened, why, and what to do.
- **One row per link, always.** Even when a run is stopped, every link gets a row.
- **Safe by design.** The Actor never opens private or internal addresses, never types into pages, and never logs in.

### Quick start

1. Paste your links in **Website links** (one per line, up to 500).
2. Pick **Device**: Laptop or Phone.
3. Pick **Capture**: Full page or Top only.
4. Press **Start**.

| Field | What it does | Default |
|---|---|---|
| Website links | 1 to 500 links. `https://` is added if missing. Duplicates are removed. | `https://example.com` |
| Device | Laptop = 1440 x 900. Phone = 390 x 844, sharp (2x), mobile layout. | Laptop |
| Capture | Full page = top to bottom. Top only = the first screen. | Full page |

#### Example input

```json
{
    "urls": ["https://example.com", "https://www.wikipedia.org"],
    "device": "phone",
    "capture": "fullPage"
}
```

#### Example output row

```json
{
    "url": "https://example.com/",
    "finalUrl": "https://example.com/",
    "result": "Done",
    "notes": "",
    "charged": false,
    "imageUrl": "https://api.apify.com/v2/key-value-stores/<store-id>/records/screenshot-94f871ba1cb95ff631b85415.png",
    "imageKey": "screenshot-94f871ba1cb95ff631b85415.png",
    "format": "png",
    "width": 780,
    "height": 1796,
    "device": "Phone",
    "takenAt": "2026-11-06T16:30:36.393Z",
    "errorType": null,
    "whatHappened": null,
    "why": null,
    "whatToDo": null
}
```

### Advanced settings

All of these are optional. They sit in one collapsed section of the form.

| Group | Field | Values | Default |
|---|---|---|---|
| Size and view | Device preset | None, iPhone, Android phone, iPad, Laptop, Big monitor (2560 x 1440). Overrides Device. | None |
| | Custom width / height | Width 320 to 3840, height 320 to 2160. Fill in both. Overrides the preset. | empty |
| | 2x sharp mode | On or off. Only when the width is 1920 or less. | Off |
| Capture | Capture mode | Use main field, Visible screen, Full page, Top N px, One element (CSS selector). Overrides Capture. | Use main field |
| | Top N px | 100 to 30000 | 3000 |
| | Element CSS selector | Up to 300 characters | empty |
| Waiting | Max wait time | 5 to 60 seconds | 30 |
| Cleaning | Clean screenshot | Hides popups, newsletter boxes and chat bubbles | On |
| | Cookie banner | Hide, or Click "Reject all" | Hide |
| | Sticky elements | Keep once at top, Hide, Leave as is | Keep once at top |
| Endless pages | When found | Capture top, or Skip | Capture top |
| | Max page height | 1000 to 30000 px | 15000 |
| Pagination | Follow pages up to N | 0 to 20 | 0 |
| | Click "Load more" up to N times | 0 to 20 | 0 |
| Clicks | Run these clicks first | Up to 10 steps | empty |
| Output | Format | PNG, JPEG, WebP, PDF | PNG |
| | Resize output width | 100 to 3840 px, keeps the shape | empty |

Notes:

- **Device preset** uses ready-made device settings (iPhone, Pixel, iPad). Custom width and height beat the preset, and the preset beats Device.
- **Sticky elements:** "Keep once at top" shows a fixed header once at the top, not again and again down the image.
- **Follow pages:** the Actor follows the page's "Next" link (or a link or button with text like Next, `>`, `>>`, or the next page number). Same website only. Each page gets its own row, for example "Page 2 (followed Next ...)".
- **Load more:** presses buttons with text like Load more, Show more, See more or View more.
- **Run these clicks first:** each step is the exact text of a button or link. Capital letters and extra spaces don't matter. Experts can write `css:<selector>`. Each step has 5 seconds. Text is up to 100 characters and a selector up to 300. The Actor never types anything.
- **Cookie banner → Click "Reject all":** works in many languages. If no reject button is found, the banner is hidden instead and a note says so.

### Output

Every link gets one row in the results table. The images are saved in the run's key-value store, and each row has a link to its image.

| Column | Meaning |
|---|---|
| URL | The link, after clean-up |
| Result | The status (see below) |
| What we noticed | Notes, for example "Cookie banner hidden" or "Max wait hit" |
| Charged? | `false` for every row while the Actor is free |
| Image | Link to the picture |

The **All details** view adds: final URL (after redirects), image key, format, width, height, device, time taken, and for problems: error type, what happened, why, and what to do.

#### Statuses

| Status | Meaning | Charged? |
|---|---|---|
| Done | Full screenshot delivered | Counts as delivered |
| Cut short | Endless or too-tall page; the top part is delivered | Counts as delivered |
| Partial | Image saved, but something went wrong (a click step was not found, the max wait was hit, or similar) | No |
| Blocked | The site blocked us (for example 403), or the address is private | No |
| Failed | Any error from the table below | No |
| Skipped | Endless page with Skip, an age check, a login page, or the run stopped before this link | No |
| Invalid link | The link failed the check before the run | No |

While the Actor is free, the **Charged?** column is `false` on every row, because nothing is charged. The run summary still counts the delivered screenshots (Done and Cut short).

#### Run summary

At the end of each run the Actor saves a **SUMMARY** record in the key-value store and shows it as the run status message. It has the number of links per status, delivered screenshots, time taken, and compute used.

#### Downloads

Open the **Storage** tab of the run (or use the API) and download the results table as **JSON**, **CSV** or **Excel**.

#### Keep your images

Apify keeps the storage of a run for a limited time. **Download the images you need to keep.**

### Failure reasons

| What happened | Why | What to do |
|---|---|---|
| Invalid link | The link is not a valid web address | Fix the link and run again |
| Domain doesn't exist | No website with this name | Check the spelling |
| 404 Not found | The site works, the page does not exist | Check the link in your browser |
| 403 Blocked | The site refuses automated tools | Try later; some sites never allow it |
| 500 Server error | A problem on the site's side (we tried twice) | Try later |
| Timeout | The site took too long (we tried twice) | Try later, or raise Max wait time |
| SSL certificate problem | The security certificate is expired or wrong | Tell the site owner |
| Redirect loop | The page sent us on more than 10 times | Use the final link |
| Private address blocked | The link points to a private or internal address | Use a public website link |
| Too big | The page tried to download more than about 50 MB | Try Top only |
| Page crashed | The page used too much memory | Try Top only. If you lowered the memory, run with 2048 MB (the default) |
| Connection problem | The connection failed (we tried twice) | Try later |
| Element not found | Your CSS selector matches nothing visible | Check the selector |
| Endless page skipped | Endless page, and the setting is Skip | Set it to Capture top |
| Age check found, not clicked | The page asks for age; the Actor never clicks it | See "Age checks" below |
| Login needed | The page needs a login | Use a public page |
| Not finished in time | The run was stopped before this link was done | Run it again |

### Limits

| Limit | Value |
|---|---|
| Links per run | 500 (duplicates removed), up to 2048 characters each |
| Pages at once | 3 overall, 2 per website, with a short pause between pages of the same site |
| Time per link | About 90 seconds |
| Screen size | Width 320 to 3840, height 320 to 2160 |
| Page height | Up to 30000 px (default 15000) |
| Total image size | About 40 million pixels |
| Click steps | 10 per link; Load more 20; Follow pages 20 (total pages per run 500) |
| Max wait time | 5 to 60 seconds |
| Image file size | About 8.5 MB. Bigger images are made smaller and a note says so |
| Links allowed | `http` and `https`, ports 80 and 443 only |
| Memory | 2048 MB by default (you can lower it to 1024 MB, but heavy pages may crash) |
| Run timeout | 3600 seconds by default |

**Formats:** PNG, JPEG, WebP, PDF. **PDF is the page's print layout, not a picture of the screen.** WebP can't be taller than 16,383 px, so taller images are made smaller and noted.

### Pricing

The Actor is free to use for now. You only pay Apify for the platform usage of your runs (compute and storage). A typical run of a few pages uses a tiny part of the free monthly credit.

### Acceptable use

You are responsible for the pages you capture and for any clicks you add. Follow each website's terms and the law.

**Not allowed:**

- Logins or private pages.
- Getting around age or ID checks, paywalls or CAPTCHAs.
- Harassment, or capturing illegal content.
- Flooding a site with requests.

**What the Actor does and does not do:**

- It never clicks age checks by itself. If it finds one, the row says "Age check found, not clicked". You may add the button text in "Run these clicks first" at your own responsibility.
- It never types into pages, never logs in, and never solves CAPTCHAs.
- It never opens private, local or internal addresses.

### Privacy

- The Actor stores nothing about page content except the images you asked for, in your own run storage.
- Logs show website names only. They never show full links, page text, cookies or HTML.
- It does not use Apify Proxy or any other proxy service, and it does not send your data anywhere else.

### FAQ

**Why is a page Blocked?** The site refused us (for example a 403 error), or the link points to a private address. Some sites block automated tools. Try again later.

**Why is a page Cut short?** The page is endless (it keeps loading more) or taller than "Max page height". You get the top part. This counts as a delivered screenshot.

**Why is a page Partial?** The image was saved, but something went wrong. The notes tell you what: a click step was not found, the page was still loading when Max wait ran out, or a cookie banner could not be removed.

**Why does a page look different from my browser?** Websites show different things by location, cookies, device and time. The Actor opens each page fresh, with no cookies, from a data centre.

**How do I add a click step?** Open the page in your browser. Find the button or link you want pressed. In "Run these clicks first", add its exact text, for example `Show all`. Steps run in order before the screenshot.

**Why was my page Skipped with "Age check found, not clicked"?** The page shows an age check. The Actor never clicks these by itself.

**A banner is still in my image.** Banner and popup detection is a best guess, and rare designs can be missed. Report the website in the Issues tab and we will look at it.

### Support

Found a problem? Open the **Issues** tab of this Actor. Please include the website name and what you expected.

### Coming in version 2

Before/after comparison, dark mode, ad blocking, Standby mode, and a proxy country setting.

# Actor input Schema

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

One link per line, 1 to 500 links. We add https:// if it is missing and remove duplicates.

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

Laptop = 1440 x 900. Phone = 390 x 844, sharp (2x), mobile layout.

## `capture` (type: `string`):

Full page = the whole page from top to bottom. Top only = what you see first, without scrolling.

## `devicePreset` (type: `string`):

Pick a ready-made device. Overrides the Device field above. None = use the Device field.

## `customWidth` (type: `integer`):

Screen width in pixels (320 to 3840). Fill in width and height together. Overrides the Device preset.

## `customHeight` (type: `integer`):

Screen height in pixels (320 to 2160). Fill in width and height together.

## `sharp2x` (type: `boolean`):

Makes the image twice as sharp (and twice as big). Only allowed when the width is 1920 or less.

## `captureMode` (type: `string`):

Overrides the Capture field above. Use main field = keep what you picked above.

## `topNPx` (type: `integer`):

Used when Capture mode is Top N px. How many pixels from the top (100 to 30000).

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

Used when Capture mode is One element. Example: #main or .product-card. Max 300 characters.

## `maxWaitSecs` (type: `integer`):

The longest we wait for a page to finish loading (5 to 60 seconds). If the page is still busy, we take the screenshot anyway and add a note.

## `cleanScreenshot` (type: `boolean`):

Hides popups, newsletter boxes and chat bubbles.

## `cookieBanner` (type: `string`):

Hide = hide the banner. Click "Reject all" = press the page's reject button. We never press "Accept all".

## `stickyElements` (type: `string`):

Headers and bars that stay on screen while you scroll. Keep once at top = shown once, not repeated down the image.

## `endlessPages` (type: `string`):

Endless pages keep loading more while you scroll. Capture top = save the top part (counts as a screenshot). Skip = no image (free).

## `maxPageHeight` (type: `integer`):

The tallest image we make (1000 to 30000 px). Taller pages are cut here.

## `followPages` (type: `integer`):

Follows the page's "Next" link up to N times (0 to 20). Same website only. Each page gets its own row.

## `loadMoreClicks` (type: `integer`):

Presses buttons like Load more / Show more / See more / View more up to N times (0 to 20).

## `clickSteps` (type: `array`):

Up to 10 steps, done in order before the screenshot. Each step = the exact text of a button or link (capital letters and extra spaces don't matter). Experts: css:<selector>. 5 seconds per step. You are responsible for the clicks you add and must follow each site's rules.

## `outputFormat` (type: `string`):

PNG = best quality. JPEG / WebP = smaller files. PDF = print layout, not a picture.

## `resizeWidth` (type: `integer`):

Make the final image this wide (100 to 3840 px). The shape stays the same. Empty = no resize.

## Actor input object example

```json
{
  "urls": [
    "https://example.com"
  ],
  "device": "laptop",
  "capture": "fullPage",
  "devicePreset": "none",
  "sharp2x": false,
  "captureMode": "useMain",
  "topNPx": 3000,
  "elementSelector": "",
  "maxWaitSecs": 30,
  "cleanScreenshot": true,
  "cookieBanner": "hide",
  "stickyElements": "keepOnce",
  "endlessPages": "captureTop",
  "maxPageHeight": 15000,
  "followPages": 0,
  "loadMoreClicks": 0,
  "clickSteps": [],
  "outputFormat": "png"
}
```

# Actor output Schema

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

No description

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

No description

## `images` (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": [
        "https://example.com"
    ]
};

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

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,spellzarr/website-screenshot-api"
        }
    }
}
```

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/TPPhw14kCol7P0fUW/builds/OrNGKoull2gEGBlL3/openapi.json
