PDF Text and Table Extractor avatar

PDF Text and Table Extractor

Pricing

$10.00 / 1,000 pdf extracteds

Go to Apify Store
PDF Text and Table Extractor

PDF Text and Table Extractor

Extract native PDF text and grid tables into JSON, text and CSV. HTTPS/base64 input, duplicate detection and clear partial/OCR statuses. Pay only for PDFs completed without technical warnings.

Pricing

$10.00 / 1,000 pdf extracteds

Rating

0.0

(0)

Developer

Orlando

Orlando

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

What does PDF Text and Table Extractor do?

Extract selectable PDF text and tables with visible borders into page-level JSON, plain text, and a CSV of table cells. Send public HTTPS PDF links or base64-encoded files. Run the built-in synthetic example without preparing an input file.

This Actor runs on Apify, so it can be invoked through the platform API and connected to existing workflows. It does not call an AI service, use a proxy, or perform OCR. A successful run means the program completed: inspect each document's status to identify partial results and files that need OCR.

Why use this extractor?

Convert native PDF reports and simple product tables into reusable data. Every table keeps its page number, row, and column, making review easier. Decimal commas, leading zeroes, currency symbols, and negative numbers remain strings in JSON. Repeated files in the same batch are detected using SHA-256 and point to the first extracted result.

This is a deterministic extraction tool. It does not interpret invoices, infer missing cells, validate totals, or certify the accuracy of a document. Tables without borders, unusual fonts, merged cells, multi-column layouts, and images may need other processing.

Practical workflows

Your inputWhat you can automateWhat still needs review
A supplier price list exported as a PDF with grid linesCollect the detected table cells as JSON or CSV, then map the relevant columns in your workflowWhich column is the SKU, currency, unit, or price; these fields are not inferred
A native PDF reportRetrieve page-level text and tables for search, indexing, or downstream analysisReading order and complex layouts
A batch with repeated PDFsExtract each unique file once within that run and keep duplicate referencesDeduplication across separate runs belongs in your workflow

Try the built-in two-page table demo first. It includes 002, 1.234,56, -12,50, and USD 1,234.56, so you can inspect how strings are preserved in JSON before connecting real documents.

How to use

  1. For a first test, leave Documents empty and enable Run built-in demo.
  2. For your own authorized files, enter HTTPS URLs or objects with a source and optional name.
  3. Choose a page limit, then start the Actor.
  4. Inspect the document statuses in the dataset. Open Storage for each document's JSON, text, and CSV records.

Input

{
"documents": [{"url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf", "name": "sample.pdf"}],
"runDemo": false,
"maxPages": 20,
"extractTables": true
}

Use exactly one of url or base64 per object. Maximum: 10 documents per run, 10 MB per PDF, 50 pages per document, and 45 seconds of worker time per document. Page limit defaults to 20. Each document's extracted JSON is limited to approximately 4 MB. The platform run is configured separately with a 600-second timeout and 512 MB memory. HTTPS port 443 is required; authenticated URLs with username/password and private-network destinations are rejected. Download redirects are limited to three and each destination is checked.

Output

OUTPUT contains the run summary and all document summaries. Each unique parsed file has document-001-json and document-001-text records. With table extraction enabled, document-001-tables is a CSV in long cell format: page, table, row, column, value. The dataset can also be downloaded using Apify's JSON, CSV, and Excel exports; it contains summaries, not the full nested table data.

{
"doc_id": "document-001",
"status": "ok",
"pages_total": 2,
"pages_processed": 2,
"table_count": 2,
"warnings": [],
"json_key": "document-001-json"
}

Automate with Python

Install apify-client>=3.2,<4 and supply your own APIFY_TOKEN through your environment or secret manager. This example starts the built-in demo, waits, and retrieves the full document JSON, not just the dataset summary. Keep the printed run ID: use the recovery block below if a connection fails.

import json
import os
from datetime import timedelta
from decimal import Decimal
from apify_client import ApifyClient
# Disable automatic retries for the start request to avoid an ambiguous restart.
client = ApifyClient(os.environ["APIFY_TOKEN"], max_retries=0)
run = client.actor("odinbrs/pdf-text-and-table-extractor").start(
run_input={"documents": [], "runDemo": True,
"maxPages": 20, "extractTables": True},
max_total_charge_usd=Decimal("0.01"),
run_timeout=timedelta(seconds=600),
memory_mbytes=512,
restart_on_error=False,
)
print("Keep this run ID:", run.id, flush=True)
# Recovery: replace run.id with your existing run ID to download without a new run.
finished = client.run(run.id).wait_for_finish(wait_duration=timedelta(seconds=660))
if finished is None or finished.status not in {"SUCCEEDED", "FAILED", "TIMED-OUT", "ABORTED"}:
raise RuntimeError("Run still active or unavailable. Check the same run in Console.")
store = client.key_value_store(finished.default_key_value_store_id)
record = store.get_record("OUTPUT")
if record is None:
raise RuntimeError("No OUTPUT available; inspect this run in Console.")
summary = record["value"]
print(json.dumps(summary, ensure_ascii=False, indent=2))
for document in summary["results"]:
if document.get("json_key"):
full_record = store.get_record(document["json_key"])
if full_record is None:
raise RuntimeError("Document record unavailable; check retention and this run.")
print(json.dumps(full_record["value"], ensure_ascii=False, indent=2))

