> Source: https://txtfetch.com/blog/extract-tables-for-rag > Plain-text twin — every page on txtfetch.com has one. https://txtfetch.com/text --- # Extracting tables from PDFs and spreadsheets for RAG Jun 2, 2026 · 3 min read · rag, tables, pdf, office-docs Ask any RAG pipeline builder which content type causes the most retrieval failures. A lot of them will say tables. A paragraph survives bad extraction gracefully. A jumbled sentence is still mostly readable. A table doesn’t survive as well. Strip out the column alignment and you’re left with a wall of numbers and labels. The order means nothing without the grid they came from. ## Why tables break naive extraction A table’s meaning lives entirely in its two-dimensional layout. Which cell is in which row, and which row belongs under which column header, both matter. Most “extract the text” libraries only understand one-dimensional text: a stream of characters in reading order. Fed a table, they have to guess how to flatten two dimensions into one. The guess is often wrong. Cells read top-to-bottom instead of left-to-right. Headers get separated from the rows they label by hundreds of characters. Merged cells get duplicated or dropped entirely. The result is number-soup, and that’s worse than an outright error. It looks like extracted text. It gets chunked and embedded like extracted text. It only fails visibly later. That happens when someone asks a question whose answer was in row 14 of a table that got scrambled into row 3’s neighborhood. ## What “extraction” for a table actually means here It’s worth being precise about what txtfetch does and doesn’t give you. `/v1/extract` returns a single flat `extracted_text` string. There’s no structured `rows`/`columns` object, and no JSON representation of cell boundaries. What Tika does well is flatten a table into that string in row-major reading order. It keeps each row’s cells together and headers attached to the data below them, instead of scattering them across the output: ```bash curl -X POST https://api.txtfetch.com/v1/extract \ -H "Authorization: Bearer $TXTFETCH_KEY" \ -F file=@quarterly-report.pdf ``` ```json { "status": "success", "extracted_text": "Region\tQ1\tQ2\tQ3\nNorth America\t3.1M\t3.6M\t4.2M\nEMEA\t1.8M\t2.0M\t2.3M..." } ``` Spreadsheets go through the same path. A sheet’s rows and columns come back as linear text in the same shape. An [XLSX model](https://txtfetch.com/extract/docx) and a [PDF table](https://txtfetch.com/extract/pdf) both resolve to the same kind of `extracted_text` your pipeline already knows how to handle: ```bash curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/models/forecast.xlsx" \ -H "Authorization: Bearer $TXTFETCH_KEY" ``` If your pipeline needs structured, per-cell output, such as a JSON object per row with typed columns, that’s a different problem than text extraction. `/v1/extract` doesn’t claim to solve it. What it solves is getting the table’s content into linear text without scrambling row/column correspondence. That’s the part that actually breaks most pipelines. ## Chunking tabular text so retrieval survives Once a table is flattened, the chunking decision matters more than usual. Splitting a table in the middle of its rows, the same fixed-size cut you’d apply to prose, divorces a row from its header. That makes the chunk unanswerable on its own. Two things help: - **Keep small tables whole.** A table under a few hundred tokens should usually be its own chunk rather than getting split, so the header stays attached to every row. - **Repeat the header row into each chunk of a large table.** For tables too big to keep whole, prefix every chunk with the header row’s text. That way each chunk is self-describing, instead of assuming the header survived from a previous chunk. See the [chunking strategies guide](https://txtfetch.com/blog/chunking-strategies-for-rag) for the general reasoning. Tables are the case where getting this specific decision right matters most. Tables are common enough inside Office documents that it’s also worth reading the [DOCX/PPTX/XLSX parsing guide](https://txtfetch.com/blog/parse-office-docs-docx-pptx-xlsx-for-llms). Read it if spreadsheets and embedded tables inside Word docs are a big share of your document set. Wrestling with a document set that’s mostly tabular? [Get in touch](https://txtfetch.com/contact) and we’ll set you up with an API key. keep reading - **[How to extract text from a PDF for RAG (without maintaining a parser)](https://txtfetch.com/blog/extract-text-from-pdf-for-rag)** Feeding PDFs into a RAG pipeline breaks the usual parser stack: multi-column layouts, embedded tables, scanned pages. One request handles all three. Jan 12, 2026 · 3 min read - **[Per-document vs per-page pricing for document extraction](https://txtfetch.com/blog/per-document-vs-per-page-pricing)** Per-page pricing looks cheaper until you multiply it by a 300-page report. This post frames what actually predicts your bill, and when per-page wins. Jul 14, 2026 · 3 min read - **[Ingesting large documents and big batches without falling over](https://txtfetch.com/blog/batch-and-large-document-ingestion)** A 500-page PDF and a ten-thousand-file backfill stress the same two things: single-request time and concurrency. Jun 23, 2026 · 3 min read See also: [PDF extraction →](https://txtfetch.com/extract/pdf) ## Try it on your own file. The free reader runs in your browser. Nothing gets uploaded. [Open the file reader →](https://txtfetch.com/tools/file-to-text) [Get an API key →](https://app.txtfetch.com/signup)