# PDF to Text OCR: Turn PDF and Image Links into Clean Text

> PDF to text OCR from a link: read the text layer or scan the page with Tesseract. Plain text or Markdown, one row per page. 20 languages. No login.

URL: https://cliqtomedia.com/actors/pdf-text-ocr/

Category: AI-ready content & documents · Status: live on Apify Store · Apify page: https://apify.com/cliqtomedia/pdf-text-ocr?fpr=cliqto

Give a link to a PDF or an image. You get its text back, page by page. Normal PDFs are read directly, and scanned pages go through OCR.

## How to use it: 3 steps

1. **Make a free Apify account.** Apify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
2. **Paste your input and press Start.** No code needed: you fill in a form (the input). It already has a working example. For example: `https://www.irs.gov/pub/irs-pdf/fw9.pdf` in PDF or image URLs. Each start is one run.
3. **Download the results.** When the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.

## What it does

Turn public PDF and image URLs into clean text or Markdown. The Actor reads the PDF text layer when a page has one, and runs Tesseract OCR on scanned pages and images, page by page. No login, no API key. A run with one text PDF costs about $0.0075; each OCR page adds $0.012.

- Downloads the file and checks its real type from the file content (not from the URL).
- Reads every selected page of a PDF:
- Text layer: if the page has real text, it is read directly. This is fast and exact.
- OCR: if the page is a scan (no usable text), it is rendered at 300 DPI and read with Tesseract OCR.
- Reads images (PNG, JPG, TIFF, GIF, BMP, WEBP) with OCR.
- Saves the text as plain text or Markdown to the Dataset, with page numbers, method (`text` or `ocr`) and OCR confidence.
- Deletes the downloaded file. Documents and page images are never stored.

### Good for

- AI agents and RAG pipelines: get clean text from a PDF link, one row per page, ready for chunking.
- Scanned archives and forms: read old scans that have no text layer.
- Mixed batches: text PDFs, scans and photos of documents in one run, with clear status per file.

## Price

Pay per event. Apify bills you, not us.

| What you pay for | Price | When |
|---|---|---|
| Start fee | $0.005 | Charged once per run. This tool uses 1 GB of memory or less by default; more memory costs more. |
| Document (text layer) | $0.0025 (from $0.0022 on paid Apify plans) | One document with at least one page read from the PDF text layer, or a PDF checked with OCR off that has no text layer. In page mode, one event per started 50 text-layer page rows. Failed and not-found documents are not charged. |
| OCR page | $0.012 (from $0.0105 on paid Apify plans) | One page (or image) read with OCR, charged once per selected OCR language. Failed pages are not charged. |

- One document: about $0.0075.
- 1,000 documents: about $2.50.
- Every day 100 documents, for 30 days: about $7.65 a month.

Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed.

Prices checked on 24 October 2026. Current price: https://apify.com/cliqtomedia/pdf-text-ocr?fpr=cliqto

## Questions

### Can it read handwriting?

Not well. OCR here reads printed text. Handwriting gives poor or empty results.

### Do you keep my files?

No. The file is deleted after reading. Only the text is saved in your dataset.

### Will my tables stay as tables?

No. Table text comes out as lines, without columns. Try our PDF to Markdown tool for tables.

### Can I upload a file from my computer?

No. It works with public links only. Put the file online first, then paste the link.

### Do I need a login or an API key for the documents?

No. The Actor reads public URLs only. It does not send cookies or passwords, and it does not open private network addresses.

### Do you keep my documents?

No. Each file is downloaded to a temporary folder and deleted after it is read. Only the extracted text is saved to your Dataset. Make sure you have the right to process the documents you send.

### Why did I pay for OCR on a PDF?

In `auto` mode, pages without usable text (scans, or pages with fewer than 25 visible characters or mostly broken glyphs) are read with OCR. Use `ocr: never` if you want the text layer only. With `ocr: never` a PDF is still charged as one `document`, also when it turns out to have no text layer.

### Is OCR 100% correct?

No. Tesseract is good on clean printed text and weaker on low-quality scans, small print, handwriting and complex layouts. Check `ocrConfidence`.

### Is the output the same as other PDF text extractors?

The text is similar, but field names are different (for example `text` and `status`). Map the fields when you switch.

## Data fields