For your own PDFs, replace the input with the JSON example above and set runDemo to false. The maximum charge of $0.01 permits one billable document; increase it to $0.10 for up to ten. Check requested_documents, documents, stop_reason, each document's status, and billing_status. A SUCCEEDED run can contain partial output. A failed run may still have recoverable records.

To retrieve plain text or CSV, call store.get_record_as_bytes(document["text_key"]) or store.get_record_as_bytes(document["tables_key"]) when that key exists, then save the returned value bytes. A duplicate points to duplicate_of; it does not have a second full record. Download before storage retention expires. If the initial start request fails before returning an ID, inspect your Console Runs before starting again.

See the official Python Actor client and key-value store client for connection options.

Connect n8n or Make

In n8n, configure the official Apify node with your own credentials. Use Run Actor, select this Actor, pass the Input JSON, and enable Wait for finish. Use the returned run's defaultKeyValueStoreId in Key-Value Stores → Get Record, with key OUTPUT. Iterate its results and retrieve the json_key, text_key, or tables_key records you need. Filter or route documents using their status before updating another system. See the Apify n8n setup guide.

In Make, use Apify's Run an Actor module and wait for completion. The ordinary Get Dataset Items operation returns summaries only. For the full content, use the run's defaultKeyValueStoreId to retrieve OUTPUT and then its document keys through an authenticated HTTP request:

GET https://api.apify.com/v2/key-value-stores/{defaultKeyValueStoreId}/records/OUTPUT
GET https://api.apify.com/v2/key-value-stores/{defaultKeyValueStoreId}/records/{json_key}
Authorization: Bearer YOUR_APIFY_TOKEN

Store authentication in the integration's credential settings, never a shared URL. If a module does not expose the maximum charge option, the platform HTTP API accepts maxTotalChargeUsd when starting a run. Avoid automatic retries of the run-start step; recover the existing run instead. Set a 600-second Actor timeout and use polling or a completion trigger if your integration cannot wait that long. Integration steps are based on the official Make guide; the exact modules available depend on your installation. No n8n or Make workspace is provisioned by this Actor.

Data fields and statuses

FieldMeaning
statusok, partial, needs_ocr, no_extractable_text, duplicate, or error
pages_total / pages_processedFile page count versus extracted pages
table_countDetected grid tables; zero does not prove no table exists
warningsPage limit, output limit, missing text, or a complex table layout requiring review
duplicate_ofOriginal document identifier for repeated bytes
errorSafe error code, without credentials or source URL
sha256Hash of original bytes, for audit and duplicate detection

An ok status indicates that extraction completed without the listed technical warnings. It is not an accuracy score. A page containing both text and scanned content may still need manual review because this version does not recognize text inside images.

Tables containing spanning cells or multiline cells trigger a complex_layout_review warning and a partial document status. These structures can combine several apparent rows into one cell. The raw extraction remains available for inspection; this version does not guess how to split those cells.

Pricing and cost estimation

US$ 0.01 per unique PDF with status ok ($10 per 1,000 completed documents). There is no start fee or additional platform-usage charge for users of this pay-per-event Actor. The live Pricing tab is authoritative.

The built-in demo, duplicates within a run, errors, blank files, OCR-only files, and all partial results have no extraction charge. Partial output is still available to inspect. A technically successful extraction is not a guarantee that every cell was recognized correctly.

Examples: five unique ok PDFs cost $0.05. Two ok PDFs plus one duplicate and one scan cost $0.02. The built-in demo costs $0. Set the run's maximum charge high enough for the number of documents you want processed ($0.10 for ten). The Actor stops before the next document if the remaining limit cannot pay for one event; unprocessed inputs are counted by comparing requested_documents with documents in OUTPUT.

Full result records, the dataset summary, and OUTPUT are saved before an extraction is charged. OUTPUT is updated with the final billing_status and charged_events; the dataset is a snapshot from before charging and can show pending. On an ambiguous billing response the run stops and reports unconfirmed, retaining the extracted output. It does not repeat the charge automatically.

Automatic replay of a previously started run (resurrection or migration) is disabled to avoid duplicate charges. Open that run's existing storage to recover saved results. Starting a separate new run is a new extraction and may charge again; deduplication applies within a run only.

Tips

Use small batches and native PDFs with visible table lines. Lower the page limit for previews. JSON preserves original extracted strings. To reduce spreadsheet formula injection risk, the CSV adds an apostrophe before cells beginning with formula-like characters, including a minus sign; use JSON when exact strings matter. Source URLs are not copied into output summaries or logs, but the platform retains the submitted input. Do not put confidential URLs in a public example.

Results are stored in the run's Apify storage and follow the account's retention and access settings. Export results before retention expires. This tool does not promise archival storage. Use only documents you are authorized to process.

FAQ and support

Does this read scans or handwriting? No. Image-only pages are marked needs_ocr; no paid fallback runs automatically.

Does it preserve a spreadsheet's original formatting? No. It returns detected cells, coordinates, and text. Check important values against the PDF.

What happens on failure? Each document gets a status and safe error code. If every document fails, the run fails after saving the summary, enabling platform failure alerts. Partial batches keep the successful results.

How do I report a problem? Use this Actor's Issues tab with the run ID, document status, and a small reproducible example that you are allowed to share. Do not post confidential PDFs, access tokens, or signed download links. Validate important values against the original PDF before relying on them.