PDF Structured Table Extractor avatar

PDF Structured Table Extractor

Pricing

Pay per event

Go to Apify Store
PDF Structured Table Extractor

PDF Structured Table Extractor

Extract structured tables from public PDF URLs into JSON rows and coordinate-aware cells with page provenance, confidence scores, and parsing warnings.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Stas Persiianenko

Stas Persiianenko

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Turn tables in public digital PDFs into structured JSON rows and coordinate-aware cells. This PDF table extractor downloads up to 50 documents per run, detects table-like regions from positioned text, and preserves the source URL, file name, page number, table number, bounding box, confidence score, and parsing warnings.

Use the Actor for recurring document pipelines, spreadsheet exports, comparisons, and data-quality review. It works without a browser, proxy, account, or external AI API.

What does PDF Structured Table Extractor do?

  1. Validates that each input is a public HTTP(S) URL.
  2. Follows only validated public redirects.
  3. Enforces download timeout and file-size limits.
  4. Verifies the downloaded bytes are a PDF.
  5. Reads digital text and its coordinates with PDF.js.
  6. Groups aligned text into rows, cells, and table records.
  7. Writes one dataset item per detected table.
  8. Stores per-document failures and run totals in the OUTPUT key-value-store record.

The default dataset is ready for JSON, CSV, Excel, Google Sheets, Make, Zapier, or custom ETL consumers.

Who is it for?

  • Data engineers ingesting recurring public reports.
  • Analysts converting PDF tables to rows for spreadsheets or notebooks.
  • Compliance teams reviewing structured values with page-level evidence.
  • Researchers collecting comparable tables from document archives.
  • Automation builders scheduling extraction and comparing later runs.

Choose PDF Text Extractor when you need full document text rather than structured table cells. Choose HTML Table Extractor for tables embedded in web pages.

Why use it?

Unlike plain PDF-to-text output, every result keeps a two-dimensional rows array and flattened cells with row/column indexes and PDF coordinates. Quality signals make ambiguous output reviewable instead of hiding uncertainty. One bad URL does not discard successful documents in the same batch.

No OCR or generative model is used, so digital PDFs are processed predictably and economically. Private-network destinations are rejected to protect your run from server-side request forgery.

Input parameters

FieldTypeDefaultPurpose
urlsstring[]required1–50 direct public PDF URLs
maxTablesinteger100Global cap on emitted table records
pageNumbersinteger[]allOptional one-based pages to process in every PDF
includeHeadersbooleantrueSeparate a first row only when it looks distinct from later data rows
minRowsinteger3Minimum aligned rows for a detected table
minColumnsinteger2Minimum positioned cells in each qualifying row
maxFileSizeMbinteger25Reject larger documents, maximum 100 MB
timeoutSecsinteger60Per-download timeout, from 5 to 300 seconds

Raising minRows can suppress short list-like regions. Raising minColumns focuses extraction on wider tables. Use pageNumbers when a large report has known table pages.

Getting started

  1. Open the Actor input page.
  2. Add one or more direct public PDF URLs.
  3. Keep the default detection settings for the first run.
  4. Click Start.
  5. Open Dataset → Detected tables.
  6. Review confidence and parsingWarnings before downstream use.
  7. Export the dataset or connect it to your workflow.

Try this real input:

{
"urls": [
"https://raw.githubusercontent.com/tabulapdf/tabula-java/master/src/test/resources/technology/tabula/campaign_donors.pdf"
],
"maxTables": 25,
"minRows": 3,
"minColumns": 2,
"includeHeaders": true
}

Output fields

FieldMeaning
sourceUrlFinal validated PDF URL after redirects
fileNameFile name from response headers or URL
pageNumberOne-based source page
tableIndexTable sequence within the source document
headersInferred header row, or null
rowsTwo-dimensional array of structured data rows
cellsFlattened cells with row/column indexes and coordinates
rowCount, columnCountDetected table dimensions
boundingBoxCombined PDF-coordinate bounds of the table
extractionMethoddigital-text-position in this release
confidenceHeuristic score from 0 to 1
qualitySignalsColumn consistency, fill ratio, and page text-item count
parsingWarningsReview signals for inconsistent, empty, or ambiguous structure
extractedAtISO timestamp

Real output example

A local run on the campaign donor example detected a 55-row, 7-column table with 0.99 confidence:

{
"type": "table",
"sourceUrl": "https://raw.githubusercontent.com/tabulapdf/tabula-java/master/src/test/resources/technology/tabula/campaign_donors.pdf",
"fileName": "campaign_donors.pdf",
"pageNumber": 1,
"tableIndex": 1,
"headers": ["Apellido", "Nombre", "Matricula", "Cuit", "Fecha", "Tipo", "Importe"],
"rows": [["Abal Medina", "Juan Manuel", "...", "...", "...", "...", "..."]],
"rowCount": 55,
"columnCount": 7,
"confidence": 0.99,
"qualitySignals": {
"consistentColumnRatio": 0.98,
"filledCellRatio": 1,
"detectedTextItems": 405
},
"parsingWarnings": []
}

The actual cells array also includes rowIndex, columnIndex, value, x, y, width, and height for every detected cell.

Quality and parsing-error signals

