# Resume PDF reading order: columns, sidebars and text boxes

> A single-column resume read the same in pdf.js, pdftotext and our checker. Columns, sidebars and text boxes came back in different orders.

|  |  |
| --- | --- |
| Category | Original research |
| Published | October 19, 2026 |
| Reading time | 8 min |
| Rendered page | https://atsprep.com/blog/resume-pdf-reading-order-columns |
| This document | https://atsprep.com/blog/resume-pdf-reading-order-columns.md |

Reading order is the sequence in which an extractor hands your lines to the parser. A single-column resume came back identically in all three readers we tested. A two-column page, a left sidebar and a contact block in a text box each came back in at least two different orders from the same file. Our own checker used to read across columns; we fixed that on 20 October 2026 after these tests.

## The short version

- Single column: pdf.js, pdftotext and the ATSPrep checker returned the same lines in the same order.
- Two columns: pdf.js read column by column and pdftotext set the two headings side by side. Our checker used to interleave the lines and file the wrapped “Present” as the first bullet; we fixed both on 20 October 2026.
- Left sidebar: pdf.js and pdftotext read the whole sidebar first, so the name arrived on line 11.
- Contact text box: pdf.js returned the email and phone after the last bullet; our checker returned the email before the name.
- Greenhouse's own support page lists columned layouts and contact details in a text box as causes of a failed parse.

## Reading order by layout and reader

Each fixture holds the same name, contact line, role, three bullets, skills and education. Only the layout changes.

*The order each reader returned*

| Layout | pdf.js | pdftotext | ATSPrep checker |
| --- | --- | --- | --- |
| Single column | in order | in order | in order |
| Two columns | column by column | headings side by side | column by column |
| Left sidebar | sidebar first, name on line 11 | sidebar first, name on line 11 | main column first, then sidebar |
| Contact details in a text box | contact box last | contact box after the name | email before the name |
| Word two-column section (DOCX) | not a PDF | not a PDF | in order |
| The same section saved as PDF | column by column | column by column | column by column |

## Single column: one order everywhere

The single-column control came back line for line the same from all three readers: name, contact, heading, role, bullets, skills, education. That is the order a parser expects, and it is the order you wrote.

*Single column (the ATSPrep checker, order-single-column.pdf)*

```text
Maya Ortiz
maya.ortiz@example.com | (555) 010-4477 | Denver, CO
EXPERIENCE
Senior Data Analyst, Northwind Traders Inc. | 2021 - Present
• Cut weekly reporting time from 6 hours to 40 minutes by automating SQL pipelines
• Built a churn model that three regional sales teams now use to plan renewals
• Trained 12 analysts on dbt and code review
SKILLS
SQL, Python, Tableau, dbt, Excel
EDUCATION
B.S. Statistics, Lakeview University, 2018
```

## Two columns

PDF 32000 §14.8.2.3 (checked 19 October 2026) defines page content order as "determined by the sequencing of graphics objects within a page's content stream", and says that order "should normally (for Western writing systems) proceed from top to bottom (and, in a multiple-column layout, from column to column)". pdf.js follows the content stream, and Chromium wrote the left column first, so pdf.js read it cleanly.

pdftotext deliberately ignores the stream. Its manual says the default is to "'undo' physical layout (columns, hyphenation, etc.) and output the text in reading order", and with -raw it will "Keep the text in content stream order". On our page its reconstruction put SKILLS straight under EXPERIENCE and slotted single skills between the bullets.

Our checker used to group text by line position only, so it read across both columns: EXPERIENCE and SKILLS fused into one line, and each skill landed between bullet fragments. The date “2021 - Present” had wrapped in the narrow column, and the checker filed “Present” as the first bullet.

We fixed both on 20 October 2026 after these tests. The checker now looks for a clear gap that runs down the page between two blocks of text and reads one column at a time, and it puts a date end that wrapped onto its own line (“- Present”) back with the role. The text it shows still has “- Present” on a line of its own, because that is where the PDF put it.

*Two columns (pdftotext 26.10.0, order-two-column.pdf)*

