# Website Screenshot API: URL to PNG or JPEG (`touchrock/url-screenshot`) Actor

Take screenshots of any list of public URLs: viewport or full page, PNG or JPEG, custom width and height. Pay only for screenshots stored; URLs that fail are free.

- **URL**: https://apify.com/touchrock/url-screenshot.md
- **Developed by:** [Touchrock](https://apify.com/touchrock) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.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.

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 API: URL to PNG or JPEG

Give it a list of public URLs and get one screenshot per URL: the visible viewport or the full page, as PNG or JPEG,
at the width and height you choose. Each screenshot is stored with a public link in the run's key-value store, and the
dataset lists every URL with its result.

### What you get

- **Viewport or full page.** Full-page shots scroll the whole page (very long pages are cut at 16,000 px, and the row
  says so with `cutAtMaxHeight: true`).
- **PNG or JPEG**, JPEG quality 1-100.
- **Any viewport** from 320×240 (phones) to 3840×2160 (4K).
- **Wait options:** page loaded, HTML ready, or network quiet, plus an extra delay of up to 10 s for animations.
- **Clean browser for each URL:** no cookies, no login, no shared state between URLs.
- **The reason for every URL that could not be captured**, in the dataset.

### Pricing

**$3.00 per 1,000 screenshots** ($0.003 each), pay per event. You pay only for screenshots that are stored.
**Never charged:** invalid URLs, pages that do not load, pages that answer an HTTP error (4xx or 5xx), and URLs beyond
your maximum cost per run (they are not opened). Apify also bills its usual tiny "Actor start" event.

### Input example

```json
{
    "urls": ["https://example.com", "https://en.wikipedia.org/wiki/Web_scraping"],
    "fullPage": false,
    "width": 1280,
    "height": 800,
    "format": "png"
}
```

### Output example (one dataset row)

```json
{
    "url": "https://example.com/",
    "ok": true,
    "screenshotUrl": "https://api.apify.com/v2/key-value-stores/<storeId>/records/screenshot-0f115db062b7c0dd030b.png",
    "screenshotKey": "screenshot-0f115db062b7c0dd030b.png",
    "finalUrl": "https://example.com/",
    "httpStatus": 200,
    "title": "Example Domain",
    "format": "png",
    "width": 1280,
    "height": 800,
    "fullPage": false,
    "cutAtMaxHeight": false,
    "bytes": 21016,
    "capturedAt": "2026-10-23T22:40:00.000Z",
    "charged": true,
    "error": null
}
```

A URL that fails has `ok: false`, `charged: false` and the reason in `error` (for example
`the page answered HTTP 404` or `the domain does not resolve (DNS lookup failed)`).

The run also writes an `OUTPUT` record with the totals: captured, failed, invalid, over the maximum cost, and the
amount charged.

### Limits and good use

- Up to 1,000 URLs per run. Only public `http` and `https` addresses: private networks, `localhost` and URLs with a
  login are refused.
- The Actor does not log in, solve CAPTCHAs or bypass blocks. A site that blocks automated browsers gives an error
  (free) or a screenshot of its block page.
- **You are responsible for using it in line with each website's terms of use and the law** (for example copyright
  of what you capture). Capture only pages you are allowed to capture.

### Use from the API

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

### Support

Open an issue on the Actor's Issues tab; we answer within a few days.

# Actor input Schema

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

Public http or https URLs, up to 1,000 per run. A bare domain (example.com) gets https://. Private and local addresses are refused. Make sure your use respects each site's terms.

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

Capture the whole scrollable page instead of only the visible viewport. Very long pages are cut at 16,000 px.

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

Browser window width, 320-3840.

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

Browser window height, 240-2160. With full page on, this is the minimum height.

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

PNG is lossless; JPEG is smaller.

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

1-100, used only for JPEG.

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

When the page counts as ready for the screenshot.

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

Extra time to wait after the page is ready, for animations or late content. 0-10000.

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

A page that takes longer fails and is not charged. 5-120.

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://en.wikipedia.org/wiki/Web_scraping"
  ],
  "fullPage": false,
  "width": 1280,
  "height": 800,
  "format": "png",
  "quality": 80,
  "waitUntil": "load",
  "delayMs": 0,
  "timeoutSecs": 30
}
```

# Actor output Schema

## `results` (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": [
        "https://example.com",
        "https://en.wikipedia.org/wiki/Web_scraping"
    ]
};

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

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

```

## MCP server setup

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

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/gajC4c1doODugV1ZF/builds/CngYwLtuL9WyuTw3i/openapi.json
