# URL to Word Document Converter (`automation-lab/web-pages-to-docx`) Actor

Convert batches of public web pages into clean editable DOCX files with headings, emphasis, links, provenance, and per-page status.

- **URL**: https://apify.com/automation-lab/web-pages-to-docx.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.92 / 1,000 page extracteds

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

## URL to Word Document Converter

Turn batches of anonymously public web pages into clean, editable Microsoft Word (`.docx`) files. This **URL to Word document** workflow keeps useful headings, paragraphs, lists, bold and italic emphasis, underlining, and clickable links while removing common navigation, scripts, forms, and page chrome.

Each processed URL also produces a typed status record with its source, final and canonical URLs, title, word count, conversion status, DOCX key, and download link. Choose separate files for filing individual pages or one combined document for research packets and handoffs.

### What does URL to Word Document Converter do?

The Actor:

1. validates that every supplied URL points to the public internet;
2. downloads public HTML with bounded redirects, timeouts, and transient retries;
3. extracts either a CSS-selected section or the page's readable main content;
4. maps common web formatting into native Word document elements;
5. adds the canonical source URL and conversion timestamp to each page;
6. stores editable DOCX files in the run's key-value store; and
7. writes one success or error record per processed page to the default dataset.

Failed pages remain visible in the dataset and are not charged as converted pages.

### Who is it for?

- **Researchers** assembling editable source packets from public references.
- **Content operations teams** moving approved website copy into Word-based editorial workflows.
- **Knowledge managers** archiving public articles in an office-friendly format.
- **Consultants and analysts** preparing sourced reading packs for clients.
- **Developers** automating URL-to-DOCX conversion through the Apify API, schedules, webhooks, or MCP.

