How to use it: 3 steps
- Make a free Apify accountApify 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.
- Paste your input and press StartNo 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.pdfin PDF or image URLs. Each start is one run. - Download the resultsWhen 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.
This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.
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 (
textorocr) 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.
Who uses it
AI agent builders
Let your agent read a PDF link and get text it can use.
Archive and records teams
Turn old scans without a text layer into searchable text.
Developers with mixed files
Send text PDFs, scans and photos in one run and get a status for each.
Price
Pay per event: you pay for each result the tool saves, plus a small start fee for each run. The price includes Apify platform costs. Apify bills you, not us. Prices below are for the Apify free plan.
| 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. |
Examples
- 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. That is enough for about 1,900 documents.
Prices checked on 24 October 2026. See the current price on Apify.
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.
Details
Step by step on Apify
- Open the Input tab.
- Keep the two prefilled
urls(an IRS W-9 form and a small test image), or add your own PDF or image URL. - Keep OCR mode
autoand OCR languagesEnglish. - Click Start.
- Open the Documents view in the Output tab and check
status,textPages,ocrPagesandtext.
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 for better results
- 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 and good to know
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
For developers
Sample result
One result from a real test run, in JSON. Real values change from run to run. In Excel or CSV each field is a column.
[
{
"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 [email protected] 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. You need your Apify API token from Apify Console → Settings → API & Integrations.
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)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"}'# 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)The cURL call waits for the results, up to 300 seconds. For longer runs, start a run (/runs) and get the results with a webhook or by checking the run. Apify API docs. LlamaIndex, MCP for AI agents and the JavaScript client: AI agents & MCP.
Data fields (26)
| Field | Type | Meaning |
|---|---|---|
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 (9)
The main fields of the input form. With the API you send them as JSON.
| Setting | Name in the API | Type | Example value |
|---|---|---|---|
| PDF or image URLs required | urls | array | ["https://www.irs.gov/pub/irs-pdf/fw9.pdf", "https://raw.githubusercontent.com/tesserac… |
| OCR mode | ocr | string | "auto" |
| OCR languages | languages | array | ["eng"] |
| Pages | pages | string | |
| Max pages per document | maxPages | integer | 50 |
| Text format | outputFormat | string | "text" |
| Rows | outputMode | string | "document" |
| Keep column layout (text layer) | preserveLayout | boolean | false |
| Max file size (MB) | maxFileSizeMb | integer | 50 |
Use cases with this tool
Each guide shows all the steps and the other tools.