```text
Maya Ortiz
maya.ortiz@example.com | (555) 010-4477 | Denver, CO
EXPERIENCE
SKILLS
Senior Data Analyst, Northwind Traders Inc. | 2021
- Present
SQL
• Cut weekly reporting time from 6 hours to 40
minutes by automating SQL pipelines
Tableau
• Built a churn model that three regional sales teams
now use to plan renewals
Excel
• Trained 12 analysts on dbt and code review
Python
dbt
EDUCATION
B.S. Statistics, Lakeview University, 2018
```

*Since the fix: two columns (the ATSPrep checker, order-two-column.pdf)*

```text
Maya Ortiz
maya.ortiz@example.com | (555) 010-4477 | Denver, CO
EXPERIENCE
Senior Data Analyst, Northwind Traders Inc. | 2021
- Present
• Cut weekly reporting time from 6 hours to 40
minutes by automating SQL pipelines
• Built a churn model that three regional sales teams
now use to plan renewals
• Trained 12 analysts on dbt and code review
SKILLS
SQL
Python
Tableau
dbt
Excel
EDUCATION
B.S. Statistics, Lakeview University, 2018
```

*After: the same content in one column (the ATSPrep checker, order-single-column.pdf)*

```text
Maya Ortiz
maya.ortiz@example.com | (555) 010-4477 | Denver, CO
EXPERIENCE
Senior Data Analyst, Northwind Traders Inc. | 2021 - Present
• Cut weekly reporting time from 6 hours to 40 minutes by automating SQL pipelines
• Built a churn model that three regional sales teams now use to plan renewals
• Trained 12 analysts on dbt and code review
SKILLS
SQL, Python, Tableau, dbt, Excel
EDUCATION
B.S. Statistics, Lakeview University, 2018
```

## Sidebars

A left sidebar is a narrow column that starts above the main one, so every reader that follows the page top-down meets it first. pdf.js and pdftotext both returned the full sidebar, contact details and skills, before the name, which came out on line 11. Our checker used to mix the two: it started with CONTACT, then alternated sidebar and body lines, and glued skills to the front of bullets.

Since our fix on 20 October 2026 the checker reads the two columns apart. It starts with the column that holds the name, set in the largest type, and reads the sidebar after it.

*Before: left sidebar (pdf.js 6.3.289, order-sidebar.pdf)*

```text
CONTACT
maya.ortiz@example.com
(555) 010-4477
Denver, CO
SKILLS
SQL
Python
Tableau
dbt
Excel
Maya Ortiz
Senior Data Analyst
EXPERIENCE
Senior Data Analyst, Northwind Traders Inc. | 2021 - Present
• Cut weekly reporting time from 6 hours to 40 minutes by automating
SQL pipelines
• Built a churn model that three regional sales teams now use to plan
renewals
• Trained 12 analysts on dbt and code review
```

*Since the fix: left sidebar (the ATSPrep checker, order-sidebar.pdf)*

```text
Maya Ortiz
Senior Data Analyst
EXPERIENCE
Senior Data Analyst, Northwind Traders Inc. | 2021 - Present
• Cut weekly reporting time from 6 hours to 40 minutes by automating
SQL pipelines
• Built a churn model that three regional sales teams now use to plan
renewals
• Trained 12 analysts on dbt and code review
CONTACT
maya.ortiz@example.com
(555) 010-4477
Denver, CO
SKILLS
SQL
Python
Tableau
dbt
Excel
```

## Text boxes

Our text-box fixture positions the email and phone in a box at the top right, written into the page after the body, which is how a floating box usually ends up in an export. Visually it sits beside the name.

Each reader put it somewhere different. pdf.js followed the stream and returned the contact details after the last bullet. pdftotext placed them after the name and title. Our checker returned the email first, then the name, then the phone, because the box sits a little higher on the page than the name's baseline. All three kept the text; none kept it where it appears. Our checker still filed the name, email and phone in the right fields.

*Before: contact details in a text box (pdf.js 6.3.289, order-text-box.pdf)*