Use [HTML Readability to Markdown Converter](https://apify.com/automation-lab/html-readability-markdown-converter) when Markdown is the desired final format. Use this Actor when the deliverable must be an editable Word file.

### Why use this Actor?

Copying web content manually often introduces broken line breaks, missing links, inconsistent headings, and unclear provenance. This Actor provides a repeatable conversion contract:

- batch input of up to 100 public URLs;
- optional body selection with a CSS selector;
- separate or combined DOCX output;
- native headings and basic inline formatting;
- source attribution inside every document;
- deterministic, collision-resistant filenames;
- explicit page-level failures instead of silently empty files;
- no browser or proxy cost for ordinary server-rendered pages.

### Supported formatting

| Web content | DOCX result |
| --- | --- |
| `h1` through `h6` | Native Word heading levels |
| Paragraphs | Editable Word paragraphs |
| Bold and strong text | Bold text runs |
| Italic and emphasized text | Italic text runs |
| Underlined text | Underlined text runs |
| Links | Clickable external hyperlinks |
| Ordered and unordered lists | Indented list paragraphs |
| Block quotes | Indented paragraphs |
| Line breaks | Word line breaks |
| Page provenance | Source link and conversion timestamp |

Complex page layouts, embedded media, interactive widgets, CSS visual styling, comments, and scripts are intentionally not reproduced.

### Input parameters

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `startUrls` | array | required | One to 100 anonymously public HTTP(S) page URLs. |
| `outputMode` | string | `separate` | `separate` creates one DOCX per success; `combined` creates one file with page breaks. |
| `documentTitle` | string | — | Filename label for combined output. |
| `contentSelector` | string | — | Global CSS selector such as `main`, `article`, or `.entry-content`. |
| `maxItems` | integer | `10` | Maximum number of unique supplied URLs to process, up to 100. |
| `maxConcurrency` | integer | `4` | Parallel page downloads, from 1 to 10. |
| `requestTimeoutSecs` | integer | `30` | Timeout for each HTTP request, from 5 to 120 seconds. |
| `maxRequestRetries` | integer | `2` | Retries for transient failures, from 0 to 4. |
| `maxContentBytes` | integer | `4000000` | Per-page HTML safety limit, up to 5 MB. |

A request-list entry may set `userData.contentSelector` to override the global selector for that URL:

```json
{
  "startUrls": [
    {
      "url": "https://developer.mozilla.org/en-US/docs/Web/HTML",
      "userData": { "contentSelector": "main" }
    }
  ],
  "outputMode": "separate",
  "maxItems": 1
}
```

### Quick start: convert one URL to DOCX

1. Open the Actor in Apify Console.
2. Add a public page under **Public web page URLs**.
3. Keep **Separate file per page** selected.
4. Click **Start**.
5. Open the run's **Output** tab to inspect page status.
6. Use **Download DOCX** or open the run key-value store.

Example input:

```json
{
  "startUrls": [{ "url": "https://www.python.org/about/" }],
  "outputMode": "separate",
  "maxItems": 1
}
```

### Combine several pages into one Word file

Combined mode is useful for research packs, editorial handoffs, and source collections:

```json
{
  "startUrls": [
    { "url": "https://www.python.org/about/" },
    { "url": "https://developer.mozilla.org/en-US/docs/Web/HTML" },
    { "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP" }
  ],
  "outputMode": "combined",
  "documentTitle": "Web standards research",
  "maxItems": 3,
  "maxConcurrency": 3
}
```

Successful pages are placed in input order and separated by page breaks. Every successful dataset row points to the same combined DOCX. Failed URLs still receive their own error rows and are omitted from the file.

### Select only the body text you need

Without a selector, Mozilla Readability identifies the likely article or main body and removes common surrounding page elements. For pages with known structure, set `contentSelector`:

```json
{
  "startUrls": [{ "url": "https://developer.mozilla.org/en-US/docs/Web/HTML" }],
  "contentSelector": "main",
  "outputMode": "separate"
}
```

If the selector is invalid or matches nothing, that page gets an explicit error record. The Actor does not silently fall back to unrelated page content after an explicit selector fails.

### Output dataset

The default dataset contains one row per processed URL:

| Field | Meaning |
| --- | --- |
| `requestedUrl` | Normalized URL supplied by the user. |
| `finalUrl` | URL after validated redirects. |
| `canonicalUrl` | Canonical source saved in the DOCX. |
| `status` | `success` or `error`. |
| `statusCode` | Successful HTTP response status. |
| `title` | Extracted page or article title. |
| `contentSelector` | Selector used for this page, if any. |
| `wordCount` | Words in cleaned content. |
| `documentKey` | Generated key-value-store key. |
| `documentUrl` | API download URL for the DOCX. |
| `outputMode` | `separate` or `combined`. |
| `error` | Actionable failure message, or `null`. |
| `convertedAt` | ISO 8601 conversion timestamp. |

Representative success record:

```json
{
  "requestedUrl": "https://www.python.org/about/",
  "finalUrl": "https://www.python.org/about/",
  "canonicalUrl": "https://www.python.org/about/",
  "status": "success",
  "statusCode": 200,
  "title": "About Python™ | Python.org",
  "contentSelector": null,
  "wordCount": 640,
  "documentKey": "DOCX-about-python-python-org-a1b2c3d4e5.docx",
  "documentUrl": "https://api.apify.com/v2/key-value-stores/sampleStore/records/DOCX-about-python-python-org-a1b2c3d4e5.docx?download=1",
  "outputMode": "separate",
  "error": null,
  "convertedAt": "2026-01-15T12:00:00.000Z"
}
```

The URL and key above illustrate the output shape; each run receives its own storage ID and deterministic URL hash.

### DOCX file storage

Generated files are stored under keys beginning with `DOCX-` in the run's default key-value store. The MIME type is the standard Office Open XML Word type:

```text
application/vnd.openxmlformats-officedocument.wordprocessingml.document
```

Key-value-store retention follows your Apify account and storage settings. Download or copy files to permanent storage when your workflow requires longer retention.

### How much does it cost to convert web pages to Word documents?

Pricing uses one small run-start fee plus one `page` event for each successfully stored page conversion. Error rows are not charged as pages. The exact active prices for your plan are shown in Apify Console before the run.

At the initial BRONZE rate, the run-start fee is **$0.005** and each successful page is **$0.001536**. Typical totals are:

- 1 converted page: **$0.006536**;
- 10 converted pages: **$0.02036**;
- 100 converted pages: **$0.15860**.

Combined mode is still charged per successfully converted source page because each page requires fetching, cleaning, formatting, status reporting, and provenance. Creating one combined file does not hide failed URLs or change the value unit.

### Reliability and retry behavior

The Actor retries only temporary failures such as request timeouts, network resets, HTTP 408/425/429, and server 5xx responses. Backoff is bounded. It does not repeatedly retry deterministic 4xx responses, malformed inputs, invalid selectors, non-HTML content, or recognized challenge pages.

Redirect destinations are revalidated before fetching. DNS results are pinned during each request to reduce server-side request forgery and DNS-rebinding risk. Localhost, private networks, credentials in URLs, and non-HTTP protocols are rejected.

### Limits

- Maximum 100 unique URLs per run.
- Maximum 5 MB of HTML per page.
- Public HTTP and HTTPS pages only.
- Server-rendered HTML only; no JavaScript browser rendering.
- No login, cookies, paywall bypass, CAPTCHA solving, or private pages.
- Images, video, embedded files, scripts, forms, and advanced CSS layout are not copied.
- Tables may be represented as readable text rather than pixel-identical Word tables.
- Word output preserves content structure and basic semantics, not exact page appearance.

A JavaScript-only site may return too little content and fail with a readable-content error. Use a public server-rendered URL or another authorized export route.

### Failure behavior

One bad URL does not discard successful conversions from the same batch. Each failed page gets `status: "error"`, no DOCX link, and a concise reason. The run fails only when every selected URL fails or the run-level input is invalid.

Common errors include:

- `Page returned HTTP 404.` — check the source URL.
- `contentSelector did not match any element` — inspect the current page HTML and update the selector.
- `Expected HTML` — the URL points to a PDF, image, download, or another unsupported type.
- `authentication or anti-bot challenge` — the page is not anonymously retrievable over this direct HTTP route.
- `No substantial readable content` — select a better content container or use a server-rendered page.

### Scheduling and automation

Use Apify schedules to regenerate approved public-page document packs. For change tracking, retain previous files and compare them in your own downstream storage; this Actor performs conversion and does not claim to detect or alert on changes itself.

Useful integrations include:

- send successful `documentUrl` values to a webhook;
- copy DOCX files to cloud storage;
- add status records to an audit table;
- notify an operator only for error rows;
- feed editable files into a reviewed editorial process.

### API usage with cURL

Replace `YOUR_TOKEN` with an Apify API token:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~web-pages-to-docx/runs?token=YOUR_TOKEN&waitForFinish=300" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://www.python.org/about/"}],
    "outputMode": "separate",
    "maxItems": 1
  }'
