# Website Screenshot API: Full-Page, Mobile & Bulk URL Capture (`birchwood-data/website-screenshot-api`) Actor

Capture full-page or viewport screenshots of any URLs in bulk: desktop, tablet and mobile, PNG or JPEG, cookie banners hidden, lazy-loaded images included. Returns a public image URL plus title, final URL and HTTP status. Pay only for successful shots.

- **URL**: https://apify.com/birchwood-data/website-screenshot-api.md
- **Developed by:** [Birchwood Data](https://apify.com/birchwood-data) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 screenshot captureds

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 API: Full-Page, Mobile & Bulk URL Capture

Turn any list of URLs into **clean, full-page screenshots** for desktop, tablet and mobile, in bulk, at a low per-image price. Each result includes a **public image URL** you can drop into a spreadsheet, a Slack/Zapier/Make/n8n workflow, a report or an AI agent, along with the page title, final URL after redirects, HTTP status and load time.

**You pay only for successful screenshots.** URLs that fail (DNS errors, timeouts, crashes) are retried automatically and, if they still fail, reported in the dataset with the error and **not charged**.

### What can this website screenshot tool do?

- 📸 **Full page or viewport.** Lazy-loaded images are scrolled into view first.
- 📱 **Device presets**: Desktop 1366, Desktop HD 1920, Laptop 1280, Tablet (2x), Mobile iPhone (3x, mobile user agent). Pick several to get one image per device, or set a custom width and height.
- 🍪 **Cookie banners hidden** (OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast…) with CSS only. Nothing is clicked or accepted for you.
- 🎯 **Capture one element** (`#pricing`, `main`), **wait for a selector**, add an **extra delay**, **hide elements** (chat widgets), use **dark mode** or **block videos**.
- 🖼️ **PNG or JPEG** (quality setting), with a max-height cap for very long pages.
- 🔁 **Retries in a fresh browser context**, per-page timeouts and parallel pages.
- 🌍 Optional **proxy**, to see a page as it looks from another country.

### Use cases

Visual monitoring and change tracking, SEO and competitor snapshots, website archiving and compliance evidence, link previews and thumbnails, QA of responsive layouts, and feeding page images to vision LLMs.

More use cases:

- **Visual website monitoring:** schedule daily captures of pricing pages or landing pages and compare them over time.
- **SEO and competitor research:** archive what competitors' homepages and SERP landing pages looked like on a given date.
- **Link previews and thumbnails:** generate preview images for directories, newsletters or internal tools.
- **Responsive QA:** capture the same URL on desktop, tablet and mobile in one run.
- **Vision LLM input:** send page images to GPT-4o, Claude or Gemini for layout or content analysis.
- **Compliance evidence:** keep timestamped page captures (`takenAt`) for audits.

### Input example

```json
{
  "urls": [{ "url": "https://apify.com" }, { "url": "https://www.bbc.com/news" }],
  "devices": ["desktop", "mobile"],
  "fullPage": true,
  "format": "jpeg",
  "quality": 80,
  "hideCookieBanners": true
}
```

### Output

One dataset item per URL and device. The images are stored in the run's key-value store, and `screenshotUrl` links straight to the image file. Here's a real item from a test run (store ID replaced):

```json
{
  "url": "https://example.com",
  "finalUrl": "https://example.com/",
  "device": "mobile",
  "httpStatus": 200,
  "success": true,
  "title": "Example Domain",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/example-com-mobile-327c3fda.png",
  "screenshotKey": "example-com-mobile-327c3fda.png",
  "format": "png",
  "fullPage": true,
  "viewportWidth": 390,
  "viewportHeight": 844,
  "bytes": 254295,
  "loadTimeMs": 851,
  "attempts": 1,
  "error": null,
  "takenAt": "2026-10-26T13:54:51+00:00"
}
```

A failed URL looks like this and is not charged:

```json
{ "url": "https://this-domain-does-not-exist-xyz123.com", "device": "mobile", "success": false,
  "error": "Page.goto: net::ERR_CONNECTION_CLOSED at https://this-domain-does-not-exist-xyz123.com/", "screenshotUrl": null }
```

The dataset's **Screenshots** view shows image thumbnails right in the Console table. A `RUN_SUMMARY` record shows the succeeded and failed counts.

### Pricing

Pay per event: **screenshot**, charged once for each image successfully saved. Failures are free. See the Pricing tab for the current price. Set *Max cost per run* and the Actor stops cleanly at your budget.

### Tips

- Use **JPEG** for long pages: it's much smaller than PNG.
- With many URLs, raise **Parallel pages** together with memory (minimum 2 GB; about 512 MB per parallel page).
- For single-page apps, use `waitUntil: networkidle` or `waitForSelector`.
- Images are kept for your plan's storage retention period. Copy them elsewhere if you need them long-term.

### Is it legal?

Screenshots capture what any visitor sees on a public page. Don't capture pages behind logins you aren't authorized to use, and respect copyright when you reuse images.

### Other Actors by Birchwood Data

Our Actors are built to chain together: **find companies → find their job boards → scrape every job → screenshot or structure the results.**

| Actor | What it does |
| --- | --- |
| [ATS Job Scraper](https://apify.com/birchwood-data/ats-job-scraper) | Jobs from Greenhouse, Lever, Ashby, SmartRecruiters and Recruitee career pages, with salary, remote flag and new/removed-job tracking. |
| [Workday Jobs Scraper](https://apify.com/birchwood-data/workday-jobs-scraper) | Jobs from any Workday (myworkdayjobs.com) career site: NVIDIA, Salesforce, Adobe and thousands more. Same core fields as ATS Job Scraper. |
| [Y Combinator Scraper](https://apify.com/birchwood-data/yc-companies-scraper) | The full YC startup directory with an optional job-board finder. Its `atsBoardUrl` output feeds straight into the two job scrapers. |
| [Text to JSON](https://apify.com/birchwood-data/text-to-data) | Turn job descriptions, emails or PDFs into JSON matching your own schema. For example, pull skills or tech stack out of `descriptionText`. |

**Example pipeline:** Y Combinator Scraper (`onlyHiring`, `detectCareersPage`) → feed the `atsBoardUrl` values into ATS Job Scraper or Workday Jobs Scraper → schedule daily with `onlyNewJobs` → send new jobs to Slack, Google Sheets or your ATS via Apify integrations.

### Support

Found a bug or need a feature? Open an issue on the **Issues** tab and we will get back to you as soon as possible.

# Actor input Schema

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

Pages to capture (full URLs, e.g. https://example.com). Add many at once with Bulk edit or a text file.

## `devices` (type: `array`):

One screenshot per URL per device.

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

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

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

Very long pages are cut at this height to keep files usable (0 = no limit).

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

PNG (lossless) or JPEG (smaller files).

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

Only for JPEG.

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

Overrides Devices when set (0 = use Devices).

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

Used with custom width (default 900).

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

Page-load event to wait for. 'networkidle' is most complete but slower.

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

Wait for animations/charts.

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

Capture only after this element appears.

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

e.g. '#pricing' or 'main'. Leave empty for the page.

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

Scrolls the page before a full-page capture so lazy-loaded images render.

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

Hides common consent popups (OneTrust, Cookiebot, Didomi, Usercentrics...) with CSS. Nothing is clicked or accepted.

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

e.g. chat widgets: '#intercom-container'.

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

Emulate prefers-color-scheme: dark.

## `blockVideos` (type: `boolean`):

Faster loads on video-heavy pages.

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

Per attempt.

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

Failed attempts are retried in a fresh browser context.

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

Raise together with memory.

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

Optional, e.g. to capture a page as seen from another country.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://apify.com"
    }
  ],
  "devices": [
    "desktop"
  ],
  "fullPage": true,
  "maxFullPageHeight": 15000,
  "format": "png",
  "quality": 80,
  "viewportWidth": 0,
  "viewportHeight": 0,
  "waitUntil": "load",
  "delayMs": 0,
  "scrollToBottom": true,
  "hideCookieBanners": true,
  "darkMode": false,
  "blockVideos": false,
  "timeoutSecs": 45,
  "maxRetries": 2,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `screenshots` (type: `string`):

Results with screenshot links and page metadata.

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

All captured images (key-value store).

## `runSummary` (type: `string`):

Succeeded / failed counts.

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

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

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

```

## MCP server setup

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