# SnapScout: Website Screenshot API for AI Agents (Image + Text) (`cybermax/website-screenshot`) Actor

Let your agent see and read any web page. URLs in, one record each: a public screenshot URL (PNG/JPEG, viewport, full page or element) plus HTTP status, final URL, title, meta and clean page text. Cookie banners clicked away. $0.003 per screenshot, failures free.

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

## Pricing

$3.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

## SnapScout: website screenshot API for AI agents (image + text)

**Let your agent see any web page, and read it too.** One call per URL returns a public screenshot
URL plus the page's status, title, meta tags and clean visible text, with cookie banners already
clicked away.

### Why SnapScout

- **Clean shots.** Consent banners (OneTrust, Cookiebot, Didomi, Quantcast, TrustArc, Usercentrics,
  CookieYes and plain "Accept all" buttons in 10+ languages) are dismissed before capture, so you
  see the page, not the overlay.
- **Image and text in one record.** Agents can read the page without a vision model, and QA scripts
  can diff status, title and text without comparing images.
- **$0.003 per screenshot, failures free.** Unreachable pages, timeouts and missing selectors aren't
  charged.

**Example record (trimmed):**

```json
{ "url": "https://example.com/", "ok": true, "httpStatus": 200, "title": "Example Domain",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/…/records/001-example-com.png",
  "text": "Example Domain\nThis domain is for use in documentation examples…", "cookieBannerDismissed": false }
```

### What you get

Give it URLs. For each one you get **one record**:

- a **public screenshot URL** (PNG or JPEG; first screen, full page or one element)
- the **HTTP status** and **final URL** after redirects
- **title**, **meta description**, first **H1**, language, canonical URL and og:image
- the page's **visible text**, cleaned and cut to the length you choose, so an agent can read the page without a vision model
- whether a **cookie banner** was clicked away, plus a `warning` if the page never finished loading

### Who it's for

- **AI agents and MCP clients** that need to *see* a page ("what does competitor.com's pricing page look like?", "did the deploy break the homepage?") or quote it with evidence.
- **QA and monitoring:** screenshot a list of pages on every deploy; the status, title and text let you diff without comparing images.
- **Sales and research:** one image plus summary facts per prospect website.
- **Content and SEO:** capture title, description, H1 and og:image next to how the page actually renders.

### Input

```json
{
  "urls": ["https://apify.com", "example.com", "https://stripe.com/pricing"],
  "device": "desktop",
  "fullPage": false,
  "format": "png",
  "includeText": true,
  "maxTextChars": 4000
}
```

| Field | Default | What it does |
|---|---|---|
| `urls` | required | Full URLs or bare domains. One record each; duplicates skipped. |
| `device` | `desktop` | `desktop` 1366x768, `laptop` 1920x1080, `tablet` 820x1180 @2x, `mobile` 390x844 @2x. |
| `fullPage` | `false` | Whole scrollable page (scrolls first so lazy images load), capped at `maxFullPageHeight` (15,000 px). |
| `selector` | none | Capture one element, e.g. `#pricing`. |
| `format` / `jpegQuality` | `png` / 80 | JPEG is 3-10x smaller, good for vision models. |
| `includeText` / `maxTextChars` | `true` / 4000 | Visible text of `main`/`article` (else `body`). |
| `dismissCookieBanners` | `true` | Click "accept", then hide leftover overlays. |
| `waitUntil` | `load` | `domcontentloaded`, `load` or `networkidle`, best effort up to 15 s. Pages that never settle are still captured, with a warning. |
| `delaySecs` | 1 | Extra wait after loading. |
| `includeImageBase64` | `false` | Also embed the image bytes in the record. |
| `viewportWidth` / `viewportHeight` | device | Custom viewport. |
| `maxConcurrency` | 2 | Pages captured in parallel (1-8). |

### Output

One dataset item per URL:

```json
{
  "url": "https://example.com/",
  "ok": true,
  "httpStatus": 200,
  "finalUrl": "https://example.com/",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/…/records/001-example-com.png",
  "title": "Example Domain",
  "description": null,
  "h1": "Example Domain",
  "lang": "en",
  "text": "Example Domain\nThis domain is for use in documentation examples without needing permission. …",
  "textChars": 127,
  "textTruncated": false,
  "cookieBannerDismissed": false,
  "device": "desktop",
  "viewport": { "width": 1366, "height": 768 },
  "fullPage": false,
  "format": "png",
  "bytes": 19675,
  "pageHeight": 768,
  "linkCount": 1,
  "loadMs": 1840,
  "capturedAt": "2026-09-23T15:20:00.000Z"
}
```

