# Download HTML from URLs (`scrapers-hub/download-html-from-urls`) Actor

Download HTML from URLs fetches raw and rendered page HTML in bulk, with optional headless Chrome, retries and per-page timeouts. 💾 Useful for archiving, scraping pipelines, page-change diffing and building training corpora.

- **URL**: https://apify.com/scrapers-hub/download-html-from-urls.md
- **Developed by:** [Scrapers Hub](https://apify.com/scrapers-hub) (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

from $1.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

### 🌐 Download HTML from URLs – Bulk HTML Downloader & Raw Page Source Extractor

The **HTML downloader** takes a list of URLs and returns the complete HTML source of each page as structured dataset items, ready for parsing, archiving, diffing or feeding into a downstream extraction pipeline. Instead of writing your own fetch loop, handling retries, rotating IP addresses and babysitting timeouts, you hand this Actor an array of URLs and collect clean `fullHtml` and `html` strings from the Apify dataset.

This HTML downloader is deliberately unopinionated. It does not try to guess what a "product" or an "article" is, it does not impose a schema on the sites you crawl, and it does not silently drop pages it could not parse. It fetches, records what came back, and tells you plainly when something failed. That makes it a solid first stage for custom scraping projects, LLM ingestion pipelines, SEO audits, compliance snapshots and regression testing of your own web properties.

Two fetch modes are available. By default a plain HTTP client retrieves the raw server response, which is fast and cheap. Enable the headless Chrome option and pages are rendered with a real browser engine so that JavaScript-generated markup appears in the captured HTML — essential for single-page applications and client-side-rendered frameworks.

***

### 📊 What Data Can You Extract with This HTML Downloader Scraper?

Every dataset item produced by the HTML downloader maps to one input URL. The field set is small on purpose — the value is in the completeness and fidelity of the markup, not in a wide schema.

| Category | Fields | What it gives you |
|---|---|---|
| 🔗 Page identity | `url` | The canonical URL of the page that was fetched, so items can be joined back to your source list |
| 📄 Full document markup | `fullHtml` | The complete HTML document including `<!DOCTYPE>`, `<html>`, `<head>`, meta tags, structured-data blocks and inline scripts |
| 🧱 Body markup | `html` | The body-level markup on its own, which is usually what you want for content parsing and text extraction |
| ⏱️ Timing metadata | `finishedAt` | ISO-8601 timestamp recording when the fetch for that URL completed |
| ⚠️ Failure reporting | `error` | A human-readable error message when a URL could not be retrieved, instead of a silently missing row |

The genuinely useful detail here is the split between `fullHtml` and `html`. Keeping both means you can read `<head>` metadata — canonical tags, Open Graph properties, JSON-LD structured data, hreflang alternates — from `fullHtml` while running your text and DOM parsing against the smaller, cleaner `html` body payload, without paying to fetch the page twice.

***

### 🌟 Key Features of the HTML Downloader Scraper

| Feature | Description |
|---|---|
| 📥 Bulk URL intake | Feed an array of URL objects in Apify's standard `requestListSources` format — paste a list, upload a file, or pass it through the API |
| ⚡ Fast HTTP mode | The default plain HTTP client fetches raw server responses without booting a browser, keeping runs quick and inexpensive |
| 🖥️ Headless Chrome rendering | Flip `useChrome` to `true` and pages are rendered with Playwright so JavaScript-injected DOM content ends up in the saved HTML |
| 🔁 Configurable retries | `maxRequestRetries` controls how many times a failing URL is attempted again before it is recorded as an error |
| ⏳ Per-page timeout control | `handlePageTimeoutSecs` caps how long a single page may take, so one slow host cannot stall an entire batch |
| 🕸️ Automatic proxy rotation | Requests are routed through rotating proxy infrastructure automatically, reducing IP-level blocking on larger lists |
| 🧾 Error rows, not silence | Failed URLs still produce a dataset item carrying the `error` message, so your pipeline can retry or report precisely |
| 🗂️ Dual markup capture | Both the full document and the body-only markup are stored per URL, covering metadata parsing and content parsing in one pass |
| 🔌 Dataset-native output | Results land in an Apify dataset and export as JSON, CSV, Excel, XML or JSONL, or stream straight out via the API |

***

### 🚀 Why Choose This HTML Downloader Scraper?

**Raw fidelity over lossy parsing.** Most scrapers hand you a pre-chewed schema and throw away everything that did not fit. This HTML downloader keeps the source document intact, so when your extraction rules change next month you re-parse the stored markup instead of re-crawling the web.

**A real choice between speed and JavaScript.** Plain HTTP fetching is dramatically cheaper and faster, and for server-rendered sites it is all you need. When you hit a React or Vue application whose content only exists after hydration, the `useChrome` switch renders the page properly rather than leaving you with an empty shell.

**Failure is visible, not hidden.** A URL that times out or returns a network error still produces a row with a populated `error` field alongside its `url`. That makes reconciliation trivial: count your input URLs, count your output items, and inspect exactly which ones need another attempt.

**Operational controls that actually matter.** Retry count and per-page timeout are the two knobs that determine whether a large batch finishes cleanly or grinds to a halt. Both are exposed directly, so you can tune a fast shallow sweep or a patient, tolerant crawl of slow legacy sites.

***

### 📥 Input

The HTML downloader accepts a compact input object. Only the URL list is required.

```json
{
  "requestListSources": [
    { "url": "https://apify.com" },
    { "url": "https://example.com/pricing" },
    { "url": "https://example.com/blog/post-1" }
  ],
  "useChrome": false,
  "maxRequestRetries": 1,
  "handlePageTimeoutSecs": 60
}
```

#### 🔧 HTML Downloader Scraper Input Fields

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `requestListSources` | array | ✅ Yes | — | List of URLs to fetch. Each item is an object with a `url` field, matching the Apify RequestList source format. |
| `useChrome` | boolean | No | `false` | If enabled, pages are rendered with a headless browser (Playwright) so the returned HTML reflects JavaScript-rendered content. If disabled, a plain HTTP client is used — faster and cheaper, but it only returns the raw server response. |
| `maxRequestRetries` | integer | No | `1` | How many times to retry a failed request before giving up on it. |
| `handlePageTimeoutSecs` | integer | No | `60` | Maximum time allowed to load and process a single page before it is considered failed. |

#### 💡 Input Examples

**Fast batch of server-rendered pages**

```json
{
  "requestListSources": [
    { "url": "https://example.com/" },
    { "url": "https://example.com/about" }
  ],
  "useChrome": false
}
```

**JavaScript-heavy single-page application**

```json
{
  "requestListSources": [
    { "url": "https://app.example.com/dashboard/public" }
  ],
  "useChrome": true,
  "handlePageTimeoutSecs": 120
}
```

**Tolerant crawl of slow or flaky hosts**

```json
{
  "requestListSources": [
    { "url": "https://legacy.example.org/catalogue" },
    { "url": "https://legacy.example.org/archive" }
  ],
  "maxRequestRetries": 4,
  "handlePageTimeoutSecs": 180
}
```

***

### 📤 Output

Each dataset item corresponds to one URL from your input list. The example below is a real record from an actual run, with the long markup strings truncated for readability.

```json
{
  "url": "https://apify.com",
  "finishedAt": "2026-08-08T16:18:44.743Z",
  "fullHtml": "<!DOCTYPE html><html data-dpl-id=\"d89ccaca32\" class=\"inter_20da4d53-module__W1FniW__className\" …",
  "html": "<body><div hidden=\"\"><!--$--><!--/$--></div><script id=\"json-ld-organization\" type=\"applicatio…"
}
```

When a URL fails, the item carries the error instead of markup:

```json
{
  "url": "https://unreachable.example.com/page",
  "finishedAt": "2026-08-08T16:19:02.118Z",
  "error": "Request timed out after 60 seconds"
}
```

#### 🧾 HTML Downloader Output Fields

| Field | Type | Description |
|---|---|---|
| `url` | string | null | Canonical URL of the scraped item. |
| `finishedAt` | string | null | When the fetch finished, as an ISO-8601 timestamp. |
| `fullHtml` | string | null | Full HTML of the item, including the document head. |
| `html` | string | null | Raw body HTML of the item. |
| `error` | string | null | Error message, if the item failed to process. |

***

### 💻 How to Use the HTML Downloader Scraper (Step by Step)

#### Step 1: Assemble Your URL List for HTML Extraction

Start by collecting the URLs you want to download. The `requestListSources` field expects an array of objects, each with a single `url` key. This is Apify's standard request-list format, which means the Apify Console editor gives you a friendly interface: paste a newline-separated list, upload a text or CSV file of links, or pull them from a remote URL. If you are calling the Actor programmatically, build the array in your own code — for example by mapping over a sitemap you have already parsed, or over the `permalink` values from another dataset.

#### Step 2: Decide Whether You Need Headless Chrome

This is the single most consequential setting. Leave `useChrome` at its default of `false` when the pages you are fetching are server-rendered — most WordPress sites, most e-commerce category pages, most news publishers and virtually every documentation site fall into this camp. Switch it to `true` only when a quick manual check shows that the content you care about is missing from the raw response. A good test is to open the page, view source, and search for a phrase you can see on screen. If the phrase is absent from the source, you need browser rendering.

#### Step 3: Tune Retries and the Page Timeout

`maxRequestRetries` defaults to `1`, which means a URL gets one additional attempt after its first failure. Raise it to three or four when you are crawling hosts known to be rate-limited or intermittently slow. `handlePageTimeoutSecs` defaults to 60 seconds; that is comfortable for HTTP mode but can be tight for heavy pages under browser rendering, where 120 to 180 seconds is a more realistic ceiling. Setting both too high wastes compute on genuinely dead links, so treat them as a budget rather than a maximum.

#### Step 4: Run the HTML Downloader and Watch the Log

Click **Start** in the Apify Console, or trigger the run through the API. The run log reports progress as URLs are processed and surfaces network-level problems as they occur. For a first run against an unfamiliar domain, use a small sample of five to ten URLs. It costs almost nothing and immediately tells you whether the markup you need is present, whether the site is blocking you, and whether your timeout is realistic.

#### Step 5: Inspect the Captured HTML

Open the dataset and expand a couple of items. Check that `fullHtml` starts with a doctype and contains the `<head>` elements you expect — canonical link, meta description, any JSON-LD blocks. Check that `html` contains the visible body content rather than a loading skeleton. If `html` looks like an empty container with a spinner, that is the classic signature of a client-rendered app and your cue to re-run with `useChrome` enabled.

#### Step 6: Export or Stream the Results

Export the dataset from the Console in JSON, CSV, Excel, XML or JSONL, or fetch it through the Apify API. Because the HTML strings can be large, JSONL is often the most practical format for downstream processing: you can stream it line by line without loading the whole file into memory. If you are feeding a database or a vector store, pull items in pages using the dataset API rather than downloading a single monolithic file.

#### Step 7: Parse, Diff or Archive Downstream

The Actor's job ends when the markup is safely stored. What happens next is yours: run BeautifulSoup, Cheerio, `parsel` or an XPath library over `html` to extract fields; parse JSON-LD from `fullHtml` to pick up structured product and organisation data; hash the markup and compare against yesterday's run to detect changes; or push the documents into a text-extraction pipeline for an LLM index. Because the raw source is preserved, you can iterate on extraction logic without ever re-crawling.

***

### 🔌 API Access & Integrations

Run the HTML downloader synchronously and receive the dataset items in a single call:

```bash
curl -X POST "https://api.apify.com/v2/acts/scrapers-hub~download-html-from-urls/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestListSources": [
      { "url": "https://apify.com" },
      { "url": "https://example.com" }
    ],
    "useChrome": false,
    "maxRequestRetries": 2,
    "handlePageTimeoutSecs": 60
  }'
```

The same run in Python with the official client:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")

run_input = {
    "requestListSources": [
        {"url": "https://apify.com"},
        {"url": "https://example.com"},
    ],
    "useChrome": True,
    "maxRequestRetries": 3,
    "handlePageTimeoutSecs": 120,
}

run = client.actor("scrapers-hub/download-html-from-urls").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item.get("error"):
        print("FAILED", item["url"], item["error"])
    else:
        print(item["url"], len(item.get("html") or ""), "bytes of body HTML")
```

Beyond direct API calls, the Actor connects to Zapier, Make, Google Sheets, Slack and any HTTP endpoint through Apify webhooks, so a completed run can automatically trigger a parsing job, drop a notification into a channel, or append rows to a spreadsheet.

***

### 💡 Best Use Cases for HTML Downloader Data

#### 🧪 Building Custom Parsers Without Repeated Crawling

Extraction rules change constantly as sites redesign. By storing `fullHtml` and `html` once, you can develop and test selectors offline against real markup, re-running your parser as often as you like without touching the target site again. This slashes both development time and the risk of getting blocked while iterating.

#### 📈 SEO Audits and On-Page Technical Checks

`fullHtml` contains the `<head>` block, which is where SEO lives: title tags, meta descriptions, canonical URLs, robots directives, hreflang, Open Graph and Twitter cards, and JSON-LD structured data. Pull a few thousand URLs from a sitemap, download their markup, and run automated checks for missing canonicals, duplicate titles or malformed schema markup.

#### 🗄️ Compliance Snapshots and Legal Evidence

Regulated industries often need to prove what a page said on a given date. Pairing `url` with `finishedAt` gives you a timestamped record, and the stored HTML is the evidence itself. Schedule the Actor to snapshot terms-of-service pages, pricing pages or disclosure documents on a fixed cadence.

#### 🔍 Change Detection and Competitive Monitoring

Hash the `html` body for each URL on every run and compare against the previous run. Any difference flags a page that changed — a competitor's price update, a new job posting, an amended policy. Because the full markup is retained, you can diff the actual HTML to see precisely what moved rather than guessing from a summary field.

#### 🤖 Feeding LLM and RAG Ingestion Pipelines

Retrieval-augmented generation pipelines need clean source documents. Using the HTML downloader as the fetch layer separates concerns cleanly: this Actor guarantees you have the markup, and your own boilerplate-removal and chunking steps turn it into embeddings. The `error` field lets your ingestion job skip and log failures rather than indexing empty documents.

#### 🧰 Regression Testing Your Own Web Properties

Point the Actor at a list of your production URLs after each deployment and compare captured markup against a known-good baseline. Missing structured data, a broken template, an accidentally noindexed page or a hydration failure on a JavaScript route all show up immediately in the stored HTML.

#### 🌍 Archiving Content Before It Disappears

Pages get taken down, rewritten or paywalled. Bulk-downloading HTML gives you a durable local copy of research sources, documentation versions, forum threads or reference material, with the original `url` preserved for citation.

***

### ⚙️ Tips for Better HTML Downloading Results

- **Test with a handful of URLs before scaling.** A five-URL trial run tells you within seconds whether you need `useChrome`, whether the timeout is adequate, and whether the target host is serving you a challenge page instead of real content.
- **Keep `useChrome` off unless you have proven you need it.** Browser rendering is significantly heavier. Verify by searching the raw source for on-screen text before flipping the switch.
- **Raise `handlePageTimeoutSecs` when you enable Chrome.** A page that loads in two seconds over plain HTTP can take far longer to render fully, and the default 60 seconds is not always enough for asset-heavy sites.
- **Batch by domain, not by size.** Splitting a huge list into per-domain runs makes retry tuning meaningful, since a value that suits one slow legacy host is wasteful for a fast CDN-backed site.
- **Always reconcile input count against output count.** Filter the dataset for items with a non-null `error` and feed those URLs back in as a second, more tolerant run with a higher `maxRequestRetries`.
- **Use JSONL for export when markup is large.** HTML strings inflate file size quickly; line-delimited JSON streams cleanly and avoids memory pressure in downstream tooling.

***

### 🛠️ Troubleshooting

**Why is my `html` field empty or just a loading skeleton?**
The page renders its content with JavaScript, so the raw server response contains only a shell. Re-run with `useChrome` set to `true` and increase `handlePageTimeoutSecs` to give the browser room to finish hydrating.

**Why do some items only contain a `url` and an `error`?**
That URL could not be fetched within the configured limits. Common causes are a genuinely dead link, a host that refused the connection, or a page that exceeded `handlePageTimeoutSecs`. Increase the timeout, raise `maxRequestRetries`, and re-submit only the failed URLs.

**The run is very slow. What should I change?**
Check whether `useChrome` is enabled — browser rendering is the usual culprit. If you do not need it, turn it off. Also lower `handlePageTimeoutSecs` so that unresponsive hosts are abandoned quickly instead of consuming the full window on every retry.

**I am getting challenge or consent pages instead of real content.**
Some sites serve interstitials to non-browser clients. Enabling `useChrome` often resolves this because a real browser engine handles cookies and client-side redirects. Proxy rotation is applied automatically, so IP-level blocking is already mitigated where possible.

**Why is my export file enormous?**
Every item carries the complete markup of a page, and `fullHtml` plus `html` means two copies of most of it. Export as JSONL and process it as a stream, or fetch items through the dataset API with `fields` limited to just the columns you need.

***

### ❓ Frequently Asked Questions About HTML Downloading

**What does this HTML downloader Actor actually do?**
It accepts a list of URLs and returns the HTML source of each page as a dataset item, along with a timestamp and, where relevant, an error message. It performs no extraction or parsing of its own.

**How do I download HTML from multiple URLs at once?**
Put every URL into the `requestListSources` array as an object with a `url` key. There is no per-run URL limit imposed by the Actor, so batch size is a matter of your own time and compute budget.

**What is the difference between the `fullHtml` and `html` fields?**
`fullHtml` is the complete document including the doctype and the `<head>` section, which is where meta tags and structured data live. `html` is the body-level markup, which is what you normally parse for visible content.

**Can this HTML downloader handle JavaScript-rendered pages?**
Yes. Set `useChrome` to `true` and pages are rendered with a headless browser (Playwright), so client-side-generated DOM content appears in the captured HTML.

**Should I always enable headless Chrome?**
No. It is slower and more expensive. Use plain HTTP mode by default and switch to Chrome only for sites where the content genuinely does not exist in the raw server response.

**Does the Actor use proxies?**
Yes, requests are routed through rotating proxy infrastructure automatically. There is no proxy configuration field in the input — rotation is handled for you.

**What happens when a URL fails to load?**
The Actor still writes a dataset item for it, containing the `url`, a `finishedAt` timestamp and a populated `error` message. Nothing is silently dropped.

**How many times will a failed URL be retried?**
By default once, controlled by `maxRequestRetries`. Increase it for flaky or rate-limited hosts.

**What is a sensible page timeout?**
The default `handlePageTimeoutSecs` of 60 works well for plain HTTP fetching. For browser rendering of heavy pages, 120 to 180 seconds is more realistic.

**Can I download HTML from pages that require a login?**
No. The Actor fetches publicly accessible pages and does not accept credentials, cookies or session tokens.

**What export formats are available for the downloaded HTML?**
Apify datasets export as JSON, JSONL, CSV, Excel, XML and RSS. For large HTML payloads, JSONL is the most practical because it streams line by line.

**Can I schedule regular HTML snapshots?**
Yes. Use Apify Schedules to run the Actor on a cron expression, which is the standard approach for change detection, compliance archiving and daily site monitoring.

**Can I trigger something automatically when a run finishes?**
Yes. Apify webhooks fire on run completion and can call any HTTP endpoint, or you can wire the Actor into Zapier, Make, Google Sheets or Slack.

**Is the HTML returned exactly as the server sent it?**
In plain HTTP mode you receive the raw server response. With `useChrome` enabled you receive the rendered DOM serialised back to HTML, which reflects post-JavaScript state and will therefore differ from the original response.

**How do I connect the output back to my original list?**
Join on the `url` field, which is preserved verbatim from your input for every item, whether the fetch succeeded or failed.

***

### 🆘 Support & Feedback

Found a bug or hit an edge case with the HTML downloader? Open a ticket on the **Issues** tab of the Actor page — include the URLs involved and the run ID so the problem can be reproduced quickly.

Need custom work? If you want a tailored version of this HTML downloader — different fetch behaviour, bespoke parsing bolted on, integration with an internal system, or a private build for a specific site — get in touch at **scraperhubapi@gmail.com** and describe what you need.

If the Actor saved you time, please leave a review on the Apify Store. Honest feedback helps other developers find the tool and directly shapes what gets improved next.

***

### ⚖️ Disclaimer

This HTML downloader retrieves publicly accessible web pages only. It does not bypass authentication, paywalls or access controls, and it does not attempt to reach content that is not served to an ordinary visitor.

You are responsible for how you use the data you collect. Downloading HTML at scale should be done in a way that respects the target site's `robots.txt`, its terms of service and any applicable rate limits. Review the platform terms of any website you intend to crawl before running large batches.

Captured HTML may incidentally contain personal data — names, contact details, user-generated comments. Where that is the case, processing it brings obligations under the GDPR, the CCPA and comparable privacy regimes. Establish a lawful basis, retain only what you need, secure it appropriately and delete it when it is no longer required. Do not use downloaded markup to build profiles of private individuals or for unsolicited contact.

If you believe content collected by this Actor should be removed, or you have a data-protection concern relating to a dataset produced with it, write to **scraperhubapi@gmail.com** and the request will be handled promptly.

# Actor input Schema

## `requestListSources` (type: `array`):

List of URLs to fetch. Each item is an object with a 'url' field (matches Apify RequestList source format).

## `useChrome` (type: `boolean`):

If enabled, pages are rendered with a headless browser (Playwright) so the returned HTML reflects JavaScript-rendered content. If disabled, a plain HTTP client is used (faster, cheaper, but only returns the raw server response).

## `maxRequestRetries` (type: `integer`):

How many times to retry a failed request before giving up on it.

## `handlePageTimeoutSecs` (type: `integer`):

Maximum time allowed to load and process a single page before it is considered failed.

## Actor input object example

```json
{
  "requestListSources": [
    {
      "url": "https://apify.com"
    }
  ],
  "useChrome": false,
  "maxRequestRetries": 1,
  "handlePageTimeoutSecs": 60
}
```

# Actor output Schema

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

Records scraped by Download HTML from URLs, stored in the run's default dataset.

# 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 = {
    "requestListSources": [
        {
            "url": "https://apify.com"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapers-hub/download-html-from-urls").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 = { "requestListSources": [{ "url": "https://apify.com" }] }

# Run the Actor and wait for it to finish
run = client.actor("scrapers-hub/download-html-from-urls").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 '{
  "requestListSources": [
    {
      "url": "https://apify.com"
    }
  ]
}' |
apify call scrapers-hub/download-html-from-urls --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapers-hub/download-html-from-urls"
        }
    }
}

```

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/sGdsj1wXhnnraZzsD/builds/Ndtk0YbTcySIKKjKc/openapi.json
