# Website Screenshot & PDF Generator API (`power_on/screenshot-url-pdf`) Actor

Website screenshot API: full-page, viewport or element captures, and webpage-to-PDF export. Removes cookie banners, blocks ads, loads lazy images. Device presets, retina scale, dark mode. Pay per use, no subscription.

- **URL**: https://apify.com/power\_on/screenshot-url-pdf.md
- **Developed by:** [Power On Labs](https://apify.com/power_on) (community)
- **Categories:** Developer tools, Automation, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## 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

## Website Screenshot & PDF Generator API

A **website screenshot API** that captures any web page as a PNG, JPEG, WebP or PDF —
full page, visible viewport, or a single element. Built for the part every other
screenshot tool leaves broken: the cookie banner covering the hero image, the lazy
images that never loaded, the ad slot that left a grey hole in the middle of your
capture.

Give it a list of URLs. Get back clean images (or PDFs) and a dataset row per URL with
a direct file link — usable from the Apify API, the REST API, or the visual UI, with
no server of your own to run or maintain.

### What makes this website screenshot API different

Most "URL to image" tools stop at rendering the page and hoping for the best. This one
handles the reasons a plain screenshot looks broken:

| | |
|---|---|
| **Cookie banners removed** | Consent overlays from OneTrust, Cookiebot, Didomi, Quantcast, Usercentrics, Sourcepoint, Iubenda and 40+ others are stripped before the capture. The default **removes** the banner rather than clicking it, so no consent is given and no tracking cookies are set. Switch to "reject all" or "accept all" if you need a real click instead. |
| **Ads blocked and their empty slots collapsed** | Blocking ad requests alone leaves grey boxes labelled "Advertisement". Those get cleaned up too, so a full-page screenshot doesn't look broken. |
| **Lazy-loaded images actually load** | The page is scrolled before a full-page capture, so images below the fold render instead of coming back blank. |
| **Real device presets** | Desktop 1920, laptop 1366, iPad and iPhone viewports with matching user agent, touch support and pixel density — not just a resized browser window. |
| **Retina / high-DPI output** | 2x and 3x pixel density for crisp images in presentations, decks and documentation. |
| **Element screenshots** | Give a CSS selector and capture just that element — a pricing table, a chart, a single card — instead of the whole page. |
| **Webpage-to-PDF export** | Single-page PDF sized to the real page height, or standard A4, as an alternative output to an image. |
| **Batch capture in parallel** | Many URLs in one run, with automatic retries. One broken URL doesn't kill the run — you get a row explaining what went wrong and the rest complete normally. |

### Quick start

Minimal input — just a list of URLs:

```json
{ "urls": ["https://example.com"] }
```

Call it however fits your stack: the Apify API and REST endpoints, the official
Node.js and Python clients, or no-code via Zapier, Make or n8n through Apify's
integrations. A minimal call with the JavaScript client:

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('power_on/screenshot-url-pdf').call({
  urls: ['https://example.com'],
  device: 'desktop',
  format: 'png',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].fileUrl);
```

And with the Python client:

```python
from apify_client import ApifyClient

client = ApifyClient('<APIFY_TOKEN>')
run = client.actor('power_on/screenshot-url-pdf').call(
    run_input={'urls': ['https://example.com'], 'format': 'pdf'}
)
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items[0]['fileUrl'])
```

### Input parameters

Only `urls` is required. Everything else has a sensible default.

```json
{
  "urls": [
    "https://example.com",
    "https://news.ycombinator.com"
  ],
  "device": "desktop",
  "fullPage": true,
  "format": "png",
  "scaleFactor": 2,
  "dismissCookieBanners": "hide",
  "blockAds": true
}
```

Useful extras: `selector` (capture one element), `hideSelectors` (kill a sticky header
or a chat widget), `customCss`, `darkMode`, `waitForSelector`, `delayMs`, `locale`,
`timezone`, `cookies` and `basicAuth` for pages behind a login, and `proxyConfiguration`
for geo-specific pages. The full list, with descriptions and defaults, is in the
**Input** tab.

### Output

One dataset row per URL:

```json
{
  "url": "https://example.com",
  "ok": true,
  "statusCode": 200,
  "title": "Example Domain",
  "format": "png",
  "width": 1920,
  "height": 3480,
  "bytes": 214233,
  "device": "desktop",
  "scaleFactor": 2,
  "durationMs": 1842,
  "key": "001-example.com.png",
  "fileUrl": "https://api.apify.com/v2/key-value-stores/.../records/001-example.com.png"
}
```

The image or PDF is stored in the run's key-value store, and `fileUrl` is a direct
link to it — no separate download step. Failed URLs come back with `ok: false` and
the reason in `error`, instead of stopping the run.

### Typical use cases

- **Open Graph and social preview images** — generate the image your link preview
  uses when shared on Slack, X or LinkedIn
- **Visual monitoring** — capture the same pages on a schedule and compare them over
  time to catch layout regressions or unwanted changes
- **Webpage-to-PDF export** — archive a page as a PDF with the layout intact, for
  compliance, records or offline reading
- **Design and QA review** — desktop, tablet and mobile capture in one run, side by
  side
- **Documentation and changelogs** that need current, accurate screenshots without a
  human taking them by hand

### Pricing

Pay per screenshot. A failed URL is not charged. There's no monthly subscription and
no minimum commitment — you pay for what you actually capture, unlike most standalone
screenshot APIs that charge a fixed monthly plan whether you use it or not.

### FAQ

**Is there a free website screenshot API?**
This Actor has no free tier of its own, but every new Apify account starts with free
monthly platform credit, which covers a number of screenshots before any charge
applies.

**Can I take a full-page screenshot, not just the visible area?**
Yes — set `fullPage: true` (the default). The page is scrolled first so lazy-loaded
images below the fold render before the capture.

**Can I convert a webpage to PDF instead of an image?**
Yes — set `format: "pdf"`. You get a single-page PDF sized to the real page height,
or standard A4.

**Does it handle cookie consent banners automatically?**
Yes, by default. Overlays from the major consent management platforms are removed
before capture, without clicking "accept" — so no consent is granted and no tracking
cookie is set. You can switch to a real "accept all" or "reject all" click instead.

**Can I screenshot just one element instead of the whole page?**
Yes — pass a CSS `selector` and only that element is captured.

**Does this work with pages behind a login?**
Yes, via `cookies` or `basicAuth` in the input, depending on how the site
authenticates.

### Known limitations

Worth knowing before you run it:

- On a few sites an ad container also holds real content, and its reserved empty space
  survives the clean-up. Removing it would risk deleting real content, so it stays.
- Pages taller than roughly 16,000 pixels are clipped by the browser engine; the run
  falls back to a clipped capture instead of failing.
- Pages behind a bot wall may need `proxyConfiguration` and a longer `timeoutSecs`.
- Video and animation are captured as a still frame, at whatever moment the page is in.

### Related tools

Need the page's text or structured data instead of a picture of it? Apify's
[Website Content Crawler](https://apify.com/apify/website-content-crawler) extracts
clean text and markdown from a site — a common pairing with this Actor when you need
both a visual and the content.

### Support

Found a page it handles badly? Open an issue on this Actor with the URL and the
settings you used. Broken pages are the fastest way to make it better, and they get
fixed.

# Actor input Schema

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

Pages to capture. One screenshot (or PDF) is produced per URL.

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

Viewport, user agent and pixel density. Choose 'Custom' to set width and height yourself.

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

Viewport width in pixels. Used only when the device preset is "Custom".

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

Viewport height in pixels. Used only when the device preset is "Custom", and ignored for full-page captures.

## `scaleFactor` (type: `integer`):

Pixel density of the output: 1 for standard, 2 for retina, 3 for extra high resolution.

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

Capture the entire scrollable page instead of just the visible viewport.

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

Optional CSS selector. When set, only that element is captured.

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

Output type. PNG for lossless quality, JPEG or WebP for smaller files, PDF for a printable document.

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

Compression quality for JPEG and WebP, from 1 to 100. Ignored for PNG and PDF.

## `transparentBackground` (type: `boolean`):

Keeps the page background transparent instead of white. PNG only, and only works if the page itself has no background.

## `dismissCookieBanners` (type: `string`):

Cookie and consent overlays ruin screenshots. 'Hide' removes them from the page without clicking anything, which is the most reliable and does not accept any tracking.

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

Faster, more consistent screenshots and no empty ad slots.

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

CSS selectors to hide before capturing, e.g. sticky headers or chat widgets.

## `customCss` (type: `string`):

Injected before the capture.

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

Renders the page as if the visitor preferred a dark colour scheme.

## `locale` (type: `string`):

Browser language, e.g. en-US, it-IT, de-DE.

## `timezone` (type: `string`):

IANA name, e.g. Europe/Rome.

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

How long to wait for the page before capturing. "Network idle" is the most complete and the slowest.

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

Wait until this CSS selector appears before capturing.

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

Wait a little longer after loading, for animations or late content.

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

Scrolls through the page first so lazy-loaded images appear in a full-page capture.

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

How long to give a single URL before giving up on it.

## `concurrency` (type: `integer`):

How many URLs to capture at the same time.

## `retries` (type: `integer`):

How many times to retry a URL that failed before recording it as an error.

## `headers` (type: `object`):

Extra HTTP headers sent with every request, as a JSON object.

## `cookies` (type: `array`):

Playwright cookie objects, for pages behind a login.

## `basicAuthUsername` (type: `string`):

Username for HTTP Basic authentication, for staging sites behind a password.

## `basicAuthPassword` (type: `string`):

Password for HTTP Basic authentication.

## `proxyConfiguration` (type: `object`):

Use a proxy for geo-specific or blocked pages.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com"
  ],
  "device": "desktop",
  "width": 1920,
  "height": 1080,
  "scaleFactor": 1,
  "fullPage": true,
  "format": "png",
  "quality": 85,
  "transparentBackground": false,
  "dismissCookieBanners": "hide",
  "blockAds": true,
  "darkMode": false,
  "locale": "en-US",
  "waitUntil": "load",
  "delayMs": 0,
  "scrollToBottom": true,
  "timeoutSecs": 60,
  "concurrency": 4,
  "retries": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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("power_on/screenshot-url-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://apify.com"] }

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

```

## MCP server setup

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