# Website Screenshot API - Fast & Cheap (PNG, JPEG, WebP, PDF) (`northledgertools/website-screenshot`) Actor

Capture screenshots of any website in bulk: full page or viewport, desktop/tablet/mobile presets, PNG/JPEG/WebP/PDF, dark mode, cookie-banner and ad blocking. Pay only per successful screenshot. Works great with AI agents and MCP.

- **URL**: https://apify.com/northledgertools/website-screenshot.md
- **Developed by:** [NorthLedger Tools](https://apify.com/northledgertools) (community)
- **Categories:** Developer tools, Automation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 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?

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: fast, cheap, bulk (PNG, JPEG, WebP, PDF)

**Website Screenshot API** captures screenshots of any web page in bulk. Give it a list of URLs and it returns one image per page: full-page or viewport, desktop, tablet or mobile, PNG, JPEG, WebP or PDF. Cookie banners and ads are hidden automatically. You pay **only for screenshots that succeed** (US$0.80 per 1,000), plus standard Apify platform usage.

It runs a real Chromium browser (Playwright), so JavaScript-heavy sites, single-page apps and lazy-loaded images render the way a visitor sees them.

### What can this website screenshot tool do?

- 📸 **Bulk screenshots**: send 1 URL or 10,000. Pages are captured in parallel.
- 📄 **Full-page or viewport**: scroll-and-capture whole pages (lazy images are loaded first) or only the visible area.
- 📱 **Device presets**: Desktop 1366×768, Desktop HD 1920×1080, Laptop, Tablet (iPad), Mobile (iPhone 13), Mobile (Pixel 7). Custom width, height and retina pixel ratio are also available.
- 🖼️ **PNG, JPEG, WebP or PDF**, with adjustable quality.
- 🍪 **Hide cookie banners** (OneTrust, Cookiebot, Didomi, Quantcast, Sourcepoint, generic "Accept" pop-ups) and 🚫 **block ads and trackers** (best effort).
- 🌙 **Dark mode** (`prefers-color-scheme: dark`).
- ⏱️ **Wait options**: extra delay, wait for a CSS selector, or wait for network idle.
- 🎯 **Element screenshots**: capture a single element, e.g. `header` or `.pricing-table`.
- 🙈 **Hide elements** such as chat widgets or sticky headers.
- 🔒 **Safe by default**: only public `http(s)` URLs; private and local network addresses are refused.
- 🌍 **Optional proxy** to capture a site as seen from another country.

### Use cases

- **Visual monitoring and archiving**: snapshot competitor pages, landing pages or prices daily with an Apify schedule.
- **SEO and marketing reports**: thumbnails of SERP results, client sites or backlinks.
- **QA and responsive testing**: compare desktop vs mobile layouts and dark mode.
- **Link previews and directories**: generate thumbnails for bookmarks, catalogs or newsletters.
- **AI agents and LLM vision**: let an agent "look" at a web page; feed the image URL to a vision model.
- **Compliance and evidence**: dated captures of web pages (each item has a `capturedAt` timestamp).

### How to use it

1. Click **Try for free**.
2. Paste your URLs (one per line).
3. Pick full-page or viewport, a device and an image format.
4. Click **Start**. The images appear in the **Output** tab, each with a direct link.

#### Example input

```json
{
    "urls": ["https://apify.com", "https://en.wikipedia.org/wiki/Screenshot"],
    "fullPage": true,
    "devicePreset": "mobile",
    "format": "webp",
    "quality": 80,
    "darkMode": false,
    "blockCookieBanners": true,
    "blockAds": true,
    "delayMs": 500,
    "timeoutSecs": 30
}
```

#### Example output (one dataset item per URL)

```json
{
    "url": "https://apify.com/",
    "status": "success",
    "screenshotUrl": "https://api.apify.com/v2/key-value-stores/AbC123/records/screenshot-apify.com-d385e6e04d.webp",
    "screenshotKey": "screenshot-apify.com-d385e6e04d.webp",
    "finalUrl": "https://apify.com/",
    "httpStatus": 200,
    "title": "Apify: Full-stack web scraping and data extraction platform",
    "width": 390,
    "height": 5461,
    "deviceScaleFactor": 3,
    "format": "webp",
    "fullPage": true,
    "sizeBytes": 412345,
    "durationMs": 4120,
    "error": null,
    "errorType": null,
    "capturedAt": "2026-10-18T13:05:00.000Z"
}
```

Failed pages are still listed, with `status: "failed"`, an `error` message and an `errorType` (`TIMEOUT`, `DNS_ERROR`, `CONNECTION_ERROR`, `SSL_ERROR`, `HTTP_ERROR`, `SELECTOR_TIMEOUT`, `SELECTOR_NOT_FOUND`, `INVALID_URL`, `BLOCKED_URL`). **Failed pages are never charged.**

The images are stored in the run's default key-value store. Open `screenshotUrl` directly, or download them all from the **Storage** tab.

### Pricing

Pay per event, with no subscription:

| Event | Price |
| --- | --- |
| Successful screenshot (any format) | **US$0.0008** (US$0.80 per 1,000) |
| Actor start | US$0.00005 per run (per GB of memory) |

- Failed, timed-out and skipped pages are free.
- Standard Apify platform usage (compute and storage) is billed separately at your plan's rates. Viewport captures at the default 2 GB usually take only a few seconds.
- Set **Maximum cost per run** in the run options to cap spending. The Actor stops cleanly when the limit is reached.

Example: 1,000 screenshots cost **US$0.80** in event fees, plus platform usage.

### Use it from AI agents, MCP and the API

This Actor is a good fit for agents: one URL in, one image URL out, with structured errors.

**Apify MCP server** (Claude, Cursor, VS Code, any MCP client): add `https://mcp.apify.com/?actors=northledgertools/website-screenshot` as an MCP server. Your agent gets a tool that takes `urls` and returns screenshot links.

**HTTP API (synchronous)**: run it and get the dataset back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/northledgertools~website-screenshot/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://example.com"],"format":"jpeg","quality":70}'
```

**JavaScript**

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('northledgertools/website-screenshot').call({ urls: ['https://example.com'], fullPage: true });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].screenshotUrl);
```

**Python**

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("northledgertools/website-screenshot").call(run_input={"urls": ["https://example.com"]})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["screenshotUrl"])
```

It also works with Make, Zapier, n8n, LangChain and LlamaIndex through Apify's integrations.

### Tips for the best screenshots

- **Cheaper and faster**: use JPEG or WebP at quality 70–80, and viewport mode when you don't need the whole page.
- **Charts and animations**: raise `delayMs` (e.g. 2000) or set `waitForSelector`.
- **Very long pages** are cut at `maxFullPageHeight` (15,000 px by default); the item then has `fullPageTruncated: true`.
- **Error pages**: by default, pages that return HTTP 4xx/5xx are still captured, since a screenshot of an error page is often useful. Turn on **Fail on HTTP errors** to skip them (they are then free).
- **Memory**: 1 GB is enough for most jobs (about 2 pages in parallel). Use 2–4 GB for big batches of full-page captures.

### Limitations

- Cookie-banner and ad blocking is best effort; unusual pop-ups may still show. Use **Hide elements** for those.
- Sites behind logins, CAPTCHAs or strong bot protection may show a challenge page instead of the content.
- Dark mode only works on sites that support `prefers-color-scheme`.

### FAQ

**Is it legal to screenshot websites?** Capturing publicly available pages is generally fine, but respect each site's terms and copyright and don't capture personal data without a legal basis.

**How long are images kept?** As long as your Apify plan keeps the run's storage (7 days on the free plan). Download them, or copy them to your own storage, if you need them longer.

**Can I request a feature?** Yes, open an issue in the **Issues** tab. Requests are usually handled quickly.

# Actor input Schema

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

Web pages to capture, one per line. The https:// prefix is added automatically if you leave it out. Each URL produces one dataset item and one image.

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

Capture the whole scrollable page instead of only the visible viewport. Lazy-loaded images are triggered by scrolling first.

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

Emulated device. Desktop presets use a desktop browser; tablet and mobile presets emulate the real device (viewport, pixel ratio, touch, user agent).

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

Optional. Overrides the preset's viewport width (200-3840).

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

Optional. Overrides the preset's viewport height (200-4320). For full-page screenshots this is only the initial viewport.

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

Optional. 2 gives retina-quality images (twice the pixels). Defaults to the preset's value.

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

PNG is lossless; JPEG and WebP are much smaller. PDF renders the page as a PDF document.

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

Compression quality from 1 to 100. Ignored for PNG and PDF.

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

Ask the page to render its dark theme (prefers-color-scheme: dark). Only works on sites that support it.

## `blockCookieBanners` (type: `boolean`):

Best effort: clicks 'Accept' on common consent pop-ups (OneTrust, Cookiebot, Didomi, Quantcast and more) and hides remaining banners.

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

Best effort: blocks requests to common ad networks and trackers. Also makes pages load faster.

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

Page load event to wait for before capturing. 'networkidle' is slowest but most complete.

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

Wait this long after the page loads, e.g. for animations or charts to finish.

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

Optional. Wait until an element matching this CSS selector is visible before capturing (e.g. '#main-chart').

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

Optional. CSS selector of a single element to screenshot instead of the page (e.g. 'header' or '.pricing-table').

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

Optional. CSS selectors of elements to hide before capturing (chat widgets, sticky headers, pop-ups).

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

Maximum time to load a page or wait for a selector. Slow pages that exceed it are reported as failed (and not charged).

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

How many times to retry a page after a network error or timeout.

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

Very long pages are cut at this height to keep images usable.

## `skipHttpErrors` (type: `boolean`):

If on, pages that return HTTP 4xx/5xx are reported as failed (not charged) instead of being captured.

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

Pages captured in parallel. Defaults to 1 per GB of memory (Apify gives 1 CPU core per 4 GB).

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

Browser locale, e.g. en-US, fr-CA, de-DE. Affects which language some sites show.

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

Optional. Use Apify Proxy or your own proxies, e.g. to capture a site as seen from another country. Off by default.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://example.com"
  ],
  "fullPage": false,
  "devicePreset": "desktop",
  "format": "png",
  "quality": 80,
  "darkMode": false,
  "blockCookieBanners": true,
  "blockAds": true,
  "waitUntil": "load",
  "delayMs": 500,
  "timeoutSecs": 30,
  "maxRetries": 1,
  "maxFullPageHeight": 15000,
  "skipHttpErrors": false,
  "locale": "en-US",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset with one item per URL. Each successful item has a screenshotUrl that links directly to the image. Failed items have status 'failed', error and errorType.

## `screenshotFiles` (type: `string`):

Image/PDF files (PNG, JPEG, WebP or PDF) saved in the default key-value store, keys prefixed with 'screenshot-'.

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

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

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

```

## MCP server setup

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