Bosco Labs

Tools › Data tools

PDF to JSON API: text, tables and metadata from a PDF URL

Coming soon to the Store

Turn any public PDF link (annual report, invoice, government notice, price list) into clean JSON: text per page in reading order (markdown headings and tables), tables as rows with a header guess, and title, author and dates. Built for AI agents that meet a PDF mid-task and for anyone who needs PDF data in a pipeline. Pricing: $0.50 per 1,000 pages ($0.0005 per page with text), no start fee. Failed files and scanned pages without text are free.

Price$0.0005 per page with text
DomainData tools
Call itApify API or MCP

Pricing: $0.50 per 1,000 pages ($0.0005 per page with text), no start fee. Failed files and scanned pages without text are free.

Coming soon to the Apify StoreAsk for early access

Questions agents ask

  • “Get the wage bracket table on page 14 of https://www.irs.gov/pub/irs-pdf/p15t.pdf as rows.”

Example

Input

{ "urls": ["https://www.sec.gov/files/form10-k.pdf"], "pages": "1-5,10", "extract": ["text", "tables"] }

Output

{
  "schema_version": "1",
  "input_index": 0,
  "url": "https://www.sec.gov/files/form10-k.pdf",
  "final_url": "https://www.sec.gov/files/form10-k.pdf",
  "file_size_bytes": 549322,
  "page_count": 19,
  "pages_processed": 2,
  "pages_charged": 2,
  "title": "Form 10-K",
  "author": "U.S. Securities and Exchange Commission",
  "subject": "Annual Report Pursuant to Section 13 or 15(d) of the Securities Exchange Act of 1934",
  "creator": "Acrobat PDFMaker 24 for Word",
  "producer": "Adobe PDF Library 24.1.163",
  "creation_date": "2024-05-12T10:49:53-04:00",
  "modification_date": "2026-09-10T12:50:48-04:00",
  "pages": [
    {
      "page": 1,
      "text": "UNITED STATES\nSECURITIES AND EXCHANGE COMMISSION\nWashington, D.C. 20549\n\nOMB APPROVAL\nOMB Number: 3235-0063\n..."
    },
    {
      "page": 2,
      "text": "(2) Particular attention is directed to Regulation 12B which contains general requirements\n..."
    }
  ],
  "tables": [],
  "warnings": [],
  "error": null,
  "source_url": "https://www.sec.gov/files/form10-k.pdf",
  "retrieved_at": "2026-11-05T22:41:04+00:00"
}

What you get