Failed pages come back with `"ok": false` and an `error` (for example `net::ERR_NAME_NOT_RESOLVED` or `selector not found: #pricing`) and are **not charged**. Pages that return 404 or 500 are still captured, with their status, because that's often what you want to see.

The images are also in the run's key-value store (`001-example-com.png`, `002-…`), in input order.

### Pricing

**$0.003 per screenshot captured**, with no start fee and no subscription. Failed pages are free. 1,000 screenshots cost $3.

### Use it from an AI agent

- **Apify MCP server** (`https://mcp.apify.com`): add the Actor `cybermax/website-screenshot` and call it with `{"urls": [...]}`. Agents without an Apify account can pay per call through Apify's agentic payments.
- **API:** `POST https://api.apify.com/v2/acts/cybermax~website-screenshot/run-sync-get-dataset-items?token=<TOKEN>` with the input JSON returns the records directly.

### When not to use it

- **You only need the text or HTML.** A plain fetcher is cheaper and faster.
- **Pages behind a login, CAPTCHA or strong bot protection.** This Actor uses a normal headless Chrome with no proxy, so some sites (large retailers, social networks) may show a block page. The record still tells you what was shown.
- **Pixel-perfect visual regression.** Fonts, ads and A/B tests change between captures.

### Limits and notes

- Chrome runs headless on Apify, with no proxy by default. Geo-specific content reflects Apify's data-centre location (US/EU).
- Full-page captures are capped at 15,000 px tall by default (configurable up to 30,000); longer pages are cut, with a `warning`.
- Records are returned in completion order; `screenshotKey` numbers follow input order.

Built by CyberMax. More tools: [apify.com/cybermax](https://apify.com/cybermax).

# Actor input Schema

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

Pages to capture. Full URLs or bare domains ("example.com" becomes https://example.com/). One screenshot record per URL; duplicates are skipped.

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

Viewport and user agent: desktop 1366x768, laptop 1920x1080, tablet 820x1180 @2x, mobile 390x844 @2x.

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

Capture the whole scrollable page instead of the first screen. Scrolls first so lazy images load. Capped at 'Max full-page height'.

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

CSS selector of one element to capture instead of the page, e.g. "#pricing" or "main". The record fails with 'selector not found' if it isn't there.

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

PNG is lossless; JPEG is 3-10x smaller, better for vision models and long pages.

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

30-100. Only used when the format is JPEG.

## `includeText` (type: `boolean`):

Return the visible text of the page (main/article if present, else body), whitespace-cleaned, so an agent can read the page without looking at the image.

## `maxTextChars` (type: `integer`):

Cut the page text at this many characters (0-50000). 'textChars' always reports the full length.

## `dismissCookieBanners` (type: `boolean`):

Click 'accept' on common consent platforms (OneTrust, Cookiebot, Didomi, Quantcast, TrustArc, Usercentrics, CookieYes and plain 'Accept all' buttons in 10+ languages), then hide leftover overlays.

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

Page state to wait for before capturing (best effort, up to 15 s after the HTML has loaded; pages that never settle are still captured, with a warning).

## `delaySecs` (type: `integer`):

Wait this long after loading, for animations and late content. 0-30.

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

Optional. Overrides the device width (320-3840).

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

Optional. Overrides the device height (320-4320).

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

Longer pages are cut at this height (1000-30000), with a warning in the record.

## `includeImageBase64` (type: `boolean`):

Also put the image bytes in the record as base64 (for agents that can't fetch URLs). Makes records large; prefer JPEG with this.

## `navigationTimeoutSecs` (type: `integer`):

How long to wait for the page's HTML (5-120).

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

How many pages to capture at once (1-8). Heavy pages share the CPU, so more is not always faster.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://example.com"
  ],
  "device": "desktop",
  "fullPage": false,
  "format": "png",
  "jpegQuality": 80,
  "includeText": true,
  "maxTextChars": 4000,
  "dismissCookieBanners": true,
  "waitUntil": "load",
  "delaySecs": 1,
  "maxFullPageHeight": 15000,
  "includeImageBase64": false,
  "navigationTimeoutSecs": 30,
  "maxConcurrency": 2
}
```

# Actor output Schema

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

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

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

```

## MCP server setup

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