# Page to PDF & Screenshot: URL or HTML to PDF, PNG (`starlitdesk/page-to-pdf-screenshot`) Actor

Turn a list of web pages or your own HTML into PDF files and full-page PNG screenshots in one run. A4 or Letter, wait and timeout controls, hide cookie banners by CSS selector. $0.003 per file created; failed pages are not charged.

- **URL**: https://apify.com/starlitdesk/page-to-pdf-screenshot.md
- **Developed by:** [Nils Landegren](https://apify.com/starlitdesk) (community)
- **Categories:** 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 file createds

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

## Page to PDF & Screenshot

Turn a list of web pages, or your own HTML, into PDF files and PNG screenshots in one run. You get one result row per input, with links to the files and a clear error message for any page that could not be captured.

Built and maintained by AI agents at Nightshift Labs, checked by tests.

### Try it: copy-paste input

A list of URLs, as PDF and PNG:

```json
{"urls": [{"url": "https://example.com"}], "outputs": ["pdf", "png"]}
```

Your own HTML, as a Letter-size PDF:

```json
{"html": [{"name": "invoice", "html": "<h1>Invoice 42</h1>"}], "outputs": ["pdf"], "pageFormat": "Letter"}
```

### What does Page to PDF & Screenshot do?

- Opens each URL in a real Chromium browser and saves it as a **PDF**, a **PNG screenshot**, or both.
- Renders **raw HTML you paste in** (for example an invoice or report template) without needing a URL. Raw HTML is rendered offline: every network request it would make is blocked, so inline your CSS and use `data:` URLs for images.
- Lets you choose when to capture: wait for `load`, `domcontentloaded` or `networkidle`, add an extra delay, and hide elements such as cookie banners with CSS selectors.
- Saves every file to the run's key-value store and puts its link in the dataset, so you can download files or pass the links on to another tool.
- Records an error row for any page that fails (any 4xx or 5xx status, a timeout or a load failure) and moves on to the next one.

It does **not** log in, accept cookies or session data, solve CAPTCHAs or get around bot checks, rotate proxies, or extract text or data from pages.

### How to use it

1. Add your page URLs under **URLs** (up to 1,000), or add HTML under **HTML** with a name for each item (up to 100). If you only use HTML, leave **URLs** empty.
2. Pick the outputs: PDF, PNG or both (default both).
3. Optional: set the page format, margins, viewport size, wait condition, delay and timeout.
4. Start the run.
5. Open the dataset: each row has `pdfUrl` and `pngUrl` links, or an `error` if the page failed.

### Input

| Field | What it does | Default |
|---|---|---|
| `urls` | Pages to capture, up to 1,000; may be empty when `html` is given | none (prefilled with https://example.com) |
| `html` | Optional list of `{name, html}` items, up to 100, rendered offline (inline CSS, `data:` URLs for images) | none |
| `outputs` | `pdf`, `png` or both | both |
| `pageFormat` | PDF page size: `A4` or `Letter` | `A4` |
| `landscape` | PDF in landscape orientation | `false` |
| `printBackground` | Include background colours and images in the PDF | `true` |
| `marginMm` | PDF margin in millimetres | `10` |
| `viewportWidth` / `viewportHeight` | Browser window size for the PNG, in pixels | `1280` / `800` |
| `fullPage` | Capture the whole page height in the PNG (cut at 16,000 px) | `true` |
| `waitUntil` | When the page counts as ready: `load`, `domcontentloaded` or `networkidle` | `load` |
| `delayMs` | Extra wait before capture, 0–10,000 ms | `0` |
| `timeoutSecs` | Time allowed per page, up to 60 seconds | `30` |
| `hideSelectors` | CSS selectors to hide before capture, e.g. cookie banners | none |

### Output

One dataset row per input:

```json
{
  "input": "https://example.com",
  "finalUrl": "https://example.com/",
  "httpStatus": 200,
  "title": "Example Domain",
  "pdfUrl": "https://api.apify.com/v2/key-value-stores/<store-id>/records/<file-key>.pdf",
  "pngUrl": "https://api.apify.com/v2/key-value-stores/<store-id>/records/<file-key>.png",
  "pdfBytes": 0,
  "pngBytes": 0,
  "ms": 0,
  "filesCharged": 2,
  "error": null,
  "note": null
}
```

`filesCharged` is the number of files you were charged for on that row. `note` gives extra information, for example `PNG cut at 16,000 px height`. A failed row has `error` set (for example a timeout or an HTTP 403) and no file links. Numbers above are placeholders; the sample output on this page shows a real run.

### How much will it cost?

This Actor uses pay-per-event pricing:

| Event | Price |
|---|---|
| Each PDF or PNG file created | $0.003 (= $3 per 1,000 files) |
| Run start (Apify default) | $0.00005 per GB of run memory, at least 1 GB; at the default 2 GB = $0.0001 per run |

**Failed pages are not charged**: a file is charged only after it is saved.

| Example run | Files | Cost of files |
|---|---|---|
| 100 pages as PDF + PNG | 200 | $0.60 |
| 1,000 pages as PDF only | 1,000 | $3.00 |
| A page that fails | 0 | $0.00 |

Add the run start to each run (at the default 2 GB memory: $0.0001, so the first example is $0.6001 in total). You can set a maximum cost per run in Apify; when it is reached, the run stops starting new work and lists the items it could not charge for with a note instead of results.

### Limits

- Up to 1,000 URLs and 100 HTML items per run.
- Up to 60 seconds per page (default 30).
- Pages that answer 401, 403 or 429, or another 4xx/5xx status, are not captured; they show up as error rows.
- A bot-check or login page that answers with status 200 is not detected: it is captured as it appears and charged like any other page.
- Full-page PNGs are cut at 16,000 px height; the row's `note` says so.
- Very long or heavy pages can hit the timeout; raise `timeoutSecs` or turn off `fullPage`.

### FAQ

**Which pages can I capture?**
Only pages you own or have the right to copy; you are responsible for how you use the files. The Actor does not log in, take cookies or passwords, or get around bot checks or CAPTCHAs. A page that answers with an error status (such as 401 or 403) gives an error row. A login or block page that answers with status 200 is captured as it appears, so check your results.

**What happens when a page fails?**
You get a row with `error` set (for example a timeout or an HTTP 403) and no file links, and the run moves on to the next page. Nothing is charged for that page: only saved files are charged ($0.003 each), plus the run start.

**Can I run it from the API or on a schedule?**
Yes. Like any Actor, you can start it through the Apify API or client libraries, run it on an Apify schedule, or connect it to other tools with Apify integrations. These are Apify platform features; the input is the same JSON as above.

**Why is my screenshot missing content that loads late?**
Set `waitUntil` to `networkidle`, or add a `delayMs` of a few seconds, so slower content has time to appear.

**How do I remove cookie banners or pop-ups?**
Add their CSS selectors to `hideSelectors`. They are hidden before the PDF or PNG is made.

**Can I turn my own HTML into a PDF?**
Yes. Put it in the `html` field with a name (up to 100 items per run). You do not need to host it anywhere. It is rendered offline, so inline your CSS and use `data:` URLs for images.

### Use cases

- Archive your own web pages or published reports as PDFs.
- Turn HTML templates (invoices, certificates, reports) into PDFs.
- Take full-page screenshots of your sites for design reviews or change records.
- Add page snapshots to a workflow that already runs on Apify.

### Rights and disclosure

Capture only pages you own or have the right to copy; you are responsible for how you use the files.

Built and maintained by AI agents at Nightshift Labs, checked by tests.

# Actor input Schema

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

Web pages to capture (http or https), up to 1,000. Only these pages are opened; no links are followed. Leave empty if you only use raw HTML.

## `html` (type: `array`):

Your own HTML to render, as a list of {"name": "invoice-1", "html": "<h1>...</h1>"}. Rendered offline: the tool blocks every network request it would make, so inline CSS and use data: URLs for images. Up to 100 items.

## `outputs` (type: `array`):

PDF, PNG or both for every page. Each file created is one paid event.

## `pageFormat` (type: `string`):

Paper size of the PDF.

## `landscape` (type: `boolean`):

Print the PDF in landscape orientation.

## `printBackground` (type: `boolean`):

Include background colours and images in the PDF.

## `marginMm` (type: `integer`):

Margin on all four sides of each PDF page, 0 to 50 mm.

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

Width of the browser window, 320 to 3,840 px. Also the PNG width.

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

Height of the browser window, 200 to 2,160 px. Used as the PNG height when Full page is off.

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

Capture the whole page height (cut at 16,000 px) instead of only the visible window.

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

When a page counts as loaded: 'load' (all resources), 'domcontentloaded' (HTML parsed) or 'networkidle' (no network traffic for 0.5 s).

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

Wait this long after loading before capturing, 0 to 10,000 ms (for animations or late content).

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

Give up on a page after this many seconds, 1 to 60. Pages that time out are not charged.

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

Elements to hide before capturing, e.g. a cookie banner on your own site: '#cookie-banner'. Up to 50.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://example.com"
    }
  ],
  "outputs": [
    "pdf",
    "png"
  ],
  "pageFormat": "A4",
  "landscape": false,
  "printBackground": true,
  "marginMm": 10,
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "fullPage": true,
  "waitUntil": "load",
  "delayMs": 0,
  "timeoutSecs": 30
}
```

# Actor output Schema

## `overview` (type: `string`):

One row per input with status, file links and errors.

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

All files saved by this run in the default 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": [
        {
            "url": "https://example.com"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("starlitdesk/page-to-pdf-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": [{ "url": "https://example.com" }] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,starlitdesk/page-to-pdf-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/IaFVETFujjfgSPpFc/builds/7zPtHuOL3grALWFig/openapi.json
