# Website Screenshot - Full Page, Mobile & Batch (`sturdyscrape/website-screenshot`) Actor

Full-page or viewport screenshots of any list of URLs, as PNG or JPEG, on desktop, mobile or tablet. Hides cookie banners and loads lazy images. Pay only for successful screenshots.

- **URL**: https://apify.com/sturdyscrape/website-screenshot.md
- **Developed by:** [Bernardo Henriques Sousa](https://apify.com/sturdyscrape) (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 $3.00 / 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

## Website Screenshot

Take clean screenshots of any list of web pages: full page or viewport, PNG or JPEG, on desktop, mobile or tablet.
Cookie banners are hidden, lazy-loaded images are loaded before the capture, and **you only pay for screenshots that succeed**.

### What does Website Screenshot do?

You give it a list of URLs. For each one it opens the page in a real Chromium browser, waits for it to load, and saves an image in the run's key-value store. The dataset gets one row per URL with a public link to the image, the page title, the HTTP status and, when something goes wrong, the reason.

### Why use it?

- **Pay only for results.** A page that times out or doesn't exist shows up in the dataset with its error, and costs you nothing.
- **No cookie walls in your images.** Consent banners from OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast, TrustArc and other common frameworks are hidden with CSS. Nothing is clicked, so no consent is given on your behalf.
- **Complete full-page captures.** Before a full-page screenshot the page is scrolled from top to bottom, so images that load on scroll actually appear.
- **Desktop, mobile or tablet.** Mobile emulates an iPhone 13 and tablet an iPad, with the right user agent and pixel ratio, so you see the responsive layout real visitors see.
- **Hide anything else.** Add your own CSS selectors to remove chat widgets, popups or sticky headers.
- **Doesn't give up on heavy pages.** Ad-heavy sites that never finish loading are captured as they are, instead of failing on a timeout.
- **Fast batches.** Several pages are captured in parallel in one run.

Typical uses: visual monitoring of your own or competitors' pages, archiving pages as evidence, thumbnails for link previews and directories, QA of responsive layouts, and reports for clients.

### How to use it

1. Add the URLs in **URLs**, one per row, or use **Bulk edit** to paste a whole list.
2. Choose **Full page** or viewport only, the **Device** and the **Image format**.
3. Click **Start**. When the run finishes, open the **Output** tab: each row has a clickable screenshot.

You can also run it via the Apify API, on a schedule, or connect it to Make, Zapier, n8n and other integrations.

### Input example

```json
{
    "urls": [
        { "url": "https://apify.com" },
        { "url": "https://www.wikipedia.org" }
    ],
    "fullPage": true,
    "device": "desktop",
    "format": "png",
    "hideCookieBanners": true
}
```

The main options:

| Option | What it does | Default |
|---|---|---|
| `fullPage` | Whole scrollable page instead of the visible viewport | `true` |
| `device` | `desktop`, `mobile` (iPhone 13) or `tablet` (iPad) | `desktop` |
| `viewportWidth` / `viewportHeight` | Window size for desktop | `1280` × `800` |
| `format` / `jpegQuality` | `png` or `jpeg`, and JPEG quality from 1 to 100 | `png` / `80` |
| `hideCookieBanners` | Hide common consent banners | `true` |
| `hideSelectors` | Your own CSS selectors to hide | none |
| `scrollToBottom` | Scroll first so lazy images load | `true` |
| `waitUntil` | `load`, `domcontentloaded` or `networkidle` | `load` |
| `waitForSelector` | Wait for an element before the capture | none |
| `delayMs` | Extra wait before the capture, for animations | `0` |
| `timeoutSecs` | Maximum load time per page | `60` |
| `maxConcurrency` | Pages captured in parallel (1 to 10) | `2` |

### Output example

```json
{
    "url": "https://example.com",
    "finalUrl": "https://example.com/",
    "statusCode": 200,
    "pageTitle": "Example Domain",
    "screenshotUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/screenshot-00001-327c3fda87.png",
    "screenshotKey": "screenshot-00001-327c3fda87.png",
    "format": "png",
    "fullPage": true,
    "device": "desktop",
    "sizeBytes": 59146,
    "takenAt": "2026-10-10T03:46:01.913309+00:00",
    "error": null
}
```

A failed URL looks like this, and is not charged:

```json
{
    "url": "https://this-domain-does-not-exist.com",
    "screenshotUrl": null,
    "error": "Page.goto: net::ERR_NAME_NOT_RESOLVED at https://this-domain-does-not-exist.com/"
}
```

You can download the dataset as JSON, CSV, Excel or HTML. The images themselves are in the run's key-value store.

### How much does it cost?

You pay a fixed price per **successful** screenshot; the exact price is on the **Pricing** tab. Failed pages are free. The run stops before going over the maximum cost per run you set, so you never pay more than you allowed.

### Tips

- Very long pages (infinite feeds, huge catalogs) produce very tall images. Turn off **Full page** if you only need what a visitor sees first.
- If a page still shows a popup, add its CSS selector to **Extra CSS selectors to hide**.
- For pages that load content after the initial load, use **Wait until: Network idle** or **Wait for selector**.

### Limitations

- Pages behind a login, a paywall or a CAPTCHA are captured as they appear to an anonymous visitor.
- Some sites block automated browsers. These pages are reported with their error and are not charged.
- Cookie banners from less common frameworks may still appear; hide them with your own selectors.

### Is it legal to take screenshots of websites?

Capturing publicly available pages is generally fine, but you are responsible for how you use the images, including copyright and the terms of the sites you capture. Don't use this Actor to collect personal data you have no legal basis for.

### Feedback

Found a bug or need a feature? Open an issue in the **Issues** tab and it will be looked at.

# Actor input Schema

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

Pages to screenshot. One screenshot per URL. Only http:// and https:// URLs are accepted.

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

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

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

Desktop uses the viewport size below. Mobile emulates an iPhone 13 and tablet an iPad (7th gen), including user agent and pixel ratio.

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

Browser window width for the desktop device.

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

Browser window height for the desktop device. With Full page on, it only affects how the page lays out.

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

PNG is lossless; JPEG files are much smaller.

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

From 1 to 100. Used only when the format is JPEG.

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

Hide the consent banners of common cookie frameworks (OneTrust, Cookiebot, Didomi, Usercentrics and others) with CSS. Nothing is clicked or accepted.

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

Any other elements to hide before the screenshot, such as chat widgets or popups.

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

Before a full-page screenshot, scroll through the page so lazy-loaded images appear.

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

How long to wait for the page before the capture. The DOM is always awaited; 'Page load' and 'Network idle' get up to 30 extra seconds, and pages that never finish loading (common on ad-heavy sites) are captured as they are instead of failing.

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

Optional CSS selector that must appear before the screenshot is taken.

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

Extra time to wait right before the screenshot, for animations.

## `timeoutSecs` (type: `integer`):

Maximum time to load each page. Pages that take longer are reported as failed and are not charged.

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

How many pages to screenshot in parallel.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://www.wikipedia.org"
    }
  ],
  "fullPage": true,
  "device": "desktop",
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "format": "png",
  "jpegQuality": 80,
  "hideCookieBanners": true,
  "hideSelectors": [],
  "scrollToBottom": true,
  "waitUntil": "load",
  "delayMs": 0,
  "timeoutSecs": 60,
  "maxConcurrency": 2
}
```

# Actor output Schema

## `results` (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": [
        {
            "url": "https://apify.com"
        },
        {
            "url": "https://www.wikipedia.org"
        }
    ],
    "hideSelectors": [],
    "waitForSelector": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("sturdyscrape/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": [
        { "url": "https://apify.com" },
        { "url": "https://www.wikipedia.org" },
    ],
    "hideSelectors": [],
    "waitForSelector": "",
}

# Run the Actor and wait for it to finish
run = client.actor("sturdyscrape/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": [
    {
      "url": "https://apify.com"
    },
    {
      "url": "https://www.wikipedia.org"
    }
  ],
  "hideSelectors": [],
  "waitForSelector": ""
}' |
apify call sturdyscrape/website-screenshot --silent --output-dataset

```

## MCP server setup

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