PDF to Excel — heuristics for table detection in the wild
PDFs describe positions, not tables. Turning that into rows and columns is an ancient computer-science problem. Here is how we approach it.

A PDF does not know what a table is. It knows what a rectangle is, and where each character is placed on the page. Converting that low-level information back into rows and columns is a research problem people have written PhD theses about.
Nobody has solved it perfectly. We have not either. But we have a set of heuristics that work well enough on the 80 percent of business documents users actually convert — invoices, financial statements, price lists, exported reports.
Two families of tables
Practically speaking, table PDFs fall into two families.
- Ruled tables — with visible horizontal and vertical lines. Easy. We detect the lines from the drawing operators and use them as cell boundaries.
- Whitespace tables — no lines, just aligned text. Hard. We infer column boundaries from statistical clustering on x-positions of text runs.
Ninety-five percent of invoices and bank statements are the second kind.
The whitespace algorithm
Our approach follows the general shape of Nurminen's 2013 method, refined in the pdftables literature and adapted for a browser runtime:
- Extract text runs with their bounding boxes via pdfjs.getTextContent().
- Sort runs by y-coordinate to group them into row candidates.
- For each row candidate, compute the histogram of run start-x positions across the page.
- Find peaks in the aggregated histogram — those are column boundaries.
- Snap each run to the nearest column, producing a rectangular matrix.
The output is a 2D array that we hand to SheetJS's xlsx library, which writes a valid .xlsx file. The whole pipeline is under 400 lines of code.
Where it fails
Nested tables (a table inside a cell) break the row-grouping step. Cells that span multiple rows or columns lose their span metadata. Diagonal headers become garbled. If your input is a Bloomberg-style report full of merged cells, no browser tool will save you.
For those cases we fall back to a per-page CSV export that preserves position but not structure. Users can then re-shape in Excel.
Try it
Drop a bank statement or invoice at /tools/pdf-to-excel and see what comes out. If the tables are clean, the workbook is instantly useful; if they are ornate, you have a starting point for manual clean-up that is still faster than typing.
Marek Novák
Engineering Lead at nctools
Keep reading
Engineering
OCR in the browser: how Tesseract.js and WebAssembly changed everything
A deep look at running the world's most-used open-source OCR engine at 200+ MB of trained models directly in a user's tab.
ReadEngineering
Client-side PDF extraction with pdfjs-dist: a deep dive
Mozilla's pdfjs-dist library powers every PDF reader on the web. Here is what it does well, where the sharp edges are, and how we build on top of it.
ReadEngineering
Building a zero-upload SaaS: architecture notes
How we structure a product where 90 percent of user activity never touches our server, and what that means for our monitoring, billing and support.
Read