# Website Screenshot & URL to PDF - Full Page, Bulk, HTML (`pennydata/shot-pdf`) Actor

Full page website screenshot and URL to PDF in bulk with headless Chromium. HTML to PDF, clip, viewport and paper size. Failed pages are never billed.

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

## Pricing

Pay per event

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 & URL to PDF - from $0.002/shot

**Website screenshot API and URL to PDF converter**: turn any public URL, or your own HTML, into a PNG/JPEG screenshot and/or a PDF using real headless Chromium. Each result gets a direct file link in the run's key-value store. You pay only for captures that succeeded; timeouts, 4xx/5xx pages and rejected URLs cost nothing.

**Free to try:** a new Apify account includes free monthly platform credit, enough to validate the output on a few dozen captures before you pay anything. This Actor has no hidden minimums: failed items are never billed.

### How to use Website Screenshot & PDF API

1. Add public page URLs to **urls**, or inline HTML to **htmlDocuments**.
2. Choose **mode**: screenshot, pdf or both; set full-page, format and viewport.
3. Click **Start**.
4. Read `screenshotUrl` / `pdfUrl` from each dataset row, or call the Actor from the API.

### Pricing

Pay per event, no subscription and no compute fees on top. Price: **$0.002 per screenshot, $0.004 per PDF**.

| Event | When it is charged | Price |
|---|---|---|
| `screenshot` | One screenshot (PNG/JPEG) produced successfully. | $0.002 |
| `pdf` | One PDF produced successfully. | $0.004 |

Failed, blocked or unknown items are not billed. Set a maximum cost per run in the run options to cap spend.

### Example input

```json
{
  "urls": [
    {
      "url": "https://example.com"
    }
  ],
  "mode": "both",
  "fullPage": true,
  "pdfFormat": "A4"
}
```

### Example output

Illustrative sample of the output shape (abridged).

```json
{
  "input": "https://example.com",
  "finalUrl": "https://example.com/",
  "httpStatus": 200,
  "title": "Example Domain",
  "screenshotUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/screenshot-<id>.png",
  "pdfUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/pdf-<id>.pdf",
  "capturedAt": "2026-10-15T12:00:00.000Z"
}
```

### Details and limits

Capture a **PNG/JPEG screenshot** and/or a **PDF** of any public web page, or render your own **HTML** to PDF/screenshot, with a real headless Chromium (Playwright + Crawlee). You get a dataset row per page with direct links to the files stored in the run's key-value store.

### What it does

- Input: list of public `http(s)` URLs and/or inline HTML strings.
- Output per item: `input`, `finalUrl`, `httpStatus`, `title`, `screenshotUrl`, `pdfUrl`, file sizes, `capturedAt`. Failed items get an `error` row and are **not charged**.
- Options: screenshot / PDF / both, full-page, PNG or JPEG, viewport size, wait-until, extra delay, wait for a CSS selector, PDF paper size, landscape, print backgrounds.
- Polite and robust: max 60 page loads/minute, default concurrency 3, automatic retries (default 3), 45 s navigation timeout.

### Limits and honesty notes

- No login, no cookies injection, no captcha solving, no proxy rotation to bypass blocks. Pages behind logins, bot walls or captchas may fail or capture the block page; that is expected.
- Only public `http(s)` URLs: localhost, private IP ranges and `file:` URLs are rejected.
- You are responsible for having the right to capture the pages you submit. No personal data is collected by the Actor itself; captures contain whatever the page shows.
- Not a scraper: it returns images/PDFs, not structured page data.

### Other Actors in this family

| Actor | What it does | Price |
|---|---|---|
| Bulk Email Validator | Bulk email validator: syntax, MX records, disposable and role-address flags, typo hints. | $0.001 per event |
| Shopify Products Scraper | Scrape products, prices, variants and stock from public Shopify stores via products. | $0.001 per event |
| Website Tech Stack Detector | Detect the CMS, ecommerce platform, analytics, CDN and JS framework of any website list from headers, meta, scripts and cookie names. | $0.005 per event |
| Bulk WHOIS Domain Lookup (RDAP) | Bulk WHOIS via official RDAP + DNS: availability, registrar, created/expiry dates, age, nameservers, MX, TXT. | $0.002 per event |
| Greenhouse Lever Ashby Job Scraper | Scrape normalized job postings from Greenhouse, Lever and Ashby job boards by company slug, with keyword, location and remote filters. | $0.001 per event |
| PDF Text & Metadata Extractor | Extract text per page, page count, metadata and table-like rows from PDF URLs. | $0.002 per event |

Find them on this publisher's Apify Store profile.

### FAQ

**Can it get past logins, bot walls or captchas?**\
No. No cookie injection, captcha solving or proxy evasion is used; such pages may fail (not billed) or capture the block page.

**Is it legal?**\
You are responsible for having the right to capture the pages you submit. localhost, private IPs and file: URLs are rejected.

**Need a custom field, a higher volume or a different source?**\
Open an issue on the Actor page and describe what you need; custom variants are possible.

**Is it maintained?**\
Yes. Reports of breakage are answered through the Issues tab, and runs that fail are not billed.

Built with AI assistance (Claude); maintained by the publisher.

# Actor input Schema

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

Public http(s) pages to capture.

## `htmlDocuments` (type: `array`):

Optional inline HTML strings to render (HTML to PDF/screenshot).

## `mode` (type: `string`):

What to produce for each page.

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

Image format for screenshots: png (lossless) or jpeg (smaller).

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

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

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

Browser viewport width in pixels (200-3840).

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

Browser viewport height in pixels (200-4000).

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

Page lifecycle event to wait for before capturing: load, domcontentloaded or networkidle.

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

Extra wait after the page is ready and before capture, in milliseconds.

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

Optional selector to wait for (max 15s) before capture.

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

Paper size used for PDF output (A4, Letter, Legal or A3).

## `pdfLandscape` (type: `boolean`):

Render PDFs in landscape orientation instead of portrait.

## `pdfPrintBackground` (type: `boolean`):

Include CSS background colors and images in PDFs.

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

Maximum number of pages captured in parallel (1-10).

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

How many times a failed page is retried before it is reported as failed (0-5).

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://example.com"
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping"
    }
  ],
  "mode": "screenshot",
  "format": "png",
  "fullPage": true,
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "waitUntil": "load",
  "delayMs": 500,
  "pdfFormat": "A4",
  "pdfLandscape": false,
  "pdfPrintBackground": true,
  "maxConcurrency": 3,
  "maxRetries": 3
}
```

# Actor output Schema

## `results` (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": [
        {
            "url": "https://example.com"
        },
        {
            "url": "https://en.wikipedia.org/wiki/Web_scraping"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pennydata/shot-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": [
        { "url": "https://example.com" },
        { "url": "https://en.wikipedia.org/wiki/Web_scraping" },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("pennydata/shot-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": [
    {
      "url": "https://example.com"
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping"
    }
  ]
}' |
apify call pennydata/shot-pdf --silent --output-dataset

```

## MCP server setup

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