# PDF Tables to Records — JSON, CSV & Page Sources (`gertner-data/pdf-table-records`) Actor

Turn text-based PDF tables into structured records for spreadsheets, ETL and AI workflows. Get JSON/CSV-ready data with page provenance, table coordinates and document hashes. Launch price: $0.0025/processed page, plus run start.

- **URL**: https://apify.com/gertner-data/pdf-table-records.md
- **Developed by:** [Евгений Гертнер](https://apify.com/gertner-data) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 processed pages

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## PDF Tables to Records — JSON, CSV & Page Sources

Turn **text-based PDF tables into structured records** for spreadsheets, ETL and AI workflows. Extract reports, catalogs and public price lists into JSON and CSV with page numbers, table coordinates and document hashes.

- **Two extraction strategies:** bordered tables or whitespace-aligned text.
- **Batch up to 10 PDFs**, with up to 100 selected pages per document.
- **Trace every row** to its page, table and source document.
- **JSON and CSV exports** ready for downstream processing.
- **Launch price: $2.50 per 1,000 processed pages**, plus $0.001 run start; platform usage included.

### Start with this input

```json
{
  "pdfUrls": ["https://raw.githubusercontent.com/jsvine/pdfplumber/stable/examples/pdfs/background-checks.pdf"],
  "startPage": 1,
  "maxPages": 2,
  "strategy": "lines",
  "mergeRepeatedHeaders": false
}
```

Choose `lines` for table borders or `text` for whitespace-aligned columns. The extractor reads the PDF's text layer and table geometry. Tune the strategy on a representative page, then reuse those settings across the same template.

### Get records with source evidence

The dataset contains one item per processed page: `status`, `tablesDetected`, `rows` and a `records` array. The key-value store provides:

- `TABLES`: flat JSON table-row array.
- `TABLES-CSV`: long-form CSV with document ID, page, table ID, row index, column and value.
- `SUMMARY`: document outcomes, processed pages, errors and request statistics.

```json
{
  "page": 1,
  "tableId": 1,
  "rowIndex": 1,
  "header": ["Product", "Price"],
  "cells": ["Widget", "12.50"],
  "record": {"Product": "Widget", "Price": "12.50"},
  "continuedFromPreviousPage": false
}
```

Numeric-looking values remain strings to preserve leading zeros and locale punctuation. Whitespace and Unicode forms are normalized. CSV applies spreadsheet-formula escaping; JSON retains the extracted values.

The first non-empty row becomes the table header. Blank and duplicate names receive deterministic names. `mergeRepeatedHeaders: true` groups consecutive single-table pages with exactly matching headers; page and table provenance remain available.

### Connect your pipeline

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("gertner-data/pdf-table-records").call(run_input={
    "pdfUrls": ["https://raw.githubusercontent.com/jsvine/pdfplumber/stable/examples/pdfs/background-checks.pdf"],
    "maxPages": 2
})
store = client.key_value_store(run["defaultKeyValueStoreId"])
summary = store.get_record("SUMMARY")["value"]
records = store.get_record("TABLES")["value"]
print(summary["complete"], len(records))
```

Use the API, saved tasks, schedules, webhooks or Apify MCP. The same document bytes and settings produce the same document ID and extraction.

### API coverage and run settings

Processes public, text-based PDFs over HTTP(S). A page with no detectable table returns `no_tables`; a page without a text layer returns `no_text_layer`. Password-protected, malformed or complex documents have structured outcomes in `SUMMARY`. Successful documents remain available when another document fails.

Table geometry determines extraction. Raw cells, normalized headers, page bounds and header/cell warnings provide review evidence for merged cells, multi-row headers and complex layouts.

1–10 PDFs, 15 MB per file, 100 selected pages per document. Page output: 1 MB; each run JSON/CSV export: 6 MB. Parser wall-clock limit: 50 seconds per subprocess, with Linux CPU/memory/file limits. Default memory: 1 GB; timeout: 900 seconds. Downloads use bounded retries for transient network errors, 429 and 5xx.

Inputs/results use your Apify retention settings. Temporary PDF bytes are removed after parsing. Diagnostic URLs omit query parameters; logs contain aggregate metrics. Use permitted public sources.

### Pricing

**Launch price: $0.001 run start + $0.0025 per processed page.** Platform usage included.

| Processed pages | Event price |
| --- | --- |
| 1 | $0.0035 |
| 2 | $0.0060 |
| 100 | $0.2510 |

Page events cover processing, including `no_tables` and `no_text_layer` outcomes. Failed downloads and unprocessed pages receive no page event. Set a maximum run charge to control spending; the start event applies independently.

Support: [Evgeny Gertner](https://t.me/evgertner).

# Actor input Schema

## `pdfUrls` (type: `array`):

One to ten public PDF URLs, up to 15 MB each. No passwords or authentication. Inputs and results are stored in your Apify account.

## `startPage` (type: `integer`):

One-based start page for every PDF.

## `maxPages` (type: `integer`):

Pages to process from the start page. Scanned/empty pages are reported explicitly.

## `strategy` (type: `string`):

Lines: ruled tables. Text: whitespace-aligned tables; may need review.

## `mergeRepeatedHeaders` (type: `boolean`):

Opt-in heuristic: group exactly matching headers on consecutive single-table pages. Does not infer missing cells.

## Actor input object example

```json
{
  "pdfUrls": [
    "https://raw.githubusercontent.com/jsvine/pdfplumber/stable/examples/pdfs/background-checks.pdf"
  ],
  "startPage": 1,
  "maxPages": 20,
  "strategy": "lines",
  "mergeRepeatedHeaders": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

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

No description

## `tables` (type: `string`):

No description

## `csv` (type: `string`):

No description

# 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 = {
    "pdfUrls": [
        "https://raw.githubusercontent.com/jsvine/pdfplumber/stable/examples/pdfs/background-checks.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gertner-data/pdf-table-records").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 = { "pdfUrls": ["https://raw.githubusercontent.com/jsvine/pdfplumber/stable/examples/pdfs/background-checks.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("gertner-data/pdf-table-records").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 '{
  "pdfUrls": [
    "https://raw.githubusercontent.com/jsvine/pdfplumber/stable/examples/pdfs/background-checks.pdf"
  ]
}' |
apify call gertner-data/pdf-table-records --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gertner-data/pdf-table-records"
        }
    }
}
```

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/XRYtly5j4jTEaBvmz/builds/RIpuPpT1S4z4RPKhH/openapi.json