FieldTypeMeaning
schema_versionstringOutput schema version.
input_indexintegerPosition of this PDF in the input, 0-based: urls[input_index], or len(urls) for pdfBase64. Rows are written as each PDF finishes, so their order can differ from the input.
urlstring | nullThe PDF URL as given in the input; null for pdfBase64.
final_urlstring | nullURL the PDF was finally downloaded from, after redirects; null for pdfBase64 or on error.
file_size_bytesinteger | nullSize of the PDF file in bytes; null when it could not be downloaded.
page_countinteger | nullNumber of pages in the PDF; null on error.
pages_processedintegerPages read in this run (after pages, maxPages and size limits).
pages_chargedintegerPage events charged for this PDF: pages that had text (1 for a metadata-only request, 0 on error).
titlestring | nullTitle from the PDF's document info; null if not set or metadata not requested.
authorstring | nullAuthor from the document info.
subjectstring | nullSubject from the document info.
creatorstring | nullApplication that created the original document, e.g. Microsoft Word.
producerstring | nullApplication that wrote the PDF.
creation_datestring | nullCreation date, ISO 8601 with the PDF's UTC offset when given, e.g. 2024-05-12T10:49:53-04:00.
modification_datestring | nullLast modification date, ISO 8601.
pagesarray | nullOne entry per processed page: {page (1-based), text}. text is markdown-ish (## headings, | tables |) or plain, in reading order; null for pages without a text layer. null when text was not requested.
tablesarray | nullTables detected from aligned text: {page, header (first row when it looks like a header, else null), rows (arrays of cell strings, null = empty cell), n_cols}. null when tables were not requested.
warningsarrayThings to know, e.g. scanned pages without text (OCR not supported, not charged) or pages left out by maxPages.
errorstring | nullWhy this PDF failed (refused URL, download error, not a PDF, password-protected, unreadable, too complex: over the parse timeout or out of memory); null on success. Failed PDFs are not charged.
source_urlstring | nullWhere the data came from (the input URL); null for pdfBase64.
retrieved_atstringUTC time the PDF was processed.

Use with AI agents (MCP)

Add this URL to your MCP client (Claude, Cursor, VS Code, ...) to load the Actor as a tool through the Apify hosted MCP server. It signs you in with OAuth or accepts Authorization: Bearer <APIFY_TOKEN>. It works once the Actor is live on the Apify Store.

https://mcp.apify.com?tools=bosco_labs/pdf-to-data

For “Get the wage bracket table on page 14 of https://www.irs.gov/pub/irs-pdf/p15t.pdf as rows.” the agent passes:

{"urls": ["https://www.irs.gov/pub/irs-pdf/p15t.pdf"], "pages": "14", "extract": ["tables"]}

one JSON row per PDF with schema_version, source_url and a page number on every page and table, so the agent can cite where a value came from. Errors come back as a row with an error text, never as a crashed run.

Or call the Apify API: POST https://api.apify.com/v2/acts/bosco_labs~pdf-to-data/run-sync-get-dataset-items with the input as JSON body. Cost: $0.0005 per page with text.

Input fields

FieldTypeMeaning
urlsarray1 to 20 public http(s) links to PDF files, e.g. ["https://www.sec.gov/files/form10-k.pdf"]. Each PDF gives one output row. Files up to 50 MB; links to private or local addresses are refused. Empty = use pdfBase64 instead.
pdfBase64stringInstead of (or besides) URLs: the PDF file itself, base64-encoded, optionally as a data: URI, e.g. "JVBERi0xLjQK...". Up to 50 MB decoded (Apify limits the whole input to a few MB, so use URLs for big files). Empty = none.
pagesstringWhich pages to read, 1-based, as ranges and single pages separated by commas, e.g. "1-5,10". Applies to every PDF; pages past the end are skipped with a warning. Empty = all pages (up to maxPages).
extractarrayAny of text, tables, metadata, e.g. ["tables"]. Default (empty) = all three. Metadata alone costs one page per PDF.
maxPagesintegerMost pages read per PDF, counted from the first selected page, e.g. 10. Default 50. You pay per page with text, so this caps the cost per PDF; a warning tells you how to request the rest.
outputFormatstringHow page text is written: "markdown" marks headings with ## and writes detected tables as markdown tables; "text" gives plain paragraphs and tab-separated table rows. Default markdown. The tables field is the same in both.
timeoutSecsintegerMost seconds spent parsing one PDF, e.g. 60. Default 120. Pages are read until 3/4 of this time (later pages get a warning and are not charged); a PDF still parsing at the limit is stopped and returns an error row, not charged. Empty = 120.

Sources, licence and limits

Scanned PDFs? Pages that are only an image (scans, photos) have no text layer. They come back with text: null and a warning, and are not charged. OCR is not supported.

How good is table detection? Tables are found from aligned text: three or more lines in a row with two or more separate columns. Clean column layouts (price lists, statements, rate tables) work well. Limits: cells that wrap over several lines come out as extra rows; columns closer than about two characters merge into one cell; ruled tables are read from their text, not their lines; a table next to running text can pick up that text as a column. The page text always has everything, in reading order.

Which PDFs are refused? Links that are not http(s), hosts that resolve to private, local or cloud-metadata addresses (also after redirects), files over 50 MB, responses that are not a PDF (e.g. a login page), password-protected and broken files. Each gives a row with an error and costs nothing.

What does a metadata-only run cost? One page per PDF (extract: ["metadata"]).

Are my files stored? No. Each PDF is downloaded into memory, parsed and dropped. Only the extracted data goes to your dataset; nothing from the document is logged.

Size limits? 50 MB per file, up to 500 pages per PDF per run (maxPages, default 50), and about 8 MB of output per PDF. A warning tells you which pages to ask for next.

Very complex or hostile PDFs? Each PDF is parsed in its own process with a time limit (timeoutSecs, default 120 s) and a memory limit. Pages are read until 3/4 of that time, then the rest gets a warning. A PDF that is still stuck at the limit (for example one page that inflates to tens of MB of drawing commands) is stopped and returns an error row ("PDF too complex"), costs nothing, and the other PDFs in the run are delivered as usual.

Speed? Measured locally: 19 text pages in 2 s, 20 pages of the EU GDPR in 5 s, 50 pages of IRS Publication 15 in 10-20 s (parsing time, download excluded).

Coming soon to the Apify StoreAsk for early access