# Website Screenshot API - Full Page Screenshot & URL to PDF (`tidytools/website-screenshot-pdf-markdown`) Actor

Bulk website screenshots: full page screenshot, one element, mobile or tablet, several widths. URL to PDF (website to PDF) and clean Markdown in one run. Hides ads and cookie banners. Failures free.

- **URL**: https://apify.com/tidytools/website-screenshot-pdf-markdown.md
- **Developed by:** [Yukai Lin](https://apify.com/tidytools) (community)
- **Categories:** Developer tools, Automation, AI
- **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.
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?

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

### What does Website Screenshot API do?

Give it a list of URLs and get back, for every page:

- 📸 **Screenshot**: viewport, full-page or **one element only** (e.g. a pricing table or chart), PNG / JPEG / WebP, desktop, laptop, tablet or mobile, retina (2x/3x) and dark mode
- 📄 **PDF**: print-ready A4 / Letter / Legal, portrait or landscape, with backgrounds
- 📝 **Markdown**: clean, LLM-ready text of the page, without navigation, headers and footers by default, optionally limited to one part of it (e.g. `article`)

All three come from a **single page load**, so asking for several formats costs no extra waiting.

It also handles the things that usually break screenshots: **lazy-loaded pages** (scroll to the bottom first), **pop-ups and chat widgets** (hide any CSS selector), **ads and trackers** (blocked on request), **slow widgets** (wait for an element), and **responsive checks** (several devices or widths per URL in one run).

| | This Actor |
|---|---|
| Mobile and tablet emulation (touch, mobile layout, 2x/3x) | ✅ |
| Several devices or widths per URL in one run | ✅ |
| Scroll first to load lazy images | ✅ |
| Hide elements by CSS selector, cookie banners removed automatically | ✅ |
| Wait for a CSS selector | ✅ |
| Screenshot of one element (CSS selector) | ✅ |
| Block ads and trackers | ✅ |
| Retina and dark mode | ✅ |
| PDF and Markdown from the same page load | ✅ |
| Failed or blocked pages free | ✅ |
| Start fee or extra compute charge | None |

### Why use it?

- **You only pay for what works.** If a site returns an error (403, 404, 500…), shows a bot-check page, or times out, you are **not charged** for that URL. The dataset tells you why it failed.
- **Clean captures.** Cookie and consent banners are removed automatically, and so are sign-in walls, newsletter and discount pop-ups, push-notification prompts and the dark backdrop behind them (page scrolling is unlocked again). Both can be turned off.
- **Sticky headers only once.** In full-page screenshots, fixed and sticky headers stay at the top, bottom bars and chat buttons move to the end of the page, so nothing repeats or covers the content.
- **Pages that never stop loading still get captured.** Sites with endless trackers or live feeds are captured as soon as their content is there, instead of failing after a timeout.
- **Built for pipelines.** Use it for monitoring, archiving, visual QA, link previews, compliance evidence, or feeding web pages to an LLM / RAG system. Call it from the API, a schedule, Make, Zapier, n8n or an AI agent.
- **Your spending limit is respected.** The Actor reserves budget before starting each page and never does work your maximum charge cannot cover.

### How much does it cost?

This Actor uses **pay-per-event** pricing. You are charged per successful output:

| Event | Price |
|---|---|
| Screenshot | $1.00 / 1,000 |
| PDF | $2.50 / 1,000 |
| Markdown | $2.00 / 1,000 |

**Example:** 1,000 URLs with a screenshot and a PDF of each cost 1,000 × $0.001 + 1,000 × $0.0025 = **$3.50** on the Free plan.

**No start fee.** Failed, blocked and timed-out pages and invalid input lines are free. There is no charge for compute time on top of the event prices. On Apify's Scale plan prices are 10% lower, on Business and higher 20% lower (screenshot $0.80 / 1,000).

#### Total price compared with other screenshot Actors

What you pay per 1,000 screenshots on the Apify Store (checked September 2026). "Platform usage" means the Actor's compute time is billed to your Apify account on top of the listed price, so the total depends on the run:

| Actor | Price per 1,000 screenshots | Also billed to you |
|---|---|---|
| **This Actor** | **$1.00** (Business plan $0.80) | Nothing: no start fee, compute included |
| cheapapi Website Screenshot API | $0.89 (Business plan $0.61) | Platform usage, $0.00001 start fee |
| crawlerbros Screenshot URL | $2.00 (Business plan $1.00) | Platform usage, $0.01 per run |
| moonweil URL Screenshot API | $4.00 | $0.001 per run; one URL per run, so about $5 in bulk |
| i-scraper Website Screenshot | $6.00 | Platform usage |
| dz\_omar Screenshot | $10.00 (Business plan $5.00) | $0.05 start fee plus a memory charge |
| Apify Screenshot URL | Free Actor | Platform usage only |

cheapapi's listed price is lower than ours and it has more options (logins, proxies); compare the total on your own runs. We have no numbers for platform usage, so none are estimated here.

With several devices or widths, each screenshot is one event (3 widths = 3 screenshots). The PDF and the Markdown are made once per URL, with the first device, because they do not depend on the screen size.

### Control your cost

- **What is charged:** each output delivered (screenshot per device or width, PDF, Markdown). Every row has `charged: true` or `false`.
- **What is free:** failed, blocked and timed-out pages, outputs that could not be produced, and invalid input lines.
- At the start, the run logs its worst case, e.g. `Plan: 50 URL(s) × 2 output(s) (screenshot, markdown) = at most $0.15`, and warns when that is more than your **maximum charge per run**.
- When the maximum charge per run is reached, the run stops and keeps everything captured so far. The status message says so, and the `SUMMARY` record has `status: "LIMIT_REACHED"` and `notProcessed` (how many URLs were not started, and up to 100 of them).

### How to use it

1. Paste your URLs into **URLs**, one per line (bare domains like `example.com` are fine).
2. Pick the **Outputs** you want.
3. Optionally tune screenshot, PDF, Markdown and loading options.
4. Click **Start**. Results appear in the **Output** tab.

#### Input example

```json
{
    "urls": ["https://example.com", "www.python.org"],
    "outputs": ["screenshot", "pdf", "markdown"],
    "device": "mobile",
    "fullPage": true,
    "hideCookieBanners": true,
    "screenshotFormat": "jpeg",
    "screenshotQuality": 80
}
```

#### Responsive screenshots: phone, tablet width and desktop in one run

```json
{
    "urls": ["https://stripe.com"],
    "devices": ["desktop", "mobile"],
    "viewportWidths": ["768"],
    "fullPage": true
}
```

Each URL gives one dataset item per variant, with a `variant` field (`desktop`, `mobile`, `768px`) and its own screenshot.

#### Long pages with lazy-loaded images

```json
{
    "urls": ["https://stripe.com"],
    "fullPage": true,
    "scrollToBottom": true,
    "scrollDelaySecs": 1,
    "selectorsToHide": "header, .chat-widget",
    "waitForSelector": "main"
}
```

#### Screenshot of one element, without ads

```json
{
    "urls": ["https://en.wikipedia.org/wiki/Cat", "https://example.com"],
    "outputs": ["screenshot"],
    "screenshotSelector": ".infobox",
    "blockAds": true
}
```

Real output from this input (shortened). The Wikipedia item is a 283 × 1,088 px image of the infobox only. example.com has no `.infobox`, so it got a normal screenshot and `selectorNotFound: true`. Both count as one screenshot each:

```json
[
    { "url": "https://en.wikipedia.org/wiki/Cat", "success": true, "screenshotSelector": ".infobox", "selectorNotFound": false, "screenshotBytes": 260403, "screenshotUrl": "https://api.apify.com/v2/key-value-stores/…/records/00000-en-wikipedia-org-wiki-Cat-screenshot.png" },
    { "url": "https://example.com", "success": true, "screenshotSelector": ".infobox", "selectorNotFound": true, "screenshotBytes": 23439, "screenshotUrl": "https://api.apify.com/v2/key-value-stores/…/records/00001-example-com-screenshot.png" }
]
```

#### Output example

Each URL produces one dataset item. Screenshots and PDFs are stored in the run's key-value store and linked by URL:

```json
{
    "url": "https://stripe.com",
    "finalUrl": "https://stripe.com/",
    "httpStatus": 200,
    "title": "Stripe | Financial Infrastructure to Grow Your Revenue",
    "success": true,
    "inputIndex": 0,
    "inputUrl": "stripe.com",
    "variant": "mobile",
    "device": "mobile",
    "viewportWidth": 390,
    "viewportHeight": 844,
    "pixelDensity": 3,
    "screenshotUrl": "https://api.apify.com/v2/key-value-stores/…/records/00000-stripe-com-screenshot-mobile.jpg",
    "screenshotBytes": 1255663,
    "screenshotTruncated": true,
    "format": "jpeg",
    "fullPage": true,
    "pdfUrl": null,
    "markdown": null,
    "scrolledPx": 16880,
    "hiddenElements": 5,
    "waitForSelectorTimedOut": true,
    "errors": {},
    "loadTimedOut": false,
    "cookieBannersHidden": 0,
    "capturedAt": "2026-09-29T02:01:42.003Z",
    "charged": true
}
```

Field notes:

- `inputIndex` is the URL's position in your list (from 0) and `inputUrl` the line exactly as you entered it. Pages finish in parallel, so sort by `inputIndex` to get your original order.
- `variant` appears only when you use **several devices** or **several widths**.
- `screenshotBytes` / `pdfBytes` are file sizes; `scrolledPx` is how far the page was scrolled; `hiddenElements` counts elements hidden by your selectors.
- `waitForSelectorTimedOut: true` means the element never appeared (this test waited for a selector that does not exist); the page was still captured.
- `screenshotTruncated: true` means the full page was longer than 16,384 px (or your **Max full-page height**) and was cut there. Set `maxScreenshotHeight` (e.g. 3000) when you only want a preview of the top of long pages.
- `screenshotSelector` and `selectorNotFound` appear only when you set **Screenshot only this element**.

A page the site refused looks like this and is not charged:

```json
{ "url": "https://example.com/private", "inputIndex": 3, "inputUrl": "example.com/private", "success": false, "error": "target returned HTTP 403 (not charged)", "errorType": "blocked", "charged": false, "httpStatus": 403 }
```

`errorType` is one of `blocked`, `not_found`, `timeout`, `network`, `http_error`, `too_large`, `unsupported`, `invalid_input` or `failed`. The run's key-value store also has a `SUMMARY` record with `status` (`SUCCESS`, `PARTIAL_RESULTS`, `FAILED`, `NO_RESULTS` or `LIMIT_REACHED`) counts, and `failedUrls` (up to 100).

### Tips

- **Faster runs:** set **Wait until** to `load`. `networkidle2` (default) waits for most network activity to finish, which gives more complete pages but takes longer.
- **Lazy-loaded images:** turn on **Scroll to the bottom first** (and keep a 1-second wait after scrolling).
- **A pop-up or chat bubble is still there:** list its CSS selector in **Hide these elements** (the automatic pop-up detection is conservative: it never hides site headers, hero sections or page content).
- **Charts or widgets that render late:** set **Wait for this element** to their selector.
- **Faster, lighter Markdown:** under **Don't load these resources**, skip images and fonts.
- **No ads or tracking scripts:** turn on **Block ads and trackers** (Advanced settings). It stops about 50 common ad and analytics hosts from loading.
- **Only a pricing table, chart or product box:** set **Screenshot only this element** to its CSS selector. Sticky banners that float over the element are captured too, so also list them in **Hide these elements**.
- **Mobile screenshots:** set **Device** to *Mobile* for a real mobile layout at 3x density.
- **Sharper desktop images:** set **Pixel density** to 2.
- **Dark theme:** turn on **Dark mode** (works on sites that support it).
- **Keep the cookie banner** (e.g. for compliance evidence): turn off **Hide cookie banners**.
- **Only the article text:** set the Markdown CSS selector to `article` or `main`. Navigation, headers and footers are already removed from the Markdown by default (**Remove navigation, headers and footers**): when the page has one main content element (`article`, `main`) only that element is converted, and leftover skip links, empty headings and image placeholders are tidied away; add more selectors under **Also remove these elements from the Markdown**, or turn the option off (`"markdownRemoveBoilerplate": false`) to convert the whole page. In our test the Markdown of `github.com` went from about 66,000 to 9,849 characters.
- **Calling the API or n8n?** Use the plain `urls` list. The older `startUrls` field still works, but Apify rejects the whole run (HTTP 400) when it holds a bare domain or a blank line.
- **Screenshots of a whole website:** get its page list with [Sitemap URL Extractor](https://apify.com/tidytools/sitemap-url-extractor), then pass the `url` values as `urls` here.
- **Only need Markdown for many pages or a whole site?** [Website to Markdown Crawler](https://apify.com/tidytools/website-markdown-crawler) fetches pages over plain HTTP for $1 per 1,000 pages (set **Crawl scope** to *Only the start URLs* for a URL list).

### Use with AI agents (MCP)

Connect Apify's MCP server (https://mcp.apify.com?tools=tidytools/website-screenshot-pdf-markdown) to Claude, Cursor or any MCP client, then ask e.g. "Take full-page desktop and mobile screenshots of stripe.com and give me the image links."

Minimal input:

```json
{ "urls": ["https://stripe.com"], "outputs": ["screenshot"] }
```

Failed items are not charged and carry an `errorType`. Each item links its screenshot (`screenshotUrl`) and PDF (`pdfUrl`); Markdown is inline in `markdown`.

### Use it from code and integrations

Run it from your own code with the Apify API. This call waits for the run and returns the results as JSON (replace `YOUR_TOKEN` with your Apify API token):

```bash
curl -X POST "https://api.apify.com/v2/acts/tidytools~website-screenshot-pdf-markdown/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://example.com"],"outputs":["screenshot","markdown"]}'
```

The synchronous endpoint waits up to 5 minutes. For bigger runs, start the run with `POST https://api.apify.com/v2/acts/tidytools~website-screenshot-pdf-markdown/runs` and read the dataset when it finishes, or use the `apify-client` package for JavaScript or Python.

**Schedules and integrations:** run it daily or weekly with Apify Schedules, get a webhook when a run finishes, or send the results to Zapier, Make, n8n, Google Sheets, Slack and other apps with Apify integrations. Results can be exported as JSON, CSV, Excel or XML.

### Limitations

- Only public `http`/`https` pages. Pages behind a login, private networks and local addresses are not supported.
- Some sites actively block automated browsers. Those URLs are reported as failed and are not charged.
- Full-page screenshots are cut at 16,384 px height.
- Pages are rendered on our own servers, so Apify proxies cannot be used for this Actor.
- Captures are rendered by a headless Chromium browser, so a few sites may look slightly different than in your own browser.

### Is it legal to capture websites?

Capturing publicly available pages is generally allowed, but you are responsible for how you use the output. Respect each site's terms of service, copyright and privacy laws, and don't use the results to collect personal data without a legal basis.

### FAQ

**Can I take full-page screenshots of many URLs at once?** Yes. Paste the URLs one per line (bare domains are fine) and turn on **Full page**. Long pages are cut at 16,384 px (or your **Max full-page height**); turn on **Scroll to the bottom first** so lazy-loaded images appear.

**How do I convert a URL to PDF?** Pick **PDF** under **Outputs**: A4, Letter or Legal, portrait or landscape, with backgrounds, for $2.50 per 1,000 PDFs. The PDF, screenshot and Markdown come from the same page load.

**Can I get mobile and tablet screenshots?** Yes. Set **Device** to *Mobile* for a real mobile layout at 3x density, or list several devices or widths (`devices`, `viewportWidths`) to get each variant in one run. Each variant is one screenshot.

**Can I use it as a screenshot API from my code?** Yes. Call the `run-sync-get-dataset-items` endpoint shown above, use the `apify-client` package, or connect it to an AI agent through Apify's MCP server. Failed pages are not charged.

### Support

Found a page that doesn't render correctly or need a feature? Open an issue in the **Issues** tab with the URL and your input settings.

# Actor input Schema

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

Main input (fill this, or `startUrls`). Pages to capture, one per line. Bare domains (example.com) are fine; blank or invalid lines are skipped and listed in the results (not charged). Only public http(s) URLs are supported.

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

What to produce for each page. You are charged only for outputs that succeed.

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

Emulate a device. Mobile and tablet use a touch screen, mobile layout and high pixel density. Choose "Custom" to use the width and height below.

## `devices` (type: `array`):

Capture every URL once per device (one dataset item and one screenshot each, with a "variant" field). Overrides Device. PDF and Markdown are made once per URL, with the first device.

## `viewportWidths` (type: `array`):

Capture every URL once per width, e.g. 375, 768, 1920 (200–3840). Combined with the devices above, at most 10 variants. Each screenshot is charged separately.

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

Capture the whole scrollable page instead of only the viewport (very long pages are cut at 16,384 px).

## `maxScreenshotHeight` (type: `integer`):

Cut full-page screenshots at this height, e.g. 3000 for a preview of the top of long pages. 0 = no limit (pages are still cut at 16,384 px). Ignored for viewport and element screenshots.

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

Used when Device is "Custom". 1280 is a typical laptop.

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

Used when Device is "Custom". Also the screenshot height when full-page is off.

## `pixelDensity` (type: `integer`):

Device pixel ratio: 2 or 3 gives sharp retina images. Leave empty to use the device default (desktop 1x, tablet 2x, mobile 3x).

## `screenshotFormat` (type: `string`):

PNG is lossless; JPEG and WebP are much smaller files.

## `screenshotQuality` (type: `integer`):

Compression quality for JPEG and WebP. Ignored for PNG.

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

Ask the page for its dark theme (prefers-color-scheme: dark). Only affects sites that support dark mode.

## `hideCookieBanners` (type: `boolean`):

Remove cookie and consent pop-ups (OneTrust, Cookiebot, Didomi, Quantcast and many more) before capturing. Applies to screenshots, PDFs and Markdown.

## `hidePopups` (type: `boolean`):

Hide sign-in walls, newsletter and discount pop-ups, push-notification prompts, country pickers and the dark backdrop behind them, and unlock page scrolling. Site headers, hero sections and page content are never hidden. The item reports how many elements were hidden in "popupsHidden".

## `fixStickyHeaders` (type: `boolean`):

For full-page screenshots: fixed and sticky headers, bottom bars and chat buttons are pinned so they appear once (headers at the top, bottom bars at the end of the page) instead of covering content in the middle of the page.

## `selectorsToHide` (type: `string`):

Comma-separated CSS selectors to hide before capturing, e.g. ".chat-widget, #newsletter-popup". Also removed from the Markdown.

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

Paper size of the generated PDF.

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

Print the PDF in landscape orientation.

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

Include background colours and images in the PDF.

## `markdownCssSelector` (type: `string`):

Optional, e.g. "article" or "main". Leave empty to convert the whole page.

## `markdownRemoveBoilerplate` (type: `boolean`):

On by default (also for API calls). Drops nav bars, site headers and footers, sidebars, breadcrumbs, cookie notices and "Skip to main content" links from the Markdown. Screenshots and PDFs are not affected. Set to false to convert the whole page.

## `markdownRemoveSelectors` (type: `string`):

Optional comma-separated CSS selectors, e.g. ".related-posts, #comments". Works with or without the option above.

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

When the page counts as loaded. "networkidle2" works for most sites; use "load" for faster captures.

## `delaySecs` (type: `integer`):

Wait this many seconds after the page loads before capturing (useful for animations or lazy content).

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

If the page has not finished loading by then, whatever has loaded is captured.

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

Scroll through the page before capturing so lazy-loaded images and sections appear, then scroll back to the top. Recommended with full-page screenshots.

## `scrollDelaySecs` (type: `integer`):

Used with "Scroll to the bottom first": how long to wait after scrolling back up.

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

Optional, e.g. "#pricing-table". Waits until it appears (within the page load timeout). If it never appears the page is still captured and the item gets "waitForSelectorTimedOut": true.

## `blockResources` (type: `array`):

Skip images, fonts, media or stylesheets for faster, lighter captures (mostly useful for Markdown).

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

How many pages are captured at the same time.

## `screenshotSelector` (type: `string`):

Optional, e.g. "#pricing" or ".chart". The screenshot shows only the first matching element (the full-page option is ignored). If the element is not on the page, a normal screenshot is taken and the item gets "selectorNotFound": true. Priced as one screenshot.

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

Don't load requests to about 50 common ad, analytics and tracking hosts (Google Ads, DoubleClick, Facebook pixel, Hotjar and more). Cleaner, faster screenshots and Markdown. The page itself is never blocked.

## `startUrls` (type: `array`):

Same as the list above, in Apify's request-list format. Kept for older inputs; the plain list above is recommended, especially for API calls.

## Actor input object example

```json
{
  "urls": [
    "https://example.com"
  ],
  "outputs": [
    "screenshot",
    "markdown"
  ],
  "device": "desktop",
  "fullPage": false,
  "maxScreenshotHeight": 0,
  "viewportWidth": 1280,
  "viewportHeight": 800,
  "screenshotFormat": "png",
  "screenshotQuality": 80,
  "darkMode": false,
  "hideCookieBanners": true,
  "hidePopups": true,
  "fixStickyHeaders": true,
  "pdfFormat": "A4",
  "pdfLandscape": false,
  "pdfPrintBackground": true,
  "markdownRemoveBoilerplate": true,
  "waitUntil": "networkidle2",
  "delaySecs": 0,
  "timeoutSecs": 30,
  "scrollToBottom": false,
  "scrollDelaySecs": 1,
  "maxConcurrency": 5,
  "blockAds": false
}
```

# Actor output Schema

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

No description

## `markdown` (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://example.com"
    ],
    "outputs": [
        "screenshot",
        "markdown"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidytools/website-screenshot-pdf-markdown").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://example.com"],
    "outputs": [
        "screenshot",
        "markdown",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("tidytools/website-screenshot-pdf-markdown").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://example.com"
  ],
  "outputs": [
    "screenshot",
    "markdown"
  ]
}' |
apify call tidytools/website-screenshot-pdf-markdown --silent --output-dataset

```

## MCP server setup

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

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/aHKoTOLGnFnzHgHPI/builds/LMmILI29BMnuzFUKz/openapi.json
