# snaplab Screenshot & PDF Renderer (`ohsiingh/snaplab-screenshot-pdf-renderer`) Actor

Render any URL or raw HTML to a PNG/JPEG/WebP screenshot or a PDF, with ad blocking, cookie-banner removal, dark mode and full-page capture.

- **URL**: https://apify.com/ohsiingh/snaplab-screenshot-pdf-renderer.md
- **Developed by:** [Harpreet Singh](https://apify.com/ohsiingh) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## snaplab Screenshot & PDF Renderer

Point this actor at a list of URLs (or a blob of raw HTML) and get back clean PNG, JPEG, WebP or PDF files — no ad clutter, no cookie banners, no half-loaded pages. It runs a real headless chromium on the Apify platform, so what you get is what a browser sees, at whatever viewport, colour scheme and page length you ask for. Every render lands in the run's key-value store with a direct link in the dataset row next to it.

### What it does

- Renders **any URL or raw HTML** to **PNG, JPEG, WebP** or **PDF**.
- **Full-page capture** — the whole scrollable document, not just the fold.
- **Ad & tracker blocking** — requests to known ad, analytics and session-replay hosts are aborted before they load.
- **Cookie-banner removal** — common consent dialogs are hidden, and an obvious accept button is clicked when one is present.
- **Dark mode** — emulates `prefers-color-scheme: dark`.
- **Custom viewport** — width and height from 320×240 up to 4096×4096.
- **Render delay** — wait up to 10 seconds after load for animations and lazy-loaded content.
- **Files land in the key-value store**, with a direct link (`keyValueStoreUrl`) in each dataset row.

### Input

```json
{
  "urls": [{ "url": "https://news.ycombinator.com" }, { "url": "https://example.com" }],
  "mode": "screenshot",
  "format": "png",
  "fullPage": true,
  "width": 1280,
  "height": 800,
  "darkMode": false,
  "blockAds": true,
  "blockCookieBanners": true,
  "delay": 500
}
```

Leave `urls` empty and pass `html` instead to render a string of markup. Pass both and you get one render per URL plus one for the HTML.

### Output

One dataset row per target:

```json
{
  "url": "https://news.ycombinator.com",
  "kind": "screenshot",
  "keyValueStoreUrl": "https://api.apify.com/v2/key-value-stores/aBcDeFgHiJkLmNoPq/records/render-0-1757210000000.png",
  "width": 1280,
  "height": 800,
  "bytes": 412870,
  "tookMs": 2841
}
```

The binary file itself is **not** in the dataset — it lives in the run's key-value store at the `keyValueStoreUrl` shown in the row. Fetch that URL to download the image or PDF.

A target that fails produces a row with an `error` field instead of a file, and the run carries on with the next target.

### Pricing

This actor is **pay per event**:

| Event | Price | When |
| --- | --- | --- |
| Actor start | **$0.005** | Once, when the run starts |
| Successful render | **$0.003** | Per URL or HTML input rendered successfully |

So a run that screenshots 100 URLs costs about **$0.305** — $0.005 to start plus 100 × $0.003.

**Failed renders are not charged.** If a page times out or errors, you get a dataset row with the error message and no charge for it.

> Implementation note for maintainers: the event definitions live in two places that must be kept in sync — `.actor/pay_per_event.json` as a standalone file, and a `payPerEvent.actorChargeEvents` block inside `.actor/actor.json`. Apify has used both conventions; carrying both means the platform finds the pricing whichever key it reads. Change one, change the other.

### Also available as a hosted REST API

If you'd rather call an endpoint than run an actor, the same renderer is available as a REST API at [snaplab.dev](https://snaplab.dev):

```bash
curl -X POST https://snaplab.dev/api/render \
  -H "Authorization: Bearer sk_..." -H "Content-Type: application/json" \
  -d '{"url":"https://example.com","format":"png","fullPage":true}' -o shot.png
```

100 free renders a month, plus PDF, HTML→image, signed URLs for `<img>` tags, an n8n community node, and an **MCP server** at `https://snaplab.dev/mcp` so Claude and Cursor can see any page. Docs: [snaplab.dev/docs](https://snaplab.dev/docs).

### FAQ

**Can I render pages behind a login?**
Not in v1. There is no cookie, header or credential input yet, so every page is fetched as an anonymous visitor. Public pages, paywall-free articles and your own marketing pages all work fine.

**Why is my full-page screenshot cut off?**
Very long pages hit chromium's own capture limits, and many sites only load images as you scroll. Set `delay` to 1000–3000 ms so lazy-loaded content has time to appear before the capture. If the page is genuinely enormous, capture it as a PDF instead.

**Does PDF mode respect `width` and `height`?**
No. In PDF mode the page size comes from `pdfFormat` (A4, Letter, Legal, A3, A5) and `landscape`. The `width`/`height` inputs only shape the browser viewport used for screenshots.

**What happens if one URL fails?**
You get a dataset row containing that URL and an `error` message, the run continues to the next target, and you are **not** charged the render event for it.

**Can I get JPEG at a specific quality?**
Not in v1 — JPEG quality is fixed at 80, which is a good size/fidelity trade-off for page captures. Use `png` or `webp` if you need lossless or smaller lossless-ish output.

**How do I get the file?**
Every dataset row carries a `keyValueStoreUrl`. That URL points at the record in the run's key-value store; fetch it to download the PNG, JPEG, WebP or PDF.

**Does this actor call the snaplab API?**
No. It is self-contained: it launches its own Playwright chromium on the Apify platform, so an Apify run needs no snaplab account or key. The hosted API above is the same capability behind a REST endpoint, for when you want to call it from your own code.

### Changelog

#### 0.1

- Initial release: URL and raw-HTML rendering, screenshot (PNG/JPEG/WebP) and PDF modes, full-page capture, ad and tracker blocking, cookie-banner removal, dark mode, custom viewport, render delay, pay-per-event pricing.

# Actor input Schema

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

One or more URLs to render. Leave empty to render the `html` field instead.

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

Render this HTML instead of (or in addition to) the URLs above.

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

Render each target to an image (screenshot) or to a PDF document.

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

Capture the entire scrollable page instead of just the viewport (screenshot mode only).

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

Browser viewport width in CSS pixels.

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

Browser viewport height in CSS pixels. Ignored for the captured height when `fullPage` is on.

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

Screenshot image format (ignored in PDF mode).

## `darkMode` (type: `boolean`):

Emulate prefers-color-scheme: dark.

## `blockAds` (type: `boolean`):

Abort requests to known ad, analytics and session-replay hosts.

## `blockCookieBanners` (type: `boolean`):

Hide common consent dialogs and click an obvious accept button when one is present.

## `delay` (type: `integer`):

Extra wait after load before capturing, for animations and lazy-loaded content.

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

Paper size (PDF mode only).

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

Landscape orientation (PDF mode only).

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://news.ycombinator.com"
    }
  ],
  "mode": "screenshot",
  "fullPage": false,
  "width": 1280,
  "height": 800,
  "format": "png",
  "darkMode": false,
  "blockAds": true,
  "blockCookieBanners": true,
  "delay": 0,
  "pdfFormat": "A4",
  "landscape": false
}
```

# Actor output Schema

## `renders` (type: `string`):

Dataset items: url, kind (screenshot|pdf), keyValueStoreUrl (direct link to the PNG/JPEG/WebP/PDF), width, height, bytes, tookMs.

## `rendersConsole` (type: `string`):

No description

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

The image/PDF binaries, one record per render (render-<index>-<timestamp>.<ext>).

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

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

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

```

## MCP server setup

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

```

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/lFh9LjYF2fQt4jfrQ/builds/Rg8a4qzGRANASTbiI/openapi.json
