What actually breaks resume PDF extraction.
We generated 108 resume PDFs in 12 layouts and read each one back with the X-Ray's own code. The results, the data and the code are public.
Last updated 2026-07-31
The short version
Bad formatting rarely deletes your words. It moves them.
Pick a layout to see what PDF.js returned
PDF.js read backTwo columns, tight gutter
- Jordan Rivera EXPERIENCE (not a line the plain layout returned)
- Senior Backend Engineer Senior Backend Engineer, Northwind Systems (not a line the plain layout returned)
- jordan.rivera@example.com 2022 - Present (not a line the plain layout returned)
- 555-0142 - Migrated 47 services from virtual machines to Kubernetes across three (not a line the plain layout returned)
- Austin, TX (not a line the plain layout returned)
- regions. (not a line the plain layout returned)
- Words back
- 97.9%
- Order kept
- 83%
- Lines welded
- 33.1%
The same split with the gutter reduced to eight points.
Outside a scanned image, at least 96.9% of words always came back. What broke was order: in the tight two-column layout, 33.1% of lines fused two unrelated lines into one. And 3 of the 12 conditions changed nothing, including fancy bullets and very tight line spacing.
Method
Each PDF was built with pdf-lib from one of 9 synthetic profiles, so the intended text is known exactly. PDF.js read it back with the X-Ray's own line rules.
The four measures, defined
- Recovery: the share of intended words that came back at all.
- Order: longest-common-subsequence overlap with the intended reading order.
- Welding: the share of output lines fused from two unrelated source lines, counted only over words that appear once in the resume.
- Blocks: whether each bullet stayed under its own role.
Welding exists because recovery misses the failure: a two-column resume recovers 97.9% of its words and still reads as nonsense.
Line rules: a new line when the vertical gap exceeds 2.5 units, a space when the horizontal gap exceeds max(1.1, 0.22 × glyph height).
Full results
Most damaged first. Means across the 9 profiles.
| Condition | Recovery | Order | Welded | Blocks |
|---|---|---|---|---|
| Scanned or exported as an image | 0% | 0% | 0% | 0% |
| Letter-spaced headings | 96.9% | 96.9% | 0% | 100% |
| Whole document letter-spaced | 96.9% | 96.9% | 0% | 100% |
| Table-style grid | 97.6% | 93.4% | 24.1% | 100% |
| Two columns, tight gutter | 97.9% | 83% | 33.1% | 100% |
| Two columns | 97.9% | 83.6% | 30.5% | 100% |
| Words positioned without spaces | 99.8% | 99.8% | 0% | 100% |
| Contact detail in the page margins | 100% | 93.7% | 0% | 100% |
| Single column, plain textControl | 100% | 100% | 0% | 100% |
| Very tight line spacing | 100% | 100% | 0% | 100% |
| Rotated sidebar | 100% | 100% | 0% | 100% |
| Decorative bullet glyphs | 100% | 100% | 0% | 100% |
A scanned image has no text layer, so it is the only condition that loses the whole document.
The result we did not expect
Letter-spaced headings lose words. Drawing every line glyph by glyph lost no more (both 96.9%), so the extra spacing is the cause, not the splitting. Bigger spaced-out text is more fragile, which makes a spaced section heading the riskiest line on a resume.
The two conditions compared
per-character-tracking: Headings drawn one glyph at a time with extra tracking, which is how design tools apply letter spacing.
per-character-body: Every line, not only headings, drawn glyph by glyph. The space threshold scales with glyph height, which is why larger tracked text breaks first.
Get the data
All 108 rows, under CC BY 4.0. Reuse it, commercially too, and credit atsprep.com/research.
Versions, and how to rebuild it
Written by pdf-lib@1.17.1, read by pdfjs-dist@6.1.200, on node@24.13.0, 2026-07-31. Extraction changes between PDF.js releases, so the versions are part of the result.
The run is deterministic. The generator and runner live in scripts/research/; one command rebuilds every document and number:
node scripts/research/run-study.mjsIf you rerun it and get different numbers, we want to know.
What this does not show
- The 108 resumes are synthetic: controlled, with no personal data, but tidier than real ones.
- One reader, PDF.js. Employer systems use others and can behave differently.
- It measures extraction, not hiring. A clean read predicts no interview (see the methodology).
- Conditions were tested one at a time, never combined.
Written up in full
10 articles work through the data condition by condition, null results included.
- We generated 108 resume PDFs to find what breaks text extraction
- What happens when a PDF reader hits a two-column resume
- Resume tables under extraction: same problem, milder form
- Contact details in page margins: nothing lost, everything moved
- Letter-spacing shreds resume headings
- Resume bullet characters and ATS parsing
- How PDF text extraction actually works
- Why a scanned resume returns nothing at all
- Resume line spacing: what to use, and does ATS care?
- Resume formatting myths, measured
Run the same test on your own file.
The X-Ray reads your PDF with the same library and line rules, in your browser, and shows the text in the order it came back.
$0 forever · No watermark · No card · No account to start