# Website Screenshot + Markdown for AI Agents (`ads_rifan/website-screenshot`) Actor

Full-page screenshots plus clean Markdown and metadata in one run. Removes cookie banners, loads lazy content. Ready for AI agents, RAG and LLMs.

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

## Pricing

from $5.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.

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 + Markdown for AI Agents

Capture pixel-perfect, clean full-page website screenshots at scale. Built from the ground up for **AI agents, MCP servers, visual regression testing, and automated page archiving**. It automatically eliminates intrusive cookie banners, triggers lazy-loaded images, handles mobile and desktop viewports, and provides instantly accessible public image URLs ready for multimodal LLMs.

***

### What does it do?

This Actor automates browser rendering via headless Chromium to take reliable, high-fidelity screenshots of public web pages. It handles common rendering roadblocks such as cookie consent banners, incomplete lazy loading, and dynamic layouts without requiring custom browser scripting.

#### Key Use Cases

- **AI Agents & MCP Workflows:** Provide multimodal language models (Claude, GPT, Gemini and other vision models) with clean visual snapshots of live web pages for visual web browsing, UI analysis, layout comprehension, and multimodal extraction.
- **Visual Monitoring & Defacement Detection:** Monitor landing pages, pricing tables, and user interfaces on a schedule to detect unwanted layout regressions, broken styling, unauthorized changes, or downtime.
- **Archiving & Visual QA:** Archive timestamped visual proof of legal disclosures, ad landing pages, or audit responsive web designs across desktop and mobile screen resolutions in batch.

***

### Why this one?

Standard headless screenshot tools often fail in real-world scenarios, producing images obscured by cookie dialogs, broken with half-loaded images, or difficult to pipe into automated pipelines. This actor is specifically tailored to solve these problems:

- **Cookie Banners & Consent Popups Removed:** Automatically dismisses common GDPR/CCPA consent modals using smart DOM button clicking and injects CSS rules to suppress fixed overlays that hide page content.
- **Lazy-Load & Dynamic Scrolling:** Executes a controlled auto-scroll sequence before capturing, ensuring lazy-loaded images, charts, and dynamic content render properly instead of appearing blank.
- **Desktop & Mobile Emulation:** Supports crisp desktop captures (1366×768 default) and mobile emulation (iPhone 13 profile), as well as custom viewport dimensions from small mobile screens up to 4K displays.
- **High-Throughput Batch Processing:** Pass between 1 and 1,000 URLs in a single run with configurable concurrency to maximize throughput without overloading resources.
- **Markdown + Metadata (included at no extra cost):** The same run also returns the page's main content as clean Markdown (navigation, footer, scripts and other chrome removed, relative links made absolute) plus metadata (`title`, `description`, `canonical`, `lang`, `ogImage`, `wordCount`, `linksCount`). Ideal for LLM context and RAG, with no second request.
- **LLM-Ready Output:** Automatically hosts images in Apify's Key-Value Store and outputs public image URLs (`screenshotUrl`) directly in the dataset, allowing multimodal LLMs to consume the image immediately without complex decoding.

***

### How much does it cost?

This actor uses a transparent **Pay-Per-Event** pricing model:

- **Price:** **$5 per 1,000 screenshots** (charged per successful capture).
- **Markdown and metadata are included:** Page content as Markdown and page metadata come with every successful screenshot at no extra cost; there is no separate event.
- **Pay only for success:** You are charged only when a screenshot is successfully captured and saved (`status: "ok"`). If a URL fails due to a DNS error, network timeout, or invalid target, you are **not** charged for that capture.
- **Predictable budgeting:** Set spend limits on your Apify account to ensure your runs never exceed your intended budget.

***

### Input

Configure the actor using the table below. All settings are passed via the standard JSON input object:

| Field | Type | Default | Description |
|---|---|---|---|
| `urls` | `Array<string>` | `["https://apify.com"]` | **Required.** List of 1–1,000 URLs to capture. Protocol is optional (defaults to `https://`). Invalid URLs will generate an error record without breaking the run. |
| `device` | `string` (`desktop` | `mobile`) | `"desktop"` | Preconfigured device profile. `desktop` uses 1366×768; `mobile` emulates an iPhone 13. |
| `viewportWidth` | `integer` | `null` | Custom viewport width in pixels (320–3840). When provided, overrides the device profile. |
| `viewportHeight` | `integer` | `null` | Custom viewport height in pixels (240–2160). When provided, overrides the device profile. |
| `fullPage` | `boolean` | `true` | When `true`, captures the full scrollable page height. When `false`, captures only the initial viewport. |
| `format` | `string` (`png` | `jpeg`) | `"png"` | Image format. Use `png` for lossless text/charts or `jpeg` for smaller file sizes. |
| `quality` | `integer` | `80` | Image compression quality (1–100). Applies only when `format` is `"jpeg"`. |
| `removeCookieBanners` | `boolean` | `true` | Automatically attempts to click accept buttons and hides sticky/modal consent overlays via CSS. |
| `scrollToBottom` | `boolean` | `true` | Automatically scrolls down the page before capture to trigger lazy-loaded media (capped at 10 seconds or 20 screens). |
| `hideSelectors` | `Array<string>` | `[]` | List of custom CSS selectors to hide before taking the screenshot (applied as `display: none !important;`). |
| `waitUntil` | `string` | `"load"` | Navigation wait condition: `"load"`, `"domcontentloaded"`, or `"networkidle"`. |
| `delayMs` | `integer` | `500` | Additional pause (0–10,000 ms) after the page is ready before triggering the capture. |
| `timeoutSecs` | `integer` | `30` | Navigation and rendering timeout per URL in seconds (5–120s). |
| `maxConcurrency` | `integer` | `3` | Number of web pages rendered concurrently (1–5). |

#### Example Input

```json
{
  "urls": [
    "https://apify.com",
    "https://news.ycombinator.com"
  ],
  "device": "desktop",
  "fullPage": true,
  "format": "png",
  "removeCookieBanners": true,
  "scrollToBottom": true,
  "delayMs": 500,
  "timeoutSecs": 30
}
```

***

### Output

Every run outputs items to both the **Dataset** and the **Key-Value Store**.

#### 1. Dataset Item Format

For each URL processed, a structured item is pushed to the default dataset:

```json
{
  "url": "https://apify.com",
  "finalUrl": "https://apify.com/",
  "status": "ok",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/a1b2c3d4/records/screenshot-c4ca4238a0b9-0",
  "key": "screenshot-c4ca4238a0b9-0",
  "format": "png",
  "width": 1366,
  "height": 4210,
  "bytes": 812345,
  "title": "Apify: Full-stack web scraping and data extraction platform",
  "device": "desktop",
  "truncated": false,
  "markdown": "# Apify

Full-stack web scraping and data extraction platform...

[Pricing](https://apify.com/pricing)",
  "markdownTruncated": false,
  "metadata": {
    "title": "Apify: Full-stack web scraping and data extraction platform",
    "description": "Cloud platform for web scraping, browser automation, and data for AI.",
    "canonical": "https://apify.com/",
    "lang": "en",
    "ogImage": "https://apify.com/og-image.png",
    "wordCount": 1250,
    "linksCount": 84
  },
  "error": null,
  "takenAt": "2026-10-29T22:45:00.000Z"
}
```

If a URL fails, an error item is recorded, allowing your batch processing to continue seamlessly:

```json
{
  "url": "https://invalid-domain-does-not-exist.xyz",
  "finalUrl": null,
  "status": "error",
  "screenshotUrl": null,
  "key": null,
  "format": "png",
  "width": null,
  "height": null,
  "bytes": null,
  "title": null,
  "device": "desktop",
  "truncated": false,
  "markdown": null,
  "markdownTruncated": false,
  "metadata": null,
  "error": "net::ERR_NAME_NOT_RESOLVED",
  "takenAt": "2026-10-29T22:45:02.000Z"
}
```

#### 2. Key-Value Store

Binary image files are stored directly in the default Key-Value Store using their unique `key` identifier with the proper MIME type (`image/png` or `image/jpeg`). The `screenshotUrl` provides a direct, accessible HTTP link to download or view the image.

***

### Use with AI Agents / MCP

This actor is purpose-built to integrate into autonomous agent architectures via the **Model Context Protocol (MCP)** or direct API calls.

#### 1. Using the Apify MCP Server

When using the `@apify/mcp-server` integration in environments like Claude Desktop, Cursor, or LangChain agents, add the actor to your MCP toolset. The agent can invoke the actor whenever visual verification or page inspection is needed:

```json
{
  "name": "apify/website-screenshot",
  "arguments": {
    "urls": ["https://example.com"],
    "fullPage": true,
    "removeCookieBanners": true
  }
}
```

The agent receives the dataset containing the `screenshotUrl`, which can be forwarded directly to multimodal vision models for prompt reasoning.

