# Website Screenshot & URL to PDF API (Bulk) (`kelp_forest_labs/website-screenshot-pdf`) Actor

Capture public web pages or your own HTML as PNG, JPEG, WebP or PDF: full page, one element, or desktop/tablet/mobile presets. Bulk URLs, one file per page, and failed captures are free. Every browser request is checked, so internal addresses are never reached.

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

## Pricing

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

Capture public web pages, or HTML you paste in, as **PNG, JPEG, WebP or PDF**. Built for developers and AI agents
who need reliable captures in bulk.

### Use cases

- Archive pages or proofs of publication as PDF.
- Thumbnails and previews for directories, link pages and dashboards.
- Visual checks of landing pages on desktop and mobile before a launch.
- Render your own HTML (invoices, reports, certificates) to PDF or PNG.
- Give an AI agent a picture of a page it is working on.

### What it does

- One row per capture, with a link to the file in the run's key-value store.
- Bare domains work (`example.com` is opened as `https://example.com`); input that is not an http(s) address gets a
  free error row that says what a valid link looks like.
- Device presets (desktop, laptop, tablet, mobile) or a custom viewport; full-page or single-element (CSS selector) captures.
- PDF output with paper size (Letter, Legal, A4, A3, Tabloid) and backgrounds.
- Raw HTML mode for invoices, reports and social cards.

### Pricing (pay per event)

| Event | Price |
|---|---|
| `screenshot` (PNG/JPEG/WebP saved) | US$0.002 |
| `pdf` (PDF saved) | US$0.003 |

**Failed captures are free:** blocked targets, timeouts and pages answering HTTP 400 or higher produce an error row
and no charge.

Each run also has Apify's run-start charge of US$0.00005 per GB of run memory (US$0.0001 at the default 2048 MB),
charged when the run starts, even if every capture fails.

### How to use

1. Open the actor in Apify Console and fill in the input form (or paste the JSON example below into the JSON editor).
2. Optional: set a maximum charge for the run under the run options to cap what a run can cost.
3. Click **Start**. Results appear in the **Output** tab as they are produced; export them as JSON, CSV, Excel or HTML.

You can also start runs from the Apify API or CLI, run the actor on a schedule (for example weekly), and send
results to other apps with Apify integrations and webhooks.

### Input example

```json
{"urls": ["https://example.com/"], "format": "pdf", "pdfFormat": "A4"}
```

### Output example (one row, as on the platform)

```json
{"url": "https://example.com/", "format": "png", "status": "ok", "event": "screenshot", "httpStatus": 200, "key": "screenshot-4e3d5eb182a8.png", "fileUrl": "https://api.apify.com/v2/key-value-stores/<store-id>/records/screenshot-4e3d5eb182a8.png", "bytes": 20567, "seconds": 0.35}
```

### FAQ

**Can it capture pages behind a login or a cookie banner?**
No. It loads pages like a fresh visitor with no cookies; it does not log in, click banners away or solve captchas. Use `selector` to capture just the part you need.

**How long can a full-page capture be?**
Very long pages are captured in one image; extremely long pages may be cut by the browser's own image size limit. PDF has no such limit.

**What does a failed capture cost?**
Nothing. Timeouts, HTTP 4xx/5xx pages and blocked addresses produce an error row without a charge. The only cost of a
run where everything fails is Apify's run-start charge (US$0.00005 per GB of memory, US$0.0001 at the default 2048 MB).

**Where are the files?**
In the run's key-value store; each dataset row has `key` and a `fileUrl` link.

**Why is a sub-resource listed in `blockedRequests`?**
The page tried to load something from a private or internal address (for example 127.0.0.1 or a cloud metadata address). The guard refused it; the rest of the page was captured.

### Limits: what this actor does not do

- No logins, cookies, captcha solving or proxies to get around blocks. Login-walled pages are out of scope.
- No private, loopback or cloud-metadata addresses. Every browser request (the page, each redirect hop, images,
  scripts, frames, fetch/XHR, WebSockets) goes through a guard that refuses such addresses. If the page itself
  redirects there, you get a free `blocked_target` error row; if only some sub-resources are refused, the capture is
  saved and the refused hosts are listed in `blockedRequests`.
- It does not bypass paywalls or a site's terms. Only capture pages you are allowed to capture.

### Changelog

- 1.0 (October 2026): first public version.

# Actor input Schema

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

Public http(s) pages to capture. Private, loopback and login-walled pages are not supported.

## `html` (type: `string`):

Render this HTML instead of (or as well as) the URLs. Useful for invoices, reports and social cards.

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

PNG/JPEG/WebP are billed as 'screenshot', PDF as 'pdf'.

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

Viewport and pixel ratio preset.

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

Overrides the preset width.

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

Overrides the preset height.

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

Capture the whole scrollable page (images only).

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

Capture only this element (images only).

## `waitMs` (type: `integer`):

Wait after the load event, for animations or late content.

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

Navigation timeout.

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

Ignored for PNG and PDF.

## `pdfFormat` (type: `string`):

Only for PDF output.

## Actor input object example

```json
{
  "urls": [
    "https://example.com/"
  ],
  "format": "png",
  "device": "desktop",
  "fullPage": false,
  "waitMs": 0,
  "timeoutSecs": 30,
  "quality": 85,
  "pdfFormat": "Letter"
}
```

# Actor output Schema

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

One row per URL or HTML input with the key and URL of the saved file, or a free error row.

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

Every captured PNG, JPEG, WebP or PDF file in the run's key-value store.

# 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://example.com/"
    ]
};

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

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kelp_forest_labs/website-screenshot-pdf"
        }
    }
}
```

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/GGUU77Mu7ILZ0lcjp/builds/i6uqEFzV7PQtsoKTj/openapi.json
