# ScreenshotKit: Website Screenshot, Scrolling Video & PDF API (`ayushunleashed/screenshotkit`) Actor

Screenshots, smooth scrolling videos (MP4/GIF) and PDFs of any website or HTML. Full page, element, retina, mobile, dark mode, proxies, cookie-banner removal. Batch or real-time API.

- **URL**: https://apify.com/ayushunleashed/screenshotkit.md
- **Developed by:** [Ayush Yadav](https://apify.com/ayushunleashed) (community)
- **Categories:** Developer tools, Automation, SEO tools
- **Stats:** 1 total users, 0 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?

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

## ScreenshotKit: Website Screenshot, Scrolling Video & PDF API

Capture **screenshots**, smooth **auto-scrolling videos** and **PDFs** of any website, or of your own HTML. Pass a list of URLs and get back a clean file per page, sized for desktop, laptop, tablet, phone or any custom viewport. Already used for 100,000+ captures on Replicate.

Use it as a normal Actor (batch of URLs) or as a **real-time HTTP API** through Standby mode, where one request returns the file.

### What can ScreenshotKit do?

- 📸 **Screenshots**: viewport, **full page**, a single **element** (`#pricing`), or a **region** (`x,y,width,height`)
- 🔍 **Retina**: 1×, 2× or 3× pixel density
- 🎬 **Scrolling videos**: the page scrolls smoothly top to bottom, **exactly** 0.1–30 seconds long, as MP4, WebM or GIF
- 📄 **PDFs**: A4, Letter or Legal, with backgrounds
- 🧾 **HTML input**: render your own HTML (OG images, invoices, templates)
- 📱 **Devices**: Desktop 1920×1080, Laptop 1440×900, Tablet 820×1180, Phone 390×844 (real mobile sites), or custom up to 4000px
- 🧹 **Clean captures by default**: cookie banners and chat widgets removed, lazy-loaded images and scroll animations loaded first
- 🚫 **Block ads and trackers**, hide any element, inject your own CSS or JavaScript, click something before capturing
- 🔐 **Logged-in pages**: send cookies and HTTP headers (e.g. `Authorization`)
- 🌍 **Dark mode, timezone, locale, user agent**, and **residential proxies** with country selection for sites that block cloud servers
- ⚡ **Real-time API**: Standby mode returns the file from one HTTP call

Typical uses: link previews and OG images, landing-page videos for social media, visual monitoring, archiving pages as PDF, competitor tracking, documentation screenshots, and feeding page images to AI agents.

### How to use ScreenshotKit

1. Click **Try for free** and enter one or more URLs (`stripe.com` works; `https://` is added automatically), or paste HTML.
2. Pick **Screenshot**, **Scrolling video** or **PDF**, and a device.
3. Click **Start**. Each page produces a file in the run's key-value store and a row in the dataset with a direct download link.

### Input

| Field | Description | Default |
|---|---|---|
| `urls` | Website URLs | — |
| `html` | Raw HTML to render instead of a URL | — |
| `action` | `screenshot`, `video` or `pdf` | `screenshot` |
| `device` | `desktop`, `laptop`, `tablet`, `phone` or `custom` (+ `width`, `height`) | `desktop` |
| `device_scale_factor` | Pixel density 1–3 (2 = retina) | `1` |
| `full_page` | Capture the whole scrollable page | `false` |
| `selector` | Capture only this element, e.g. `#pricing` | — |
| `clip` | Capture a region, `"x,y,width,height"` | — |
| `image_format`, `image_quality` | `png`, `jpeg` or `webp`; quality 1–100 | `png` |
| `video_duration`, `video_format` | 0.1–30 seconds; `mp4`, `webm` or `gif` | `10`, `mp4` |
| `pdf_format` | `A4`, `Letter` or `Legal` | `A4` |
| `hide_cookie_banners` | Remove cookie/consent popups | `true` |
| `hide_chat_widgets` | Remove Intercom, Drift, Crisp, HubSpot and similar chat bubbles | `true` |
| `block_ads` | Block major ad networks and trackers | `false` |
| `hide_selectors` | Elements to remove, e.g. `[".promo-bar"]` | — |
| `custom_css`, `custom_js` | CSS or JavaScript to run before capturing | — |
| `click_selector` | Element to click before capturing | — |
| `wait_until` | `load`, `domcontentloaded`, `networkidle` or `time` | `load` |
| `wait_for_selector` | Wait until this element appears | — |
| `wait_time` | Extra seconds to wait | — |
| `dark_mode` | Request the site's dark theme | `false` |
| `timezone`, `locale`, `user_agent` | e.g. `Europe/Berlin`, `de-DE` | — |
| `headers`, `cookies` | e.g. `{"Authorization": "Bearer …"}`, `[{"name": "session", "value": "…"}]` | — |
| `proxy`, `proxy_country` | `none`, `datacenter` or `residential`; e.g. `US` | `none` |

```json
{
    "urls": ["https://stripe.com", "apify.com"],
    "action": "screenshot",
    "device": "laptop",
    "device_scale_factor": 2,
    "full_page": true,
    "image_format": "jpeg",
    "image_quality": 80
}
```

### Output

One dataset item per page:

```json
{
    "url": "https://stripe.com",
    "action": "screenshot",
    "file_url": "https://api.apify.com/v2/key-value-stores/aBcDeFgHiJkLmNoPq/records/screenshot-1.jpeg",
    "key": "screenshot-1.jpeg",
    "content_type": "image/jpeg",
    "device": "laptop",
    "width": 1440,
    "height": 900,
    "error": null
}
```

If a page can't be loaded (bad domain, element not found), its item has an `error` message and **you are not charged** for it. The other URLs still complete.

### Real-time API (Standby mode)

Call the Actor like a regular screenshot API. The response body is the file itself.

```bash
curl -H "Authorization: Bearer $APIFY_TOKEN" \
  "https://ayushunleashed--screenshotkit.apify.actor/?url=stripe.com&device=phone&image_format=webp" \
  -o stripe.webp
```

Every input field works as a query parameter (lists and objects as JSON strings), or send them as a JSON body with `POST /`, which is the way to pass `html`:

```bash
curl -X POST -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
  -d '{"html": "<h1>Hello</h1>", "device": "custom", "width": 1200, "height": 630, "device_scale_factor": 2}' \
  "https://ayushunleashed--screenshotkit.apify.actor/" -o og.png
```

Responses: `200` with the file, `400` for invalid parameters, `502` when the page could not be captured (not charged).

### Pricing

Pay per event. You pay only for successful captures; failed pages are free. Residential proxy use is charged per capture on top. See the pricing tab for current prices.

### FAQ

**Why are some images blank in full-page screenshots?** ScreenshotKit scrolls the page first to load lazy images, but a few sites only render sections while they're on screen. Recording a scrolling video captures those.

**Why did I get a "blocked" page?** Some sites block cloud servers. Set `proxy` to `residential` (optionally with `proxy_country`), which gets through most of them (e.g. Reddit). A few sites with advanced bot protection (e.g. NYT) still can't be captured.

**Can I capture pages behind a login?** Yes: pass your session `cookies` or an `Authorization` header.

**Does dark mode work everywhere?** It works on sites that follow the system dark-mode setting (`prefers-color-scheme`). Sites with only a manual toggle can be switched with `click_selector` or `custom_js`.

**What video format is used?** MP4 (H.264, 30 fps) by default, exactly the duration you request. WebM and GIF (10 fps, up to 640px wide) are also available.

**How are scrolling videos made?** ScreenshotKit loads the whole page (including lazy images), captures it once, and renders a perfectly smooth ease-in-out scroll over it. That makes every video smooth no matter how heavy the site is. The trade-off: the page is frozen while it scrolls, so sticky headers stay at the top and on-page animations or embedded videos don't play.

**How long does a capture take?** A viewport screenshot usually takes 3–15 seconds (ScreenshotKit waits for the page to finish rendering and loads lazy content), a full page a bit longer. Short videos take about 20–60 seconds; a 30-second video takes around 3 minutes. For long videos, use a normal run rather than the real-time API.

**Is it legal to screenshot websites?** Capturing publicly available pages is generally fine. Respect each site's terms and don't capture personal data without a legitimate reason.

# Actor input Schema

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

Pages to capture. https:// is added if missing (stripe.com works).

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

Optional: raw HTML to capture instead of (or in addition to) URLs. Handy for OG images and templates.

## `action` (type: `string`):

Screenshot image, auto-scrolling video, or PDF of the page.

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

Viewport preset. Tablet and phone load the mobile version of sites.

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

Viewport width. Used only when device is Custom.

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

Viewport height. Used only when device is Custom.

## `device_scale_factor` (type: `number`):

2 = retina (twice the pixels), 3 = high-end phones. Applies to screenshots.

## `full_page` (type: `boolean`):

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

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

CSS selector of a single element to capture, e.g. #pricing or .hero. Overrides full page.

## `clip` (type: `string`):

Capture a rectangle: "x,y,width,height" in CSS pixels, e.g. 0,0,1200,630.

## `image_format` (type: `string`):

Screenshot file format.

## `image_quality` (type: `integer`):

Quality for JPEG/WebP (1-100). Ignored for PNG.

## `video_duration` (type: `number`):

Exact length of the video. The page scrolls from top to bottom over this time.

## `video_format` (type: `string`):

MP4 plays everywhere; GIF is for embeds in docs and emails.

## `pdf_format` (type: `string`):

Paper size when Output is PDF. Backgrounds are included.

## `hide_cookie_banners` (type: `boolean`):

Remove cookie and consent popups.

## `hide_chat_widgets` (type: `boolean`):

Remove Intercom, Drift, Crisp, HubSpot, Zendesk, Tawk and similar chat bubbles.

## `block_ads` (type: `boolean`):

Drop requests to major ad networks and trackers.

## `hide_selectors` (type: `array`):

CSS selectors of elements to remove before capturing, e.g. .promo-bar.

## `custom_css` (type: `string`):

CSS injected into the page before capturing.

## `custom_js` (type: `string`):

JavaScript run in the page before capturing (await is allowed).

## `click_selector` (type: `string`):

CSS selector to click before capturing, e.g. a tab or "Accept" button.

## `wait_until` (type: `string`):

When the page counts as ready.

## `wait_for_selector` (type: `string`):

Wait until this CSS selector appears (up to 20s) before capturing.

## `wait_time` (type: `number`):

Seconds to wait after the page loads. Required when Wait until is Fixed time.

## `dark_mode` (type: `boolean`):

Ask the site for its dark theme (prefers-color-scheme: dark). Works on sites that support a system dark mode.

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

IANA timezone, e.g. America/New_York.

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

Browser language, e.g. de-DE. Sites that localize will show this language.

## `user_agent` (type: `string`):

Override the browser user agent.

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

Extra headers for every request, e.g. {"Authorization": "Bearer ..."}.

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

Cookies to set, e.g. \[{"name": "session", "value": "abc"}] (domain defaults to the URL). Use this to capture logged-in pages.

## `proxy` (type: `string`):

Residential proxies get through sites that block cloud servers (e.g. NYT, Reddit). Datacenter proxies only change the IP/country and are still blocked by those sites.

## `proxy_country` (type: `string`):

Two-letter country code for the proxy IP, e.g. US, DE.

## Actor input object example

```json
{
  "urls": [
    "https://stripe.com"
  ],
  "action": "screenshot",
  "device": "desktop",
  "device_scale_factor": 1,
  "full_page": false,
  "image_format": "png",
  "video_duration": 10,
  "video_format": "mp4",
  "pdf_format": "A4",
  "hide_cookie_banners": true,
  "hide_chat_widgets": true,
  "block_ads": false,
  "wait_until": "load",
  "dark_mode": false,
  "headers": {},
  "cookies": [],
  "proxy": "none"
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset with a file link per captured URL

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

Key-value store holding the images and videos

# 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://stripe.com"
    ],
    "headers": {},
    "cookies": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("ayushunleashed/screenshotkit").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://stripe.com"],
    "headers": {},
    "cookies": [],
}

# Run the Actor and wait for it to finish
run = client.actor("ayushunleashed/screenshotkit").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://stripe.com"
  ],
  "headers": {},
  "cookies": []
}' |
apify call ayushunleashed/screenshotkit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ayushunleashed/screenshotkit"
        }
    }
}
```

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/89DZhz2XCJxS42cgb/builds/LIRh0sfA2Xq1fEPw0/openapi.json