#### 2. Calling via Apify REST API

You can run the actor synchronously or asynchronously from any script:

```bash
curl -X POST "https://api.apify.com/v2/acts/<ACTOR_ID>/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://apify.com"],
    "fullPage": true,
    "format": "png"
  }'
```

#### 3. Calling via Python SDK

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run = client.actor("<ACTOR_ID>").call(run_input={
    "urls": ["https://apify.com"],
    "fullPage": True,
    "removeCookieBanners": True,
    "scrollToBottom": True
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item["status"] == "ok":
        print(f"Captured {item['url']} -> {item['screenshotUrl']}")
```

***

### FAQ

##### 1. How are cookie popups and consent banners dismissed?

The actor uses a multi-layered approach: it scans the DOM for commonly used consent dialog buttons (e.g., "Accept All", "Agree", "Allow Cookies") and clicks them. Concurrently, it injects custom CSS rules to hide prominent sticky overlays and backdrop dialogs that often obscure page content.

##### 2. What happens if a URL fails to load?

If a single URL fails due to a network error, DNS resolution failure, or timeout, it is marked as `status: "error"` in the output dataset with an informative error message. The actor continues processing the remaining URLs in your batch, and you are **not** charged for the failed item.

##### 3. Are the screenshots directly accessible by multimodal LLMs?

Yes. Each successful screenshot record includes a public `screenshotUrl` hosted in Apify's Key-Value Store. Multimodal vision models (Claude, GPT, Gemini and others) can fetch and inspect the visual layout directly using this URL.

##### 4. Is using this actor legal and compliant?

Yes. Capturing screenshots of publicly available web pages is a standard and legitimate web practice. However, **users are solely responsible for the URLs they submit** and must comply with the target websites' terms of service, copyright considerations, and applicable privacy regulations. This actor does not bypass paywalls or access private data.

##### 5. Can I capture full-length landing pages with heavy lazy loading?

Yes. Setting `scrollToBottom: true` directs the browser to perform an automated scrolling pass down the page (capped at 10 seconds or 20 screen heights) before snapping the picture. This triggers intersection observers and JavaScript lazy-loading scripts so images and components render completely.

***

### Limitations

- **Heavy Anti-Bot Defenses:** Websites protected by strict anti-bot systems, Cloudflare "Under Attack" mode, or interactive CAPTCHAs (such as Cloudflare Turnstile or reCAPTCHA) may block headless Chromium requests.
- **Authentication & Login Portals:** The actor is designed for publicly accessible pages. Pages requiring user login, single sign-on (SSO), or session cookies cannot be accessed without custom session credentials.
- **Infinite Scrolling Restraints:** Pages with infinite scrolling (such as social media feeds) will auto-scroll up to a safe threshold of 20 viewports or 10 seconds to avoid memory overflow and runaway run times.

# Actor input Schema

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

Public web page URLs to capture.

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

Desktop or mobile device profile used for the capture.

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

Optional viewport width that overrides the selected device.

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

Optional viewport height that overrides the selected device.

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

Capture the entire scrollable page instead of only the viewport.

## `maxHeightPx` (type: `integer`):

Full-page screenshots taller than this are truncated.

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

Image format used for the screenshot.

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

Compression quality used only for JPEG screenshots.

## `removeCookieBanners` (type: `boolean`):

Hide common cookie banners and click common accept buttons.

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

Scroll through the page to trigger lazy-loaded content.

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

CSS selectors for elements that should be hidden before capture.

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

Page lifecycle event to wait for before taking the screenshot.

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

Additional wait time in milliseconds before capture.

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

Maximum navigation time in seconds for each URL.

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

Maximum number of web pages captured in parallel.

## `outputMarkdown` (type: `boolean`):

Also return the page content as Markdown plus page metadata, at no extra cost.

## `maxMarkdownChars` (type: `integer`):

Markdown longer than this is truncated.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com"
  ],
  "device": "desktop",
  "fullPage": true,
  "maxHeightPx": 15000,
  "format": "png",
  "quality": 80,
  "removeCookieBanners": true,
  "scrollToBottom": true,
  "hideSelectors": [],
  "waitUntil": "load",
  "delayMs": 500,
  "timeoutSecs": 30,
  "maxConcurrency": 3,
  "outputMarkdown": true,
  "maxMarkdownChars": 100000
}
```

# Actor output Schema

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

No description

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

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

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

```

## MCP server setup

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