# Doc-to-Markdown/JSON RAG Prep - Convert PDF & DOCX for RAG (`bigjoecoding/doc-to-markdown-json-rag-prep`) Actor

Convert PDF, DOCX, PPTX and webpages to clean Markdown and RAG-ready JSON chunks for your embedding pipeline. No LLM cost. $0.03 per document.

- **URL**: https://apify.com/bigjoecoding/doc-to-markdown-json-rag-prep.md
- **Developed by:** [Joseph Curry](https://apify.com/bigjoecoding) (community)
- **Categories:** Automation, AI
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $30.00 / 1,000 document converteds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

### What does Doc-to-Markdown/JSON RAG Prep do?

**Doc-to-Markdown/JSON RAG Prep** is a document-to-Markdown converter that turns any URL, a webpage or a direct link to a document file (PDF, DOCX, PPTX, XLSX, CSV, HTML, and more), into clean **Markdown** plus a structured, **RAG-ready JSON** chunk breakdown, ready to feed straight into an embedding pipeline or vector database. Try it free on Apify: batch processing, scheduling, API access, and run monitoring are included at no extra cost.

### Why use this PDF-to-Markdown RAG prep tool?

If you're building a RAG (Retrieval-Augmented Generation) pipeline, AI agent knowledge base, or semantic search index, the boring-but-critical first step is turning messy source documents into clean text your embedding model can actually use. Most "AI document cleaning" tools do this with an LLM call per page, which means paying model inference cost on every single document, every time you re-run your pipeline. **This Actor never calls an LLM.** It uses [markitdown](https://github.com/microsoft/markitdown), Microsoft's free, open-source (MIT-licensed), deterministic conversion library, so the same input always produces the same output. Your only cost is Apify's platform pass-through plus this Actor's flat per-document fee, with no monthly rental and no per-token model bill.

#### Who this is for

- **RAG and AI agent developers** who need a fast, cheap, deterministic PDF-to-Markdown and DOCX-to-Markdown step before chunking and embedding.
- **Data engineers** building a document ingestion pipeline for a vector database (Pinecone, Weaviate, pgvector, or similar) who want batch conversion with structured output.
- **No-code and low-code builders** who want to convert a folder of PDFs, spreadsheets, or slide decks to Markdown without writing a parser.
- **Anyone migrating legacy content** (old PDFs, Word docs, PowerPoint decks) into a clean Markdown knowledge base or documentation site.

### How to use Doc-to-Markdown/JSON RAG Prep

1. Open the Input tab and add one or more **URLs**, webpages or direct document links.
2. (Optional) Adjust **Max characters per RAG chunk** to match your embedding model's ideal chunk size (default 1500).
3. Click **Start**. Each URL is converted independently; one bad URL in a batch never stops the others.
4. Results appear in the Dataset tab: clean Markdown, a title (if found), and a heading-aware chunk breakdown for each successfully converted URL.

### Input

- **URLs** (required): an array of URLs to convert. Max 25 per run.
- **Max characters per RAG chunk** (default 1500, minimum 200): chunk size ceiling; a single long paragraph is kept whole rather than cut mid-sentence.

### Output

Each URL is a dataset item:

```json
{
  "sourceUrl": "https://example.com/report.pdf",
  "success": true,
  "error": null,
  "title": "Annual Report 2026",
  "markdown": "# Annual Report 2026\n\n...",
  "charCount": 38061,
  "chunkCount": 36,
  "chunks": [
    {
      "chunkIndex": 0,
      "headingPath": "Annual Report 2026 > Executive Summary",
      "text": "...",
      "charCount": 842
    }
  ]
}
````

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. Failed URLs are included in the same dataset with `success: false` and a plain-English `error` field, never a raw stack trace.

#### Data table

| Field | Description |
|---|---|
| `sourceUrl` | The URL that was converted |
| `success` | `true`/`false` |
| `error` | Plain-English reason for failure, or `null` |
| `title` | Extracted document title, if available |
| `markdown` | Full converted Markdown |
| `charCount` | Character count of the Markdown |
| `chunkCount` | Number of RAG chunks produced |
| `chunks` | Array of `{chunkIndex, headingPath, text, charCount}` |

### Why not use an LLM to clean this up?

Because it would break the entire point of this Actor. An LLM pass adds real per-page cost, non-determinism (the same document can convert differently run to run), and latency. This Actor is built on [markitdown](https://github.com/microsoft/markitdown), a rules-based, deterministic tool, not a model. Chunking (splitting Markdown into RAG-ready pieces) is likewise mechanical: it splits on heading and paragraph boundaries, not "semantic meaning," so it never requires a model call either.

### How much does document-to-Markdown conversion cost?

This Actor uses **Pay-Per-Event pricing**, with no monthly rental fee:

| Event | Price | When it's charged |
|---|---|---|
| Document converted | $0.03 | Once per URL that successfully converts. **Failed conversions are never charged.** |

Converting 10 documents costs roughly **$0.30**. Apify's own small platform-usage charge for the first 5 seconds of every run is subsidized by Apify by default.

### Tips for better conversion quality

- If a webpage returns messy Markdown (ads, navigation menus, etc.), try a more direct source URL, such as a PDF or DOCX version of the same content; structured document formats convert more cleanly than heavily-styled webpages.
- Tune **Max characters per RAG chunk** to your embedding model: smaller chunks (500 to 800 characters) work well for precise retrieval, larger chunks (1500 to 2500) preserve more context per chunk.
- Batch related URLs into a single run, up to 25 at once, rather than running this Actor once per URL.

### FAQ, disclaimers, and support

**Does this actually avoid LLM costs entirely?**
Yes. There is no LLM call anywhere in this Actor's conversion or chunking path. You can verify this yourself: the source code is a small, readable Python module with no API calls to any model provider.

**Will every URL convert successfully?**
No, and this Actor is upfront about that. Some sites (for example, sites that block automated requests, return a 403, or require a login) will fail; failed URLs are reported honestly with a plain-English reason and are **never charged**. Complex scanned or image-heavy PDFs, or heavily-styled documents, may also convert with lower fidelity than clean text-based sources.

**Is the chunking "smart" (semantic)?**
No, by design; it's mechanical, splitting on Markdown headings and paragraph boundaries. This keeps it deterministic and free. If you need semantic chunking, you'd add that as a separate step in your own pipeline (which may involve a model call on your end, a decision left to you).

**What formats are supported?**
Whatever the underlying markitdown library supports: HTML, PDF, DOCX, PPTX, XLSX, CSV, and several others. If a format isn't supported, the URL fails with a clear error rather than producing garbage output.

**How is this different from other document-to-Markdown Actors on Apify Store?**
Most comparable tools either charge a monthly rental fee on top of usage, or rely on an LLM/OCR model for conversion, which adds cost and non-determinism. This Actor is pure pay-per-event with no rental fee, and its deterministic conversion means the same document produces the same Markdown every time you run it.

Questions or issues? Use the Actor's Issues tab on Apify Store.

# Actor input Schema

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

One or more URLs to convert to clean Markdown + RAG-ready JSON. Each can be a webpage or a direct link to a document file (PDF, DOCX, PPTX, XLSX, CSV, HTML, and more). Max 25 per run.

## `maxChunkChars` (type: `integer`):

Each document's Markdown is split into RAG-ready chunks along heading and paragraph boundaries, each no larger than this many characters (a single long paragraph is kept whole rather than cut mid-sentence). Tune this to match your embedding model's ideal chunk size.

## Actor input object example

```json
{
  "urls": [
    "https://example.com"
  ],
  "maxChunkChars": 1500
}
```

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bigjoecoding/doc-to-markdown-json-rag-prep").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"] }

# Run the Actor and wait for it to finish
run = client.actor("bigjoecoding/doc-to-markdown-json-rag-prep").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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"
  ]
}' |
apify call bigjoecoding/doc-to-markdown-json-rag-prep --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=bigjoecoding/doc-to-markdown-json-rag-prep",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Doc-to-Markdown/JSON RAG Prep - Convert PDF & DOCX for RAG",
        "description": "Convert PDF, DOCX, PPTX and webpages to clean Markdown and RAG-ready JSON chunks for your embedding pipeline. No LLM cost. $0.03 per document.",
        "version": "0.1",
        "x-build-id": "TXNUe1Y0EOi7VkQjn"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/bigjoecoding~doc-to-markdown-json-rag-prep/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-bigjoecoding-doc-to-markdown-json-rag-prep",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/bigjoecoding~doc-to-markdown-json-rag-prep/runs": {
            "post": {
                "operationId": "runs-sync-bigjoecoding-doc-to-markdown-json-rag-prep",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/bigjoecoding~doc-to-markdown-json-rag-prep/run-sync": {
            "post": {
                "operationId": "run-sync-bigjoecoding-doc-to-markdown-json-rag-prep",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "urls"
                ],
                "properties": {
                    "urls": {
                        "title": "URLs to convert",
                        "type": "array",
                        "description": "One or more URLs to convert to clean Markdown + RAG-ready JSON. Each can be a webpage or a direct link to a document file (PDF, DOCX, PPTX, XLSX, CSV, HTML, and more). Max 25 per run.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxChunkChars": {
                        "title": "Max characters per RAG chunk",
                        "minimum": 200,
                        "type": "integer",
                        "description": "Each document's Markdown is split into RAG-ready chunks along heading and paragraph boundaries, each no larger than this many characters (a single long paragraph is kept whole rather than cut mid-sentence). Tune this to match your embedding model's ideal chunk size.",
                        "default": 1500
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
