# Website Screenshot & PDF: Full Page, Most Cookie Banners Hidden (`far003/website-screenshot-pdf`) Actor

Screenshots (PNG, JPEG, WebP) and PDFs of web pages or HTML. Full page with lazy images, mobile presets, common cookie banners hidden. You pay only for files produced.

- **URL**: https://apify.com/far003/website-screenshot-pdf.md
- **Developed by:** [Francesco Antonio Russo](https://apify.com/far003) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 screenshot or pdf files

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 & PDF – Full Page, Mobile, Common Cookie Pop-ups Hidden

Give it web addresses (or a piece of HTML) and get back a **PNG, JPEG, WebP or PDF file for each one**: the whole page with its lazy-loaded images, as a desktop, phone or tablet, with the common cookie banners and consent walls hidden. **You pay only for a file that was produced and is not empty**: a 404, a blocked page, a timeout or a bad address costs nothing.

For people who need page images or PDFs at scale: archiving and compliance snapshots, link previews, visual checks of a website on many screens, invoices and reports turned from HTML into PDF, thumbnails for a catalogue.

### Price

One event: **Screenshot or PDF file**, **$2 per 1,000 files** ($0.002 per file). The event is charged only when a file was produced, is not empty and is stored in the key-value store of the run.

| What you run | Files produced | Cost |
|---|---|---|
| The prefill (2 pages) | 2 | $0.004 |
| 100 pages | 100 | $0.20 |
| 1,000 pages, 20 of them are 404 | 980 | $1.96 |
| 5,000 pages | 5,000 | $10.00 |
| 10,000 pages | 10,000 | $20.00 |

**Free, never charged:** an address that is not a valid web address (`invalid_url`), an address that is not http or https (for example `ftp://`) or that points inside a private network (`blocked_unsafe_url`), a host that does not exist or refuses the connection (`unreachable`), a page that answers an error such as 404 or 500 (`http_error`), a login wall, rate limit or bot challenge (`blocked`), a page that does not load in time (`timeout`), a capture that could not produce a file (`empty_capture`), and a page that came out as one flat colour with nothing on it (`blank`). Each of them still gets a record that says why. The spending limit you set on the run is respected exactly: the run stops before a file that would go over it. Apify's own platform fees, if any, are on the Pricing tab of this Actor.

### What you can set

| Input | What it does |
|---|---|
| `urls` | The addresses to capture (a list of addresses, or of `{"url": "..."}` objects). Only http and https. |
| `html` | A complete HTML page to render instead of, or besides, the addresses (an invoice, a report). Relative addresses inside it cannot be resolved: use inline styles and `data:` or absolute https images. |
| `format` | `png` (default), `jpeg`, `webp` or `pdf`. |
| `fullPage` | Capture the whole page (default on) or only the first screen. |
| `maxFullPageHeight` | Tallest capture in CSS pixels, up to 16,384 (WebP: 16,383). A taller page is cut there and marked `truncated`. |
| `quality` | JPEG and WebP quality, 1 to 100 (default 80). |
| `device` | `desktop` 1440x900 (default), `desktop_hd` 1920x1080, `laptop` 1280x800, `iphone_15`, `iphone_se`, `pixel_8`, `ipad`. Phones and the tablet also get a mobile browser identity and touch. |
| `width`, `height` | Your own screen size; they replace the preset (the record then says `custom`). |
| `deviceScaleFactor` | Pixel density 1 to 3 (2 = retina: twice as wide and tall). Default 1. |
| `colorScheme` | `light` (default) or `dark`, for sites that follow the system setting. |
| `selector` | Capture only one element, for example `#pricing-table`. |
| `waitUntil` | `load` (default), `domcontentloaded` or `networkidle` (waits for a quiet network for at most 15 more seconds, and captures anyway if the page never gets quiet). |
| `waitForSelector` | Wait (up to 20 seconds) for an element to exist before capturing. |
| `delayMs` | Extra wait in milliseconds, 0 to 10,000. |
| `scrollToBottom` | Before a full page, a PDF or an element, scroll the page step by step so lazy-loaded images load (default on; at most 12 seconds and never beyond the height cap). |
| `cookieBanners` | `hide` (default) or `off`. Never "accept": this Actor gives no consent on your behalf. |
| `hideSelectors` | Your own list of CSS selectors to hide (chat widgets, sticky bars). |
| `customCss` | CSS added to the page before the capture. |
| `blockAds` | Do not load a short fixed list of advertising networks (about 25 domains). Default off. |
| `pdfFormat`, `pdfLandscape`, `pdfMargins`, `pdfPrintBackground`, `pdfMedia` | PDF paper size (A3, A4, A5, Letter, Legal, Tabloid), orientation, margins (default 10 mm), backgrounds (default on), and whether the print styles (default) or the screen styles are used. |
| `cookies`, `headers`, `basicAuth` | Your own session cookies, HTTP headers and basic-auth login for pages you may capture. Stored as secrets, never written to the log or the output. Cookies need a `domain` or `url` and are sent only there; headers and basic auth are sent only to the address of the page itself, never to the third-party files it loads. |
| `timeoutSecs` | Time given to one address, 2 to 120 (default 45). A timeout, a reset connection or a 5xx answer is tried once more. |
| `maxConcurrency` | Pages in parallel, 1 to 6 (default 3). |

Options that do not apply to the chosen format (for example `selector` with `pdf`) are listed as warnings in the log and in the SUMMARY.

Example input (this is the prefill):

```json
{
  "urls": [
    { "url": "https://www.python.org/" },
    { "url": "https://en.wikipedia.org/wiki/Web_scraping" }
  ]
}
```

### What you get

One record per address (and one for the `html` input) in the dataset, and one file per record in the key-value store of the run. Records are written as captures finish: `index` is the position of the entry in your input.

| Field | Meaning |
|---|---|
| `index` | Position of the entry in your input, counting from 0 (an address repeated later in the list has no record of its own, so the numbers can skip; the HTML page, if any, comes after all the addresses). |
| `inputType` | `url` or `html`. |
| `url` | The address you gave (null for HTML). |
| `finalUrl` | Where the page ended after redirects. |
| `status` | `ok` or the free reason (see below). |
| `httpStatus` | HTTP status of the page itself. |
| `title` | Title of the page. |
| `format` | `png`, `jpeg`, `webp` or `pdf` (null when there is no file). |
| `fileUrl` | Public link to the file (works without a token; it lives as long as the storage of the run). |
| `fileKey` | Key of the file in the key-value store. |
| `bytes` | Size of the file. |
| `width`, `height` | Size of the image in pixels as produced (CSS pixels times `deviceScaleFactor`); null for PDF. |
| `fullHeightPx` | Height of the whole page in CSS pixels. |
| `truncated` | True when the page was taller than the cap and the image was cut. |
| `pages` | Number of pages of a PDF. |
| `device` | The preset used, or `custom`. |
| `durationMs` | Time spent on this entry. |
| `error` | Why there is no file. |
| `capturedAt` | When the record was written. |

A real record (from a run on 2026-10-15; the link of your run has your store id and a signature):

```json
{
  "index": 0,
  "inputType": "url",
  "url": "https://www.python.org/",
  "finalUrl": "https://www.python.org/",
  "status": "ok",
  "httpStatus": 200,
  "title": "Welcome to Python.org",
  "format": "png",
  "fileUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/shot-0001-www-python-org.png?signature=<signature>",
  "fileKey": "shot-0001-www-python-org.png",
  "bytes": 488595,
  "width": 1440,
  "height": 2549,
  "fullHeightPx": 2549,
  "truncated": false,
  "pages": null,
  "device": "desktop",
  "durationMs": 4209,
  "error": null,
  "capturedAt": "2026-10-15T09:10:08.749Z"
}
```

A free record, from the same kind of run:

```json
{
  "index": 5,
  "inputType": "url",
  "url": "https://httpbin.org/status/404",
  "finalUrl": "https://httpbin.org/status/404",
  "status": "http_error",
  "httpStatus": 404,
  "title": null,
  "format": null,
  "fileUrl": null,
  "fileKey": null,
  "bytes": 0,
  "width": null,
  "height": null,
  "fullHeightPx": null,
  "truncated": false,
  "pages": null,
  "device": "desktop",
  "durationMs": 642,
  "error": "the page answered HTTP 404",
  "capturedAt": "2026-10-14T15:32:07.789Z"
}
```

| `status` | Meaning | Charged |
|---|---|---|
| `ok` | A file was produced and stored. | yes |
| `invalid_url` | Not a web address (or credentials inside the address: use `basicAuth`). | no |
| `unreachable` | The name does not resolve, or the host refused or dropped the connection. | no |
| `http_error` | The page answered 4xx or 5xx other than 401, 403 and 429. No file is saved, not even of the error page. | no |
| `blocked` | 401, 403, 429, or a bot challenge page ("Just a moment", "Attention Required", or a CDN challenge that answers 202 with an empty page, or a short block page that answers 200 with a known sentence such as "You've been blocked by network security" or "Access denied"). A page with a lot of text is never taken for a block page because it contains those words. No attempt is made to get around it. | no |
| `timeout` | Not captured within `timeoutSecs` (after one more attempt), or `waitForSelector` never showed up. | no |
| `blocked_unsafe_url` | Not http or https, or an address inside a private network, loopback, link-local or cloud-metadata range, also after redirects. | no |
| `empty_capture` | The browser could not produce a file: the `selector` matches nothing, the address is a file download, the tab crashed, or the image came out empty. | no |
| `blank` | The picture of the page is one flat colour (99.9% of the pixels) and the page has no text and no pictures of its own, typically a challenge page or a page that never rendered. Only whole-page images are judged (not PDF, not a `selector` capture); a page with any text, logo or picture is never blank. If it is a page that needs more time, raise `delayMs`. | no |

A run also writes a `SUMMARY` record: files produced, files charged, free records by reason, why the run stopped (`done`, `budget exhausted`, `time limit`, `aborted`), warnings and a few counters. If every address of a run is invalid, the run still ends normally with one free record per address.

### How it works, and what it will not do

It opens each page in Chromium (Playwright), waits for it, scrolls through it so lazy images load, hides what you asked to hide and takes the picture or prints the PDF. It identifies itself honestly: the user agent of Chromium plus `(compatible; WebsiteScreenshotPDF/0.1)`, the name of this Actor (https://apify.com/far003/website-screenshot-pdf). The link is not in the user agent because some publishers refuse any agent that names a scraping platform.

It does **not**: solve CAPTCHAs, mask itself as a normal browser, rotate proxies, fake a location, click "Accept" on consent banners, or sign in for you. A page behind a login is captured only with the cookies, headers or login that you provide. Some sites refuse automated visitors that say who they are; you then get a free `blocked` record (in a test on 2026-10-14 a large news site and a photo site both answered 403).

**Safety.** Every connection of the browser goes through a filter that resolves the name itself and connects only to a checked public address. Private networks (10.x, 172.16-31.x, 192.168.x), loopback, link-local and cloud metadata addresses are refused for the page you ask for, for its redirects and for everything the page loads, so an address you give, or a page you capture, cannot be used to reach into the machine that runs the Actor. Mail, shell and database ports are refused too.

### Memory and speed

Default memory is 2,048 MB (minimum 1,024, maximum 4,096). Peaks measured on a laptop (macOS, resident memory of Node plus Chromium; Linux numbers can differ):

| Run | Peak |
|---|---|
| The prefill, 2 pages, 3 in parallel | about 1.1 GB |
| 3 very tall pages (cut at 16,384 px), density 1, run memory 2,048 MB | about 1.8 GB |
| One 1440 x 16,384 page at `deviceScaleFactor` 2 (image 2880 x 32,768) | about 2.3 GB |
| 3 of those, run memory 4,096 MB | about 3.3 GB |

Pages load in parallel, but turning a tall page into an image waits its turn when the memory of the run would not hold both: this is why a run with little memory is slower, not killed. A single capture that is bigger than the memory of the run (retina on a very tall page with 2,048 MB) runs alone and may still run out of memory: use 4,096 MB for that, or lower `deviceScaleFactor` or `maxFullPageHeight`. A typical page takes 2 to 12 seconds; a very tall page about 10 seconds.

### Limits, honestly

- **Height.** Chromium cuts or empties images taller than 16,384 pixels (WebP: 16,383 pixels **of the file**: with `deviceScaleFactor` 2 a WebP is cut at 8,191 CSS pixels, with 3 at 5,461). Such a page is captured up to the cap and the record says `truncated: true` and gives the real height in `fullHeightPx`. Use a PDF to get a very long page whole.
- **Single-page apps.** With the default `waitUntil: load` an app that draws its content after the page has loaded can be captured as its loading skeleton, and it is charged as a file. If the pictures show placeholders, use `waitUntil: networkidle` (or `waitForSelector` on an element that only exists once the content is there).
- **PDF of a long page.** The PDF is what the browser prints. A page that scrolls inside its own container (a fixed-height app or an article frame) or whose print style hides the content can come out as one page; the record gives the number of pages in `pages`: check it, or try `pdfMedia: screen`.
- **Lazy loading** is woken by scrolling, with a time cap. A page that grows forever (endless scroll) is captured up to the cap; content that needs a click, a login or a long animation may not be there. Sections sized to the screen height (`100vh`) can look stretched in a full-page image.
- **Cookie banners** are hidden by a list of the common consent platforms (OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast, Sourcepoint and others); it was checked on real pages for OneTrust and Cookiebot, and the consent walls that cover the whole page and lock its scroll of Le Monde, Le Figaro, Marca, Corriere della Sera and El País are hidden too (the page is freed, so a full page is captured). The list is not complete. A banner that is not recognised stays; send its selector in `hideSelectors`. The list never hides a page wrapper, the body or anything that contains the main content.
- **A login redirect is a page.** A page that sends you to a login page is captured as that login page (`status: ok`, and `finalUrl` shows it): check `finalUrl` if that matters to you. It is charged like any file.
- **HTML input** cannot load relative files. The sandbox page has no real address.
- **DNS.** The address check and the connection use the same checked address, so a name that changes its answer in the middle cannot slip a private address in.
- **No guarantee from the sites.** Pages change, block or go down; a file reflects the page at the moment of the capture.

### FAQ

**Do I pay for pages that fail?** No. Only a produced, non-empty, stored file is charged. You can see every free record and its reason in the dataset.

**Why did I get `blocked`?** The site answered 401, 403 or 429, or showed a bot challenge or a short block page (also when its code is 200). This Actor does not try to get past that. If you are allowed to see the page, pass your own `cookies`, `headers` or `basicAuth`.

**Can it capture pages behind a login?** Yes, with your own session cookie (or header, or basic auth). They are secret inputs and are never logged or put in the output.

**Does it accept cookie banners?** No. It hides the common ones, because accepting is a consent that only you can give. Use `cookieBanners: "off"` to see the page as a first-time visitor does.

**How do I get a mobile screenshot?** Set `device` to `iphone_15`, `iphone_se`, `pixel_8` or `ipad`, and `deviceScaleFactor` to 2 for a sharp image.

**How do I turn an invoice into a PDF?** Put the HTML in `html`, set `format` to `pdf`, and choose `pdfFormat` and `pdfMargins`. Styles inline or in a `<style>` tag; images as `data:` addresses.

**The page is taller than 16,384 pixels.** The image is cut at the cap and marked `truncated`. For the whole page use `pdf`, or capture sections with `selector`.

**How long are the files kept?** In the key-value store of the run, for as long as your Apify plan keeps the storage of runs. Download or copy what you need to keep.

### Call it from code

Replace `<APIFY_TOKEN>` with your token.

```bash
curl -X POST "https://api.apify.com/v2/acts/far003~website-screenshot-pdf/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"urls": [{"url": "https://example.com"}], "format": "webp", "device": "iphone_15"}'
```

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

const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('far003/website-screenshot-pdf').call({
    urls: [{ url: 'https://example.com' }],
    format: 'png',
    fullPage: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) console.log(item.status, item.fileUrl);
```

### Your responsibility

You are responsible for having the right to capture the pages you give, and for what you do with the files: copyright, terms of the sites and privacy law (such as the GDPR) apply to a screenshot as to any copy. This Actor does not look for personal data and stores nothing but the file you asked for and the record that describes it.

# Actor input Schema

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

The web pages to capture, one file per address. Only http and https addresses are captured. An address that is not valid, or is not http/https, gives a free record with the reason; a page that answers an error (404, 500...), refuses (401, 403, 429), asks for a challenge, does not load in time, or points to a private network address gives a free record too. Use either this list, or the HTML field below, or both. Lists of addresses in a remote file ("requestsFromUrl") are not supported.

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

A complete HTML page to render instead of (or besides) the addresses, for example an invoice or a report to turn into a PDF. Styles must be inline or in a <style> tag, and images must be data: addresses or absolute https addresses: relative addresses cannot be resolved. Up to 5 MB. The record has inputType "html" and no url.

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

png (lossless, default), jpeg and webp (smaller, use Quality) or pdf. One file per address, stored in the key-value store of the run.

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

Capture the whole page, not only the first screen. Ignored for PDF (a PDF always contains the whole page) and when a selector is given. Pages taller than the maximum height are cut there and marked truncated: true.

## `maxFullPageHeight` (type: `integer`):

Tallest capture in CSS pixels, from 100 to 16384 (the limit of Chromium). A page taller than this is cut at this height and the record says truncated: true and gives fullHeightPx. WebP cannot be taller than 16383 pixels, so 16383 is its cap.

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

From 1 to 100. No effect on PNG and PDF.

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

The screen to emulate. Desktop is 1440 x 900. The phone and tablet presets also send a mobile browser identity and touch. Width and Height below override the size of the preset.

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

Overrides the width of the device preset, from 200 to 3840. The record then says device: "custom".

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

Overrides the height of the device preset, from 100 to 4320. It is the height of the first screen; with Full page the capture goes beyond it.

## `deviceScaleFactor` (type: `number`):

1 to 3. 2 gives a sharp retina image twice as wide and tall (4 times the pixels, so more memory and bigger files). Default 1.

## `colorScheme` (type: `string`):

Light or dark, for sites that follow the system setting (prefers-color-scheme).

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

For example #pricing-table or .hero. Only that element is captured (the first one that matches). If nothing matches, the record is empty_capture and free. Ignored for PDF.

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

When the page counts as loaded. load (default) waits for the load event; domcontentloaded is faster; networkidle also waits for the network to be quiet, at most 15 seconds more (a page that never gets quiet is still captured).

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

Wait until this element is in the page (up to 20 seconds) before capturing. If it does not show up the record is timeout and free.

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

Wait this long after the page has loaded and scrolled, for animations or late content. 0 to 10000.

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

Before a full page, PDF or element capture, scroll down the page step by step so that lazy-loaded images and sections load, then go back to the top. Capped at 12 seconds and at the maximum height, so an endless page cannot hang the run.

## `cookieBanners` (type: `string`):

hide (default) hides the banners of the common consent platforms (OneTrust, Cookiebot, Didomi, Usercentrics, Sourcepoint, Quantcast and similar) and frees a page they froze. It never clicks Accept: this Actor gives no consent on your behalf. Best effort: a banner that is not recognised stays. off leaves the page as it is.

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

Elements to hide before the capture, for example chat widgets or sticky bars. Up to 50 selectors.

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

CSS added to the page before the capture, up to 20,000 characters.

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

Do not load requests to a short, fixed list of advertising networks (about 25 domains, such as doubleclick.net and googlesyndication.com). It is not a general tracker blocker.

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

Paper size when the format is pdf.

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

Print the PDF in landscape orientation.

## `pdfMargins` (type: `object`):

For example {"top": "10mm", "right": "10mm", "bottom": "10mm", "left": "10mm"} (the default). Units: mm, cm, in or px.

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

Print the backgrounds of the page (on by default; browsers drop them from printouts otherwise).

## `pdfMedia` (type: `string`):

print (default) uses the print styles of the page, as a browser Save as PDF does, and respects @page rules (good for invoices and articles). screen keeps the look of the screen.

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

Cookies to send, for pages behind a login. A list of objects with name, value and a domain (or url), for example \[{"name": "session", "value": "...", "domain": "example.com"}]. A cookie without domain or url is refused: it would be sent to every address of the run. Never written to the log or to the output.

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

For example {"Authorization": "Bearer ..."}. Sent only to the address of each page itself, never to the third-party resources it loads. Host, Cookie, User-Agent and similar headers are ignored. Never written to the log or to the output.

## `basicAuth` (type: `object`):

For example {"username": "user", "password": "..."}. Sent only to the origin of each page. Never written to the log or to the output.

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

A page that has not been captured in this time is given up (record timeout, free) so that the run never hangs. A timeout, a reset connection or a 5xx answer is tried once more. From 2 to 120.

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

From 1 to 6. With the default memory (2048 MB) 3 is comfortable; heavy captures (retina, very tall pages) need fewer or more memory.

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://www.python.org/"
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping"
    }
  ],
  "format": "png",
  "fullPage": true,
  "maxFullPageHeight": 16384,
  "quality": 80,
  "device": "desktop",
  "deviceScaleFactor": 1,
  "colorScheme": "light",
  "waitUntil": "load",
  "delayMs": 0,
  "scrollToBottom": true,
  "cookieBanners": "hide",
  "blockAds": false,
  "pdfFormat": "A4",
  "pdfLandscape": false,
  "pdfMargins": {
    "top": "10mm",
    "right": "10mm",
    "bottom": "10mm",
    "left": "10mm"
  },
  "pdfPrintBackground": true,
  "pdfMedia": "print",
  "timeoutSecs": 45,
  "maxConcurrency": 3
}
```

# Actor output Schema

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

No description

## `problems` (type: `string`):

No description

## `allFiles` (type: `string`):

No description

## `summary` (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://www.python.org/"
        },
        {
            "url": "https://en.wikipedia.org/wiki/Web_scraping"
        }
    ]
};

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

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

```

## MCP server setup

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