- `url` (string): Input URL as given.
- `finalUrl` (string): URL after redirects; null when the file was not downloaded.
- `status` (string): complete, partial (some pages failed or were not processed), not_found (HTTP 404/410) or error.
- `fileType` (string): Detected type from the file content: pdf, png, jpg, tiff, gif, bmp or webp.
- `contentType` (string): Content-Type header sent by the server (document rows).
- `fileSizeBytes` (integer): Downloaded size in bytes (document rows).
- `pageCount` (integer): Total pages in the document (1 for single images); null if unknown.
- `pagesProcessed` (integer): Pages read successfully (document rows).
- `pagesTruncated` (boolean): true when maxPages cut the page selection (document rows).
- `textPages` (integer): Pages taken from the PDF text layer (document rows). In document mode all of them together are charged as one document event.
- `ocrPages` (integer): Pages read with OCR, each charged as one ocr-page event per selected OCR language (document rows).
- `pageNumber` (integer): Page number, 1-based (page rows).
- `method` (string): How the page was read: text (PDF text layer), ocr, or none (no text found with OCR off) (page rows).
- `ocrConfidence` (number): Tesseract mean word confidence 0–100 for OCR pages; null for text-layer pages (page rows).
- `format` (string): text or markdown.
- `ocrLanguages` (array): OCR languages used, when any page was OCRed (document rows).
- `charCount` (integer): Characters in text.
- `text` (string): Extracted text of the document (document rows, pages joined) or of the page (page rows). null on error.
- `pages` (array): Per page: pageNumber, method, charCount, ocrConfidence, text, error (document rows).
- `title` (string): Title from the PDF metadata; null when the PDF has none.
- `metadata` (object): PDF metadata as reported by the file: author, subject, keywords, creator, producer, creationDate, modificationDate, pdfVersion. Not verified (document rows).
- `encrypted` (boolean): true when the PDF is encrypted (it may still be readable) (document rows).
- `error` (object): Error for this row: {code, message}, e.g. NOT_FOUND, FILE_TOO_LARGE, UNSUPPORTED_FILE_TYPE, PDF_PASSWORD_REQUIRED, DOWNLOAD_TIMEOUT, DEADLINE_REACHED, TOO_MANY_FAILURES; null when there is none.
- `warnings` (array): Notes such as truncated pages or pages without a text layer.
- `fetchedAt` (string): When the file was downloaded (ISO 8601).
- `processedAt` (string): When the row was written (ISO 8601).

## Input settings

- `urls` (array, required): Up to 100 public http(s) URLs of PDF files or images (PNG, JPG, TIFF, GIF, BMP, WEBP). The file type is detected from the file content, not the URL. No login, cookies or private networks; duplicates are processed once. Files are deleted when the run ends.
- `ocr` (string): auto (default): use the PDF text layer and run OCR only on pages without usable text (scans). always: OCR every page, even if it has a text layer. never: text layer only, no OCR (images then fail with OCR_DISABLED). Text-layer pages are covered by one per-document charge; OCR is charged per page and per selected language.
- `languages` (array): Languages of the document, used by OCR only. Up to 3. Each OCR page is charged once per selected language, and more languages make OCR slower, so pick only the languages the document uses. Default: English.
- `pages` (string): Optional page selection for every document, e.g. 1-3, 5, 10- (10 to the end). Empty: all pages, up to Max pages per document.
- `maxPages` (integer): Upper limit of processed pages per document (after the page selection). Extra pages are skipped, not charged, and reported in warnings. 1–300, default 50.
- `outputFormat` (string): text (default): clean plain text. markdown: paragraphs re-flowed, bullet and numbered lists, short ALL-CAPS lines as headings, page markers. Tables are not rebuilt.
- `outputMode` (string): document (default): one row per document with full text and a pages[] list; text-layer pages are charged as one document event. page: one row per page, ready for chunking and RAG; text-layer pages are charged as one document event per started 50 page rows. A scan with OCR off gives one row, charged as one document event.
- `preserveLayout` (boolean): Keep the physical layout of text-layer pages (columns, aligned spacing). Off by default, which gives reading-order text. Does not affect OCR pages.
- `maxFileSizeMb` (integer): Larger files are not downloaded and get error FILE_TOO_LARGE. 1–100, default 50.

## Step by step on Apify

1. Open the Input tab.
2. Keep the two prefilled `urls` (an IRS W-9 form and a small test image), or add your own PDF or image URL.
3. Keep OCR mode `auto` and OCR languages `English`.
4. Click Start.
5. Open the Documents view in the Output tab and check `status`, `textPages`, `ocrPages` and `text`.

## Use cases

| Task | Input | You get | Key fields | Next step |
|---|---|---|---|---|
| Give an AI agent the text of a PDF link | `urls` | document row | `text`, `pageCount`, `title` | MCP tool call, LLM prompt |
| Split documents into pages for RAG | `urls`, `outputMode: page` | page row | `pageNumber`, `text`, `method` | Chunking, vector database |
| Read a scanned archive | `urls`, `ocr: auto`, `languages` | document row | `ocrPages`, `pages[].ocrConfidence`, `text` | Search index, review queue |
| Get headings and lists as Markdown | `urls`, `outputFormat: markdown` | document row | `text`, `format` | Notes, knowledge base |
| Read only part of long reports | `urls`, `pages: "1-3"` | document row | `pagesProcessed`, `text` | Summaries, alerts |

## Tips

- Use a page range for long reports. You pay OCR only for the pages you read.
- Check the OCR confidence on each page. Low numbers mean you should check the page by hand.
- Use PDF, not multi-page TIFF, for long scans. A TIFF is read in one OCR call with a time limit.