```

Read status rows from the run's default dataset and download files through each successful row's `documentUrl`.

### API usage with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/web-pages-to-docx').call({
  startUrls: [{ url: 'https://www.python.org/about/' }],
  outputMode: 'separate',
  maxItems: 1,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].status, items[0].documentUrl);
```

### API usage with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/web-pages-to-docx').call(run_input={
    'startUrls': [{'url': 'https://www.python.org/about/'}],
    'outputMode': 'separate',
    'maxItems': 1,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items[0]['status'], items[0]['documentUrl'])
```

### Use with Apify MCP

#### Claude Code setup

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/web-pages-to-docx"
```

#### Claude Desktop setup

Claude Desktop can use this HTTP MCP server configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/web-pages-to-docx"
    }
  }
}
```

#### Cursor setup

In Cursor, add the same `apify` server URL under **Settings → Tools & MCP → New MCP Server**.

#### VS Code setup

In VS Code, add the same HTTP URL to your MCP server configuration and enable the server for the workspace.

Example prompts:

- “Convert this public article to a separate editable Word file and return the download URL.”
- “Combine these three public documentation pages into one DOCX research packet.”
- “Extract only the `main` section from this page and show the conversion status.”

### Legality and responsible use

Convert only content you are authorized to access and reuse. Public availability does not automatically grant permission to republish copyrighted material. Follow website terms, robots guidance where applicable, licenses, attribution requirements, privacy rules, and applicable law.

Do not use the Actor to bypass authentication, paywalls, technical access controls, or anti-bot challenges. Review generated documents before external distribution, especially when the source contains personal data, regulated content, or third-party intellectual property.

### Troubleshooting

#### Why is my DOCX missing navigation or sidebars?

That is expected. Readability extraction and cleanup intentionally focus on main content. Set a specific `contentSelector` if a page section outside the detected article is legitimately required.

#### Why did one URL fail while the run succeeded?

Batch runs preserve page-level status. Successful pages remain useful while failed pages receive error records. Correct the failed URL or selector and rerun only that page.

#### Why is a JavaScript-heavy page empty?

Version 1 uses direct HTTP and does not execute client-side JavaScript. Supply a server-rendered public page or an authorized alternate public URL.

#### Why do several rows share one download URL?

In `combined` mode every successful source page belongs to the same DOCX file, so their status rows intentionally share its key and URL.

#### Can I convert PDFs or existing Word files?

No. This Actor accepts HTML web pages and produces DOCX. Use a document-specific converter or extractor for PDF, DOCX, spreadsheet, or presentation inputs.

### Related Automation Lab Actors

- [HTML Readability to Markdown Converter](https://apify.com/automation-lab/html-readability-markdown-converter) — one public page or raw HTML to clean Markdown.
- [Website to Obsidian Markdown](https://apify.com/automation-lab/website-to-obsidian-markdown) — batch pages to Obsidian-ready notes with frontmatter and tags.
- [Website Content Crawler](https://apify.com/automation-lab/website-content-crawler) — bounded same-site crawling with text, Markdown, metadata, and links.

### FAQ

#### Does the Actor create real editable Word files?

Yes. It creates Office Open XML `.docx` files containing native paragraphs, headings, text runs, lists, and hyperlinks.

#### Is each error charged?

No. The per-page event is emitted only after useful content is converted and the DOCX output is stored. The one-time run-start event still applies.

#### Can each URL use a different selector?

Yes. Put `contentSelector` inside that request-list entry's `userData`. It overrides the global selector for that URL.

#### Does combined mode preserve input order?

Yes. Successful pages are assembled in the normalized input order, even though downloads may run concurrently.

#### Are duplicate URLs converted twice?

No. Exact normalized duplicate URLs are processed once.

#### Can I raise concurrency?

Yes, up to 10. Lower concurrency is friendlier to rate-limited websites and often more reliable. Increasing it does not add browser support or bypass source restrictions.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/web-pages-to-docx/changelog.md

# Actor input Schema

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

Pages to convert. Add userData.contentSelector to an individual URL to override the global selector for that page.

## `outputMode` (type: `string`):

Create one DOCX per successful page, or combine all successful pages into one DOCX with page breaks.

## `documentTitle` (type: `string`):

Optional title used in the combined DOCX filename. Applies only to combined mode.

## `contentSelector` (type: `string`):

Optional CSS selector such as main or article. When omitted, readability extraction removes navigation, ads, and other page chrome.

## `maxItems` (type: `integer`):

Maximum number of unique supplied pages to process.

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

Number of page downloads processed at once. Lower this for rate-limited websites.

## `requestTimeoutSecs` (type: `integer`):

Maximum time to wait for each HTTP request.

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

Retries for temporary network, rate-limit, and server failures. Permanent errors are not retried.

## `maxContentBytes` (type: `integer`):

Download safety limit for each HTML page.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.python.org/about/"
    }
  ],
  "outputMode": "separate",
  "maxItems": 10,
  "maxConcurrency": 4,
  "requestTimeoutSecs": 30,
  "maxRequestRetries": 2,
  "maxContentBytes": 4000000
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing one success or error record per processed page.

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

Key-value store containing the generated Word documents.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.python.org/about/"
        }
    ],
    "outputMode": "separate",
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/web-pages-to-docx").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 = {
    "startUrls": [{ "url": "https://www.python.org/about/" }],
    "outputMode": "separate",
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/web-pages-to-docx").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 '{
  "startUrls": [
    {
      "url": "https://www.python.org/about/"
    }
  ],
  "outputMode": "separate",
  "maxItems": 10
}' |
apify call automation-lab/web-pages-to-docx --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/web-pages-to-docx"
        }
    }
}
```

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/5oAw9m4wqSLdniVOm/builds/PGdlumzuhyGECbImp/openapi.json