confidence is not a claim that every semantic column is perfect. It measures geometric consistency and filled cells. Review records when:

  • parsingWarnings is non-empty;
  • merged or spanning cells create inconsistent column counts;
  • a document uses multi-line headers;
  • a numbered list is geometrically similar to a two-column table;
  • layout changes between scheduled runs.

Download failures are listed in the OUTPUT record with their URL and error. If every document fails, the run fails with a non-zero status. If a valid digital PDF has no qualifying table, it completes with zero table records.

How much does it cost to extract structured PDF tables?

Pricing uses one start event per run and one table event per detected table. The current source configuration starts at $0.005 per run and the BRONZE table rate is $0.0196 per table, with lower per-table rates at higher usage tiers.

At the BRONZE rate:

  • 5 detected tables: about $0.103 total.
  • 25 detected tables: about $0.495 total.
  • 100 detected tables: about $1.965 total.

These examples combine the start fee and table events. The platform shows the active tier and maximum charge before each run. Failed downloads and PDFs with no detected table do not produce table events.

Batch and recurring workflows

  • Schedule a monthly batch of public financial reports.
  • Compare normalized rows with the previous dataset.
  • Alert when table dimensions or selected values change.
  • Export new table records to Google Sheets or a warehouse.
  • Keep sourceUrl, pageNumber, and cell coordinates with every transformed record for auditability.

For recurring documents, use stable direct URLs where possible and retain the source dataset ID alongside your transformed output.

Export to CSV or Excel

Each dataset item represents one table and contains nested rows. JSON preserves the complete structure. For flat CSV or Excel output, map each element of rows to a separate downstream row and copy sourceUrl, pageNumber, and tableIndex onto it. Apify integrations, Make, Zapier, or a short script can perform that expansion.

Run with the Apify API

Replace APIFY_TOKEN with your token.

cURL

curl -X POST \
"https://api.apify.com/v2/acts/automation-lab~pdf-structured-table-extractor/runs?token=APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls":["https://raw.githubusercontent.com/camelot-dev/camelot/master/docs/_static/pdf/foo.pdf"],"maxTables":10}'

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/pdf-structured-table-extractor').call({
urls: ['https://raw.githubusercontent.com/camelot-dev/camelot/master/docs/_static/pdf/foo.pdf'],
maxTables: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Python

from apify_client import ApifyClient
import os
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/pdf-structured-table-extractor').call(run_input={
'urls': ['https://raw.githubusercontent.com/camelot-dev/camelot/master/docs/_static/pdf/foo.pdf'],
'maxTables': 10,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)

Use with MCP and AI agents

Add the Actor to Claude Code:

claude mcp add --transport http apify \
"https://mcp.apify.com?tools=automation-lab/pdf-structured-table-extractor"

Claude Desktop

Add this JSON under mcpServers in the Claude Desktop configuration:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com?tools=automation-lab/pdf-structured-table-extractor"
}
}
}

Cursor

Add the same apify server URL in Cursor Settings → MCP.

VS Code

Add the same apify server URL to your VS Code MCP server configuration.

Example prompts:

  • “Extract tables from these three public report URLs and summarize warnings.”
  • “Run the PDF table extractor on pages 4, 7, and 9, then return source coordinates for cells containing percentages.”
  • “Compare structured rows in this month’s PDF with the previous dataset.”

Limits

  • Digital-text PDFs only; image-only scans need OCR before this Actor.
  • Password-protected or encrypted PDFs may fail.
  • It does not log in, solve CAPTCHAs, or access private files.
  • Irregular, rotated, borderless, spanning, or deeply nested tables may need threshold adjustment or manual review.
  • A geometric detector can classify aligned numbered lists as tables.
  • pageNumbers applies to every URL in a batch.
  • The Actor does not edit PDFs and is not a PDF table editor.

Legality and responsible use

Process only documents you are authorized to download and reuse. Respect copyright, licensing terms, privacy obligations, and source-site policies. Public availability does not automatically permit every redistribution or commercial use. Avoid exposing personal or sensitive data through public datasets.

Troubleshooting

The run returned zero tables. Confirm the PDF contains selectable text, remove pageNumbers, lower minRows to 2, or lower minColumns to 2. An image-only scan requires OCR.

Columns are split or merged incorrectly. Review cells and coordinates, adjust detection thresholds, and keep parsingWarnings with downstream records.

The URL works in my browser but fails here. Use a direct public PDF URL without login, cookies, expiring access, or a private-network address. Check the OUTPUT record for the exact HTTP, size, timeout, or signature error.

One URL failed in a batch. Successful documents still produce results. Failed URL details remain in OUTPUT; rerun only those URLs after fixing access.

FAQ

Does it use OCR or AI?

No. This release uses PDF.js digital text positions. That keeps extraction deterministic and inexpensive, but scanned pages are unsupported.

Can it process several PDFs?

Yes. Supply up to 50 URLs and cap total output with maxTables.

Are headers always removed from rows?

No. With includeHeaders: true, the first row is separated only when it differs enough from later numeric data rows. Otherwise headers is null and all detected rows remain in rows with a warning.

Can I trace a value back to the PDF?

Yes. Every table includes the source URL and page number; every flattened cell includes PDF coordinates.

Does it charge for failed URLs?

Failed URLs do not produce table events. A run still has its one-time start event.

Support

If a reproducible digital PDF is parsed incorrectly, open an Actor issue with the public URL, input, expected page/table, and a link to the run. Do not include private documents or credentials.