## Limits

In document mode, a document gets `status: partial` when some pages were read and others failed (for example one OCR page timed out) or the run stopped in the middle of it (deadline or cost limit). Read pages keep their text; failed pages have `pages[].error`. Only read pages are charged. In page mode there is no `partial` status: each page row is `complete` or `error`, and a stop is listed in `warnings` and `RUN_SUMMARY`.

- No handwriting. Tesseract reads printed text; handwritten text gives poor or empty results.
- Tables are not rebuilt. Table text comes out as lines, without columns.
- No Chinese, Japanese or Korean OCR. PDFs in these languages still work if they have a text layer.
- No files behind a login, cookies or a private network. No uploads: only URLs.
- No DOCX, HTML or EPUB. An HTML page gives the error `UNSUPPORTED_FILE_TYPE`.
- A multi-page TIFF is read with one OCR call, which must finish within the time limit of one OCR page (50 seconds at 1 GB). Use PDF for long scans.
- Up to 100 URLs per run. 100 text PDFs took 31 seconds in our test.
- Up to 300 pages per document (`maxPages`). A 300-page text PDF took about 17 seconds.

## Sample result

```json
[
  {
    "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf",
    "finalUrl": "https://www.irs.gov/pub/irs-pdf/fw9.pdf",
    "status": "complete",
    "fileType": "pdf",
    "contentType": "application/pdf",
    "fileSizeBytes": 140815,
    "pageCount": 6,
    "pagesProcessed": 6,
    "pagesTruncated": false,
    "textPages": 6,
    "ocrPages": 0,
    "format": "text",
    "ocrLanguages": null,
    "charCount": 37820,
    "text": "W-9\n\nForm\n(Rev. March 2024)\nDepartment of the Treasury\nInternal Revenue Service\n\nRequest for Taxpayer\nIdentification Number and Certification…",
    "pages": [
      { "pageNumber": 1, "method": "text", "charCount": 5703, "ocrConfidence": null, "text": "W-9\n\nForm\n(Rev. March 2024)…", "error": null }
    ],
    "title": "Form W-9 (Rev. March 2024)",
    "metadata": { "subject": "Request for Taxpayer Identification Number and Certification", "creator": "Designer 6.5", "pdfVersion": "1.7" },
    "encrypted": false,
    "error": null,
    "warnings": [],
    "fetchedAt": "2026-10-13T05:23:31.200Z",
    "processedAt": "2026-10-13T05:23:31.254Z"
  },
  {
    "url": "https://raw.githubusercontent.com/tesseract-ocr/tessdoc/main/images/eurotext.png",
    "status": "complete",
    "fileType": "png",
    "pageCount": 1,
    "textPages": 0,
    "ocrPages": 1,
    "ocrLanguages": ["eng"],
    "charCount": 414,
    "text": "The (quick) [brown] {fox} jumps!\nOver the $43,456.78 <lazy> #90 dog\n& duck/goose, as 12.5% of E-mail\nfrom aspammer@website.com is spam.…",
    "pages": [
      { "pageNumber": 1, "method": "ocr", "charCount": 414, "ocrConfidence": 90.2, "text": "The (quick) [brown] {fox} jumps!…", "error": null }
    ],
    "title": null,
    "metadata": null,
    "error": null,
    "warnings": []
  }
]
```

## Use it from code

Actor ID: `cliqtomedia/pdf-text-ocr`

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/pdf-text-ocr").call(run_input={
    "urls": [
        "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
    ],
    "ocr": "auto"
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

```bash
curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~pdf-text-ocr/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf"], "ocr": "auto"}'
```

```python
# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool

tool = ApifyActorsTool("cliqtomedia/pdf-text-ocr")
result = tool.invoke({"run_input": {"urls": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf"], "ocr": "auto"}})
print(result)
```

run-sync waits up to 300 seconds; for longer runs start a run and use a webhook. LlamaIndex and MCP: https://cliqtomedia.com/actors/ai-agents/

## Use cases with this tool

- [One piece of content, ten new posts](https://cliqtomedia.com/actors/use-cases/content-repurposing/): Turn videos, podcasts, PDFs and articles into clean text. Make posts, notes and AI drafts from it.

## Similar tools

- [DOI Metadata & Bibliography Enrichment](https://cliqtomedia.com/actors/doi-bibliography-enrichment/)
- [YouTube Subtitles & Transcript Scraper API](https://cliqtomedia.com/actors/youtube-transcript-scraper/)
- [RSS & Atom Feed Reader / Monitor](https://cliqtomedia.com/actors/rss-atom-feed-reader-monitor/)
- [WordPress Posts & Pages Scraper](https://cliqtomedia.com/actors/wordpress-posts-pages-scraper/)
- [News Article Extractor: RSS, URLs & Clean Text](https://cliqtomedia.com/actors/news-article-extractor/)
- [RAG Web Search: Google Results as Clean Markdown](https://cliqtomedia.com/actors/rag-web-search/)