```text
Maya Ortiz
Senior Data Analyst
EXPERIENCE
Senior Data Analyst, Northwind Traders Inc. | 2021 - Present
• Cut weekly reporting time from 6 hours to 40 minutes by automating SQL pipelines
• Built a churn model that three regional sales teams now use to plan renewals
• Trained 12 analysts on dbt and code review
maya.ortiz@example.com
(555) 010-4477
```

*Before: the same file (the ATSPrep checker, order-text-box.pdf)*

```text
maya.ortiz@example.com
Maya Ortiz
(555) 010-4477
Senior Data Analyst
EXPERIENCE
Senior Data Analyst, Northwind Traders Inc. | 2021 - Present
• Cut weekly reporting time from 6 hours to 40 minutes by automating SQL pipelines
• Built a churn model that three regional sales teams now use to plan renewals
• Trained 12 analysts on dbt and code review
```

## Word's two-column sections

Word's own columns (Layout, Columns, Two) flow text from the bottom of the left column to the top of the right. In the DOCX that flow is one sequence of paragraphs, and our importer read it perfectly: 8 roles, 24 bullets, 5 skills.

Exported to PDF by LibreOffice 26.8.1.1, pdf.js and pdftotext still read column by column. Our checker used to pair each left-column line with the right-column line beside it, starting with the name joined to a bullet. Since our fix on 20 October 2026 it returns the same lines as pdf.js and files the same 8 roles, 24 bullets and 5 skills as from the DOCX.

*DOCX with a two-column section (the ATSPrep checker, order-word-columns.docx)*

```text
Maya Ortiz
maya.ortiz@example.com | (555) 010-4477
EXPERIENCE
Senior Data Analyst, Northwind Traders Inc. | 2021 - Present
• Cut weekly reporting time from 6 hours to 40 minutes by automating SQL pipelines
• Built a churn model that three regional sales teams now use to plan renewals
```

*Since the fix: the same file as PDF (the ATSPrep checker, order-word-columns-pdf.pdf)*

```text
Maya Ortiz
maya.ortiz@example.com | (555) 010-4477
EXPERIENCE
Senior Data Analyst, Northwind Traders Inc. | 2021
- Present
[U+F0B7] Cut weekly reporting time from 6 hours to
```

## What ATS vendors say about columns and text boxes

Greenhouse is one of the few vendors that publishes its list. Its support article on unsuccessful parses (checked 19 October 2026) names "Resumes that have a columned layout" and "Resumes with the name and contact information in the header, footer, or text box". The fixtures above show the mechanism: the text is there, but the order it comes back in depends on the extractor.

## How to fix reading order

- Use one column for everything a parser fills in: name, contact details, job titles, employers, dates and bullets.
- Put contact details in the body as ordinary text under your name, not in a text box or a sidebar.
- List skills as a comma-separated line or short list under a SKILLS heading in the same column.
- Keep dates on the same line as the role, and make sure the line doesn't wrap at any width you export.
- Test the export in two readers. If both return your sections in the order you wrote them, the layout is doing its job.

## How we tested

We built every fixture from the same fictional one-page resume, changing one thing at a time. PDFs come from Chromium 153.0.8010.12 (printed through Playwright 1.63.0) and from LibreOffice 26.8.1.1 converting our DOCX files, the way Word users export. Each file was read three ways: pdf.js 6.3.289 getTextContent, poppler pdftotext 26.10.0 in its default mode, and the importer the ATSPrep checker runs in your browser. DOCX files have no PDF text layer, so only our importer reads them. The code blocks on this page are the readers' output, copied by script; private-use and control characters are written as [U+XXXX] because they would otherwise be invisible.

These are three common open readers, not any employer's applicant tracking system. Commercial parsers use their own extractors, so treat a failure here as a risk to remove, not a prediction of what a specific system will do.

## Common questions

### Does PDF text extraction keep columns in reading order?

Sometimes, and it depends on the extractor. On our two-column fixture pdf.js read column by column because it follows the PDF's content stream; pdftotext rebuilt the layout and set the two headings side by side. The ATSPrep checker used to read straight across both columns; since a fix on 20 October 2026 it reads them one at a time. A single column came back identically in all three.

