# PDF Text Extractor – PDF, DOCX & PPTX to Markdown (`openfeeds/pdf-to-text-markdown-extractor`) Actor

Turn PDF, Word (DOCX) and PowerPoint (PPTX) files into clean text and Markdown. Give URLs or uploads and get one row per document, page or RAG-ready chunk, with metadata and a status per file.

- **URL**: https://apify.com/openfeeds/pdf-to-text-markdown-extractor.md
- **Developed by:** [OpenFeeds](https://apify.com/openfeeds) (community)
- **Categories:** AI, Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 document 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

### What does PDF Text Extractor do?

**PDF Text Extractor** turns **PDF files into clean text and Markdown** in bulk, and also handles **Word (DOCX)** and **PowerPoint (PPTX)**. Give it document URLs or upload files, and it returns **one row per file, one row per page or slide, or one row per RAG chunk**, with whitelisted metadata and a status for every file.

Use it as a **PDF parser API**, for **PDF to Markdown for RAG**, for Word to Markdown, or for PowerPoint to text. Everything runs on the Apify platform with pure-JavaScript parsers (pdf.js, mammoth and our own PowerPoint reader): no browser and no AI calls.

What it does **not** do: no OCR (scanned pages are detected and flagged, not read), no PDF table structure (tables inside PDFs come out as text lines), and no Excel, EPUB, HTML pages or old `.doc`/`.ppt` files.

### Why use PDF Text Extractor?

- **Flat, CSV-friendly rows.** Every row has the same columns, so the dataset opens cleanly in Excel, Google Sheets or a database.
- **Stable IDs for citations.** `docId` plus `pageNumber` or `chunkIndex` identify every piece of text, run after run.
- **A status for every file, and failures are free.** Broken links, web pages, scans and password-protected files each get an explicit status and are never charged.
- **Cleaner PDF text.** Repeated headers, footers and page numbers are removed and two-column pages are read in order. In `markdown`, lines are reflowed into paragraphs, hyphenated words are joined, headings are detected by font size and bullet lists become Markdown lists. The plain `text` field keeps the PDF's visual lines (and any line-end hyphens), with a blank line between paragraphs.
- **Real Markdown tables for Word and PowerPoint**, plus footnotes, image alt text and PowerPoint speaker notes.
- **RAG-ready chunks** with size, overlap, page or slide span and the heading path. Table rows are never split, and a table that continues in the next chunk (or in its overlap) repeats its header row.
- **Metadata without personal fields.** Title, language, dates and the creating application are returned; author, last-modified-by, company and comment authors are never output.
- **Publisher opt-outs respected.** The Actor checks TDMRep reservations and robots.txt before it downloads a file, and again for every redirect target (a short link or download redirector cannot get around a reservation).
- **Control over cost.** Page and slide selection, a per-file page cap and a file-size limit.
- **Apify platform benefits:** run it from the API, on a schedule, or from Make, Zapier, n8n and other integrations; feed the dataset to LangChain or LlamaIndex loaders; or call it as a tool through the Apify MCP server.

### Supported formats

| Format     | Accepted variants                           | Rows in `pages` mode | What is extracted                                                                                                                                                                                                                                               |
| ---------- | ------------------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| PDF        | `.pdf`                                      | one per page         | Text layer as text and Markdown: headings by font size, lists, reflowed paragraphs, de-hyphenation, header/footer removal, two-column order. Metadata, scanned-page and garbled-text flags. Copy restrictions are respected. PDF tables come out as text lines. |
| Word       | `.docx`, `.docm`, `.dotx`, `.dotm`          | one per file         | Headings from Word styles, lists, real Markdown tables, footnotes and endnotes, image alt text. Comments, revision authors, headers and footers are not output.                                                                                                 |
| PowerPoint | `.pptx`, `.pptm`, `.ppsx`, `.ppsm`, `.potx` | one per slide        | Slides in presentation order with titles, bullets with levels, real Markdown tables, image alt text and speaker notes (optional). Hidden slides are skipped.                                                                                                    |

Formats are detected from the file's bytes, not from the URL or the server's Content-Type. Password-protected Word and PowerPoint files are not supported; save an unprotected copy.

### What data can PDF Text Extractor extract?

| Field                                          | Description                                               |
| ---------------------------------------------- | --------------------------------------------------------- |
| `rowType`                                      | `document`, `page` or `chunk`                             |
| `sourceUrl`                                    | The URL you supplied                                      |
| `fileType`                                     | `pdf`, `docx` or `pptx`                                   |
| `status`                                       | `ok` or the reason the file was skipped (see below)       |
| `title`                                        | From the file's metadata, or detected from the first page |
| `text`                                         | Plain text in reading order                               |
| `markdown`                                     | Markdown with headings, lists and tables                  |
| `pageNumber` / `pageLabel`                     | Page or slide number, printed page label or slide title   |
| `chunkIndex` / `headingPath`                   | Chunk number and the section headings in force            |
| `pageCount` / `pagesExtracted`                 | Total and processed pages or slides                       |
| `language` / `createdAt` / `modifiedAt`        | Declared language and dates from the metadata             |
| `isScanned` / `textCoverage`                   | Scan detection for PDFs                                   |
| `tableCount`                                   | Markdown tables found in Word and PowerPoint files        |
| `charCount` / `wordCount` / `approxTokenCount` | Size of each row's text                                   |
| `contentSha256`                                | Hash of the file, for change detection                    |
| `chargedEvents`                                | How many billing events the file used (0 when free)       |

**Statuses:** `ok`, `no_text` (scanned, blank or garbled), `unsupported_format` (web page, Excel, EPUB, legacy Office, image), `http_error`, `blocked` (HTTP 401, 403, 407, 451, a 429 that persists, or an empty HTTP 202 answer such as a bot check), `too_large`, `timeout`, `parse_error`, `password_required`, `encrypted_file`, `copy_restricted`, `tdm_reserved`, `robots_disallowed`, `unsupported_host`, `invalid_url` and `charge_limit_reached`. Only `ok` files are charged.

### How to extract text from PDF, Word and PowerPoint files

1. Paste direct file links into **Document URLs** (one per line), or add files with **Upload files**.
2. Choose **Output rows**: one row per file, one row per page or slide, or one row per chunk for RAG.
3. Optionally limit pages with **Pages or slides to extract**, for example `1-5, 8, 10-`.
4. Click **Start**. The prefilled example (a one-page test PDF plus a sample Word memo and a sample PowerPoint deck) finishes in a few seconds.
5. Download the results as JSON, CSV, Excel or HTML, or read them through the API.

### How much does it cost to extract text from PDFs?

You pay per file that yields text, plus a small start fee per run (pay-per-event pricing, cheaper on higher Apify plans):

| Event                                                                      | Free    | Bronze  | Silver  | Gold    | Platinum | Diamond |
| -------------------------------------------------------------------------- | ------- | ------- | ------- | ------- | -------- | ------- |
| Document extracted (per file)                                              | $0.0025 | $0.0022 | $0.0018 | $0.0014 | $0.0014  | $0.0014 |
| Actor start (per run; once per GB of memory, the default 1 GB counts once) | $0.002  | $0.002  | $0.0015 | $0.001  | $0.001   | $0.001  |

That is **$2.50 per 1,000 files** on the free tier, down to $1.40 per 1,000 on Gold and higher plans. The start fee is charged once per GB of run memory: the default 1 GB run pays it once, and a run with 4 GB of memory pays 4 start events ($0.008 on the free tier).

- One PDF in one run at the default 1 GB memory: $0.002 + $0.0025 = **$0.0045**.
- 100 files in one run: about **$0.25**.
- 1,000 files in one run: about **$2.50**.

**Large files** count once per started 100 pages or slides, plus once per full 10 MB of file size. A Word file always counts as one unit of pages. Most files are one event:

| File                                       | Events                     | Free-tier price |
| ------------------------------------------ | -------------------------- | --------------- |
| PDF, 12 pages, 0.3 MB                      | 1                          | $0.0025         |
| PDF, 250 pages, 4 MB                       | 3                          | $0.0075         |
| PDF, 30 pages, 12 MB                       | 2                          | $0.005          |
| `pageRange: "1-5"` on a 900-page PDF       | 1 (only 5 pages extracted) | $0.0025         |
| Word file, 40 pages of text, 2 MB          | 1                          | $0.0025         |
| PowerPoint deck, 60 slides, 35 MB (images) | 4                          | $0.01           |

**Failed, blocked, unsupported, scanned (no text) and skipped files are free.** The Apify free plan's $5 monthly credit covers about 2,000 normal files in one run. You can cap spending per run with the maximum charge setting. A large file that needs more events than are left is skipped with status `charge_limit_reached`, and smaller files after it are still processed; once the budget is used up, the Actor stops cleanly and lists the files it did not start as `charge_limit_reached` in the SUMMARY record (they get no dataset row).

### Input

See the **Input** tab for every option. The most important ones:

- **Output rows** (`outputMode`): `documents` gives one row per file, `pages` one row per PDF page or PowerPoint slide (a Word file gives one row), `chunks` one row per text chunk.
- **Pages or slides to extract** (`pageRange`): numbers and ranges such as `1-5, 8, 10-`. Applies to PDF and PowerPoint files; Word files are processed as one unit.
- **Chunk size** and **Chunk overlap** (`chunkSize`, `chunkOverlap`): target length in characters (about 4 characters per token) and the characters repeated from the previous chunk. The overlap must be less than half the chunk size.
- **Include PowerPoint speaker notes** (`includeSpeakerNotes`): adds a "Speaker notes" block under each slide.
- **Respect publisher opt-outs** (`respectOptOuts`): skips files whose publisher reserved text and data mining (TDMRep) or that robots.txt disallows. Turn it off only for files you own or are licensed to process.
- **Custom User-Agent** (`userAgent`): some publishers ask you to identify yourself with your organisation and a contact address.

Example input (the prefill):

```json
{
    "urls": [
        "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
        "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-memo.docx",
        "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-deck.pptx"
    ],
    "outputMode": "documents"
}
```

### Output

You can download the dataset in various formats such as JSON, HTML, CSV or Excel. The dataset has five views: **Overview**, **Documents**, **Pages and slides**, **Chunks** and **Status and problems** (sort or filter by `status` to find skipped files).

A PDF document row for a 51-page statute (abridged):

```json
{
    "rowType": "document",
    "inputIndex": 0,
    "docId": "2c969fa851870f34",
    "sourceUrl": "https://www.gesetze-im-internet.de/gg/GG.pdf",
    "fileName": "GG.pdf",
    "fileType": "pdf",
    "status": "ok",
    "httpStatus": 200,
    "fileSizeBytes": 271974,
    "contentSha256": "bf6bda4ee99a3f3d260455cadb7941eaaee9dae4518e37f98de4887f18f1ebe2",
    "title": "Grundgesetz für die Bundesrepublik Deutschland",
    "titleSource": "heading",
    "language": "de",
    "creatorTool": "Apache FOP Version 2.6",
    "createdAt": "2026-05-06T14:42:29.000Z",
    "pageUnit": "page",
    "pageCount": 51,
    "pagesExtracted": 51,
    "pagesWithText": 51,
    "isScanned": false,
    "tdmReserved": false,
    "robotsAllowed": true,
    "markdown": "<!-- page 1 -->\n# Grundgesetz für die Bundesrepublik Deutschland\n\nGG\n\nAusfertigungsdatum: 23.05.1949 …",
    "charCount": 182861,
    "approxTokenCount": 45716,
    "truncated": false,
    "chargedEvents": 1
}
```

A PowerPoint slide row in `pages` mode:

```json
{
    "rowType": "page",
    "inputIndex": 2,
    "fileType": "pptx",
    "status": "ok",
    "title": "Sample Deck",
    "pageUnit": "slide",
    "pageCount": 2,
    "pageNumber": 2,
    "pageLabel": "Regional Figures",
    "hasText": true,
    "widthPt": 720,
    "heightPt": 405,
    "markdown": "## Slide 2: Regional Figures\n\n| Region | Q1 | Q2 |\n| --- | --- | --- |\n| North | 10 | 12 |\n\n### Speaker notes\n\nMention that the North region grew fastest.",
    "charCount": 111
}
```

A file that was skipped (never charged):

```json
{
    "rowType": "document",
    "sourceUrl": "https://www.w3.org/",
    "fileType": null,
    "status": "unsupported_format",
    "statusMessage": "Server returned a web page (often a login, cookie or share page), not a document",
    "httpStatus": 200,
    "contentType": "text/html",
    "chargedEvents": 0
}
```

The run's key-value store also holds a **SUMMARY** record (counts per status and file type, charged events and one entry per input file) and, for documents longer than **Max characters per row** (or single pages over 1,000,000 characters in `pages` mode), the full text and Markdown (`fullTextUrl` and `fullMarkdownUrl` link to them). Full texts are stored only for files that were output and charged.

### Tips

- **Pages or chunks for RAG?** Use `pages` when you cite page numbers and want one embedding per page; use `chunks` for even-sized pieces with overlap and a heading path.
- **Cut cost on huge files** with **Pages or slides to extract**; only the selected pages count.
- **Large PDFs:** raise the run memory to 2–4 GB for documents with 1,000+ pages. Each GB counts as one start event, so a 4 GB run costs $0.006 more per run than the default 1 GB on the free tier.
- **Change detection:** on scheduled runs, compare `contentSha256` to skip files that did not change.
- **Slow websites:** some sites ask robots to wait between downloads (Crawl-delay), so batches from one site can take longer. The Actor downloads at most 2 files at a time from the same site. Waiting for a turn does not count toward **Timeout per file**, so queued files are not cut off.

### FAQ, disclaimers and support

#### Is it legal to extract text from documents?

You process files you choose, so make sure you have the rights to the documents you convert and respect their copyright and licences. By default the Actor checks text and data mining reservations (TDMRep, as foreseen by § 44b UrhG and Art. 4 of the EU DSM Directive) and robots.txt, and it never bypasses logins, paywalls, copy protection or encryption.

Our Actors are ethical and do not extract any private user data. The documents you process may still contain personal data, which is protected by the GDPR in the European Union and by other laws worldwide. PDF Text Extractor never outputs author, last-modified-by, manager, company or comment-author metadata, and it never logs document text. Do not process personal data unless you have a legitimate reason; if you are unsure, consult your lawyers.

#### Does it do OCR?

Not yet. Scanned pages are detected (`isScanned`, status `no_text`) and are not charged.

#### Why was my file skipped?

Check `status` and `statusMessage`. Common reasons: the link opens a web page instead of the file (`unsupported_format`), the server refuses access (`blocked`), the file is larger than **Max file size** (`too_large`), the PDF needs a password (`password_required`), the PDF forbids copying text (`copy_restricted`), or the publisher opted out (`tdm_reserved`, `robots_disallowed`; when a link redirects, the message names the host whose rules apply). A link without `http://` or `https://`, or otherwise malformed, gets `invalid_url`. `robots_disallowed` also covers a site whose robots.txt answers with a server error or does not answer within 10 seconds: the robots.txt standard (RFC 9309) treats that as "do not fetch", and `statusMessage` says which case applies. A link whose host does not exist or cannot be reached gets `http_error` (for example "Host not found" or a TLS error), or `invalid_url` for private network addresses.

#### Can it read Excel, EPUB or old .doc and .ppt files?

No. Save them as DOCX, PPTX or PDF first.

#### Do Google Drive or Dropbox links work?

Use direct download links. Google links are not supported, and share pages that show a preview return a web page.

#### What about password-protected files?

For PDFs, enter the password in **PDF password** (it is stored encrypted and never logged). PDFs that open without a password, such as ones that only restrict printing or editing, are read as they are, even when a password is set. Password-protected Word and PowerPoint files are not supported; save an unprotected copy.

#### Are tables extracted?

Word and PowerPoint tables become Markdown tables. Tables inside PDFs come out as text lines.

#### What is the maximum file size?

Up to 100 MB per file (default 50 MB), and up to 5,000 pages or slides per file (default 500).

#### How do I report a problem?

Open an issue on the **Issues** tab with the file URL (if public) and what you expected.

#### Can I use it from code or an AI agent?

Yes. See the **API** tab for HTTP, JavaScript and Python examples. The Actor also works as a tool through the Apify MCP server.

### Changelog

- **1.0** (2026-10-13): first release. PDF, Word (DOCX) and PowerPoint (PPTX); documents, pages and chunks output; TDMRep and robots.txt checks; pay-per-event pricing.

# Actor input Schema

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

Direct links to PDF, Word (DOCX) or PowerPoint (PPTX) files, one per line, starting with http:// or https://. Each unique URL gets its own result row with a status, so one bad link never stops the run: a malformed link gets status `invalid_url`. A URL listed twice is processed once (the run's SUMMARY counts it under `duplicatesSkipped`). Links to Google Drive and other unsupported platforms are skipped; share pages that return a web page are reported as `unsupported_format`. Exception: once your maximum charge per run is used up, the files not yet started get no row and are listed as `charge_limit_reached` in the SUMMARY record.

## `uploadedFiles` (type: `array`):

Upload PDF, Word (DOCX) or PowerPoint (PPTX) files from your computer (they are stored in your Apify key-value store), or paste file links. Processed exactly like document URLs.

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

How results are split into dataset rows: one row per file (`documents`), one row per PDF page or PowerPoint slide (`pages`; a Word file gives one row), or one row per text chunk for RAG and embeddings (`chunks`). Files that fail always produce one status row.

## `includeText` (type: `boolean`):

Adds the `text` field: reading-order plain text with paragraphs separated by blank lines.

## `includeMarkdown` (type: `boolean`):

Adds the `markdown` field: headings, lists, tables (Word and PowerPoint) and reflowed paragraphs.

## `removeHeadersFooters` (type: `boolean`):

PDF: drops lines that repeat at the top or bottom of most pages (running titles, page numbers). PowerPoint footer, date and slide-number boxes are always skipped, and Word headers and footers are never included.

## `pageMarkers` (type: `boolean`):

In `documents` mode, inserts `<!-- page N -->` (PDF) or `<!-- slide N -->` (PowerPoint) before each page or slide so you can cite them.

## `includeSpeakerNotes` (type: `boolean`):

Adds each slide's speaker notes under the slide as a 'Speaker notes' block.

## `pageRange` (type: `string`):

Page or slide numbers and ranges, for example `1-5, 8, 10-`. Leave empty for all. Applies to every PDF and PowerPoint file; ignored for Word files.

## `maxPagesPerDocument` (type: `integer`):

Stops after this many pages or slides of each file (after the page selection). Larger files are charged per started 100 pages or slides (see Pricing).

## `maxFileSizeMb` (type: `integer`):

Larger files are skipped with status `too_large` and are not charged.

## `maxCharsPerDocument` (type: `integer`):

In `documents` mode, longer text or Markdown is cut at a paragraph boundary and the full version is saved to the run's key-value store (see `fullTextUrl` / `fullMarkdownUrl`).

## `chunkSize` (type: `integer`):

Target length of each chunk in `chunks` mode. About 4 characters ≈ 1 token.

## `chunkOverlap` (type: `integer`):

Characters repeated from the end of the previous chunk, so context is not lost at boundaries.

## `pdfPassword` (type: `string`):

Password for encrypted PDFs, if you have it. Tried on every PDF that asks for one; PDFs that open without a password (for example, ones that only restrict printing or editing) are read as they are. Password-protected Word and PowerPoint files are not supported. Stored encrypted; never logged.

## `respectOptOuts` (type: `boolean`):

Skips files whose publisher reserved text and data mining (TDMRep header, `/.well-known/tdmrep.json` or PDF metadata) or that robots.txt disallows. Skipped files are not charged. Turn off only for files you own or are licensed to process.

## `userAgent` (type: `string`):

Optional. Some publishers require you to identify yourself (for example with your organisation name and a contact address). Leave empty for the default.

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

How many files are downloaded at the same time. At most 2 run against the same website, to stay polite.

## `timeoutPerDocumentSecs` (type: `integer`):

Limit for downloading and, separately, for parsing each file. Time spent waiting for a turn on the same website (at most 2 parallel downloads per site, plus any robots.txt Crawl-delay) does not count. Files that take longer get status `timeout` and are not charged.

## Actor input object example

```json
{
  "urls": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
    "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-memo.docx",
    "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-deck.pptx"
  ],
  "uploadedFiles": [],
  "outputMode": "documents",
  "includeText": true,
  "includeMarkdown": true,
  "removeHeadersFooters": true,
  "pageMarkers": true,
  "includeSpeakerNotes": true,
  "pageRange": "",
  "maxPagesPerDocument": 500,
  "maxFileSizeMb": 50,
  "maxCharsPerDocument": 300000,
  "chunkSize": 2000,
  "chunkOverlap": 200,
  "respectOptOuts": true,
  "userAgent": "",
  "maxConcurrency": 4,
  "timeoutPerDocumentSecs": 60
}
```

# Actor output Schema

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

One row per document, page/slide or chunk, plus a status row for every skipped or failed file.

## `summary` (type: `string`):

Counts per status and file type, charged events and one entry per input file (SUMMARY record).

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

Keys of the run's key-value store, including the full text and Markdown of documents that were truncated in the 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 = {
    "urls": [
        "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
        "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-memo.docx",
        "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-deck.pptx"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("openfeeds/pdf-to-text-markdown-extractor").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://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
        "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-memo.docx",
        "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-deck.pptx",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("openfeeds/pdf-to-text-markdown-extractor").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://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
    "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-memo.docx",
    "https://api.apify.com/v2/key-value-stores/openfeeds~pdf-to-text-markdown-extractor-samples/records/sample-deck.pptx"
  ]
}' |
apify call openfeeds/pdf-to-text-markdown-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,openfeeds/pdf-to-text-markdown-extractor"
        }
    }
}
```

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/NAif8RdvJ0hHHC3O1/builds/rkpLTBRPnbCXR61h6/openapi.json