### What is the reading order of a single-column resume PDF?

Top to bottom, exactly as written. Our single-column fixture returned name, contact line, EXPERIENCE, role, bullets, SKILLS and EDUCATION in that order from pdf.js, pdftotext and our checker.

### Is a sidebar resume ATS friendly?

It's a risk. In our test pdf.js and pdftotext read the whole sidebar before the name, and our checker interleaved sidebar and body lines until we fixed it on 20 October 2026. Other parsers won't all have that fix. Move contact details under your name and skills into the main column.

### Do applicant tracking systems read text boxes?

The text inside a text box usually extracts, but not where you put it. In our fixture pdf.js returned the boxed email and phone after the last bullet, pdftotext after the name, and our checker before the name. Greenhouse lists contact information in a text box as a cause of failed parses.

### How do I run a resume ATS text extraction test on a PDF or DOCX?

Read the file the way software does. For a PDF, copy all of its text into a plain-text editor, or run pdftotext resume.pdf - in a terminal, and check that each section comes back in order. For PDF or DOCX, the ATSPrep checker shows the lines its importer read, in order, in your browser.

## Sources and further reading

1. [PDF 32000-1:2008, §9.10 Extraction of Text Content and §14.8.2 Logical Structure](https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf), Adobe / ISO
2. [pdftotext(1) manual page, poppler-utils](https://manpages.debian.org/testing/poppler-utils/pdftotext.1.en.html), Debian
3. [PDFPageProxy.getTextContent, PDF.js API](https://mozilla.github.io/pdf.js/api/draft/module-pdfjsLib-PDFPageProxy.html), Mozilla
4. [Unsuccessful resume parse](https://support.greenhouse.io/hc/en-us/articles/200989175-Unsuccessful-resume-parse), Greenhouse Support
5. [Test fixture: order-two-column.pdf](/research/extraction-fixtures/order-two-column.pdf), ATSPrep
6. [Test fixture: order-sidebar.pdf](/research/extraction-fixtures/order-sidebar.pdf), ATSPrep
7. [Test fixture: order-text-box.pdf](/research/extraction-fixtures/order-text-box.pdf), ATSPrep
8. [Test fixture: order-word-columns.docx](/research/extraction-fixtures/order-word-columns.docx), ATSPrep
9. [Test fixture: order-word-columns-pdf.pdf](/research/extraction-fixtures/order-word-columns-pdf.pdf), ATSPrep

## Related

- [What happens when a PDF reader hits a two-column resume](https://atsprep.com/blog/two-column-resume-extraction-test.md)
- [Why columns and text boxes can scramble resume extraction](https://atsprep.com/blog/resume-columns-text-boxes-ats.md)
- [Tables in resumes: what PDF and DOCX text extraction returns](https://atsprep.com/blog/resume-tables-text-extraction.md)
- [Bullet characters and Unicode symbols in PDF resumes](https://atsprep.com/blog/pdf-resume-bullet-characters-unicode.md)
- [Resume headers and footers in PDF and DOCX text extraction](https://atsprep.com/blog/resume-header-footer-text-extraction.md)

## About ATSPrep

ATSPrep (https://atsprep.com) is a free resume and application workspace. Match experience to a posting, strengthen claims with evidence, and track the next action. Its PDF check shows text recovered by ATSPrep's extractor, not an employer's proprietary ATS or hiring decision.

- **Price:** free. Checking, importing, editing and downloading cost nothing, and downloads carry no watermark. Everything listed here is free.
- **Account:** none needed to check, import or edit a resume. A free sign-in is needed to download after the first file, to sync, and for more checks or more than 5 AI edits.
- **Your file:** parsed and exported inside the browser. The resume file itself is never uploaded.
- **Optional:** text leaves the browser only when you press a button: semantic match and AI edits (the lines involved), a job link (the link) and Pip voice calls (your speech). Never your contact details, and none of it is stored.
- **Connection:** some tools load on first use and need a connection to download. Local storage is not a cloud backup.
- **Accepts:** PDF, DOCX, TXT, Markdown, or pasted plain text.

Start here: https://atsprep.com/studio
