Making your resume readable by screening software
35 min · Intermediate
Need help? Ask a tutor on WhatsApp (opens in a new tab)A recruiter types "Python" into the search box over 800 applications. A resume that the software reads in the wrong order, or as a picture, never shows up. Interviewers also ask why you built yours this way.
How applicant tracking systems commonly parse resumes
An ATS (applicant tracking system) is software that stores job applications, pulls out fields such as name, skills and education from each resume, and lets recruiters search and filter them.
Parsing means turning your file into plain text and guessing which text is your name, contact details, education and skills. Here is a clean resume and what a typical tool extracts from it.
Example 1 · What a parser extracts
ANANYA RAO+91 90000 00000 | ananya.rao.dev@gmail.com | github.com/ananya-raoEDUCATIONB.Tech CSE, ABC Institute of Technology 2022 - 2026 CGPA 8.1/10SKILLSLanguages: Python, SQL | Libraries: pytest | Tools: Git, MySQLname: Ananya Rao phone: +91 90000 00000 email: ananya.rao.dev@gmail.com degree: B.Tech CSE graduation: 2026 skills: Python, SQL, pytest, Git, MySQL
What this code does
- A clean single-column resume with standard headings maps neatly to fields. The exact fields and their names depend on the tool.
- Recruiters later search these fields, for example skills containing "Python" and graduation year 2026.
Recruiters then search those fields, for example "Python AND pytest", or filter by degree and graduation year. Behaviour varies a lot by tool and by company settings, and many tools also show the original file to the recruiter. So the goal is to make the text easy to extract and the facts easy to find, not to "beat" a machine.
What is common and what varies:
- Common: text extraction, section detection by headings, keyword search, filters on degree, year and location.
- Varies: how tables, columns, headers, footers and icons are handled, and whether scores rank candidates.
- Myth to ignore: "a secret score rejects 75% of resumes". No published data backs this, and tool settings differ by company.
Simple layouts: avoid tables, images and columns that break parsing
A single-column layout puts every section one below the other in one column, so a parser reads it top to bottom in the right order. Two columns, tables and text boxes can be read out of order.
Some parsers read straight across the page, joining the two columns line by line. This program does that to a two-column resume, then reads the same text as one column.
Example 2 · How a two-column layout can scramble
left = ["SKILLS", "Python, SQL", "pytest", "MySQL, Git"]right = ["PROJECTS", "Online Store API", "- Built 20+ operations", "- Salted password hashes"]
print("Reading row by row across both columns:")for left_text, right_text in zip(left, right): print(left_text, right_text)print()print("Reading a single-column layout:")for line in left + right: print(line)Reading row by row across both columns: SKILLS PROJECTS Python, SQL Online Store API pytest - Built 20+ operations MySQL, Git - Salted password hashes Reading a single-column layout: SKILLS Python, SQL pytest MySQL, Git PROJECTS Online Store API - Built 20+ operations - Salted password hashes
What this code does
- Some extractors read straight across the page, joining the two columns line by line. Skills and project lines then merge into nonsense such as "pytest - Built 20+ operations".
- This is a simplified model; many modern parsers handle columns, but not all. A single column removes the risk for free.
A single column is read in the right order by almost every parser. Two-column designs, tables, text boxes and contact details placed in the page header or footer can be read out of order or skipped by some tools, so your skills may end up mixed with your project lines. Images hold no text for a parser: a skill-logo row, an icon for the phone number or a photo of text are simply invisible.
A safe layout:
- Use: one column, standard headings, plain bullets and text dates like "May 2025 - Jul 2025".
- Avoid: tables for layout, text boxes, two columns, icons instead of words, contact info only in the header area.
- Fonts: common ones (Calibri, Arial, Times New Roman); fancy fonts can turn into wrong characters.
Using job-description keywords honestly
A keyword is a skill, tool or job title that a recruiter searches for, such as Python, SQL or Git. If a skill is true for you, write it in the job description's spelling.
This program counts how often each job-description keyword appears in a resume, whole words only, so "SQL" does not match inside "MySQL".
Example 3 · Keyword coverage, counted honestly
import re
def count(text, keyword): pattern = r"(?<![A-Za-z])" + re.escape(keyword) + r"(?![A-Za-z])" return len(re.findall(pattern, text, re.IGNORECASE))
resume = """Skills: Python, SQL, MySQL, Git, pytestOnline Store API: built 20+ operations in Python with MySQL.Wrote pytest tests; used Git for every change."""jd_keywords = ["Python", "SQL", "pytest", "MySQL", "Microservices", "Docker"]
for keyword in jd_keywords: n = count(resume, keyword) print(f"{keyword}: {n}" + (" (missing: add only if true)" if n == 0 else ""))Python: 2 SQL: 1 pytest: 2 MySQL: 2 Microservices: 0 (missing: add only if true) Docker: 0 (missing: add only if true)
What this code does
- The pattern is case-insensitive and refuses letters right before or after the keyword, so "SQL" does not count inside "MySQL".
- Two or three honest mentions (skills line plus a project bullet) are plenty. Missing keywords are a to-learn list, not words to paste in.
Keyword stuffing means pasting the whole job description, hiding white text or repeating "Python" twenty times. A human spots it quickly and it can get you rejected, because many tools show the recruiter the text exactly as extracted. Two or three honest mentions, in the skills line and in a project bullet where you used the skill, are plenty.
File naming, and PDF vs DOCX
A text PDF is a PDF exported from an editor such as Word or Google Docs, so its text can be selected and copied. A scanned PDF is only a picture of paper, with no text for a parser to read.
A recruiter may download 200 files in one day. These before-and-after names show how to make yours clear, small and safe for portals.
Example 4 · File names: before and after
resume.pdfResume_final_FINAL (2).pdfscan0012.pdf (a photo of a printed resume)ananya@resume#2026!.docxAnanya_Rao_Resume.pdf Ananya_Rao_Resume.pdf Ananya_Rao_Resume.pdf (exported from the editor, so it has real text) Ananya_Rao_Resume.docx (only when the portal asks for Word)
What this code does
- A name-based file name helps the recruiter who downloads 200 files named
resume.pdf. - A scan has no selectable text, so a parser sees nothing. Always export from the editor instead of scanning a printout.
PDF keeps your layout exactly and most portals accept it; a text PDF exported from Word or Google Docs parses well. A scanned PDF (a photo of paper) has no text at all. DOCX is safest when a portal or company asks for Word format; follow the instructions on the application page whenever they exist. Keep the file well under 1 MB and avoid special characters in its name.
The plain-text copy test
The plain-text copy test is a quick self-check: open your PDF, select all, copy and paste into a plain text editor such as Notepad. What you see is roughly what a parser gets.
The program below automates part of the test. It reads the pasted text and lists what a parser would miss.
Example 5 · The plain-text copy test, automated
import re
def problems(pasted): found = [] if not re.search(r"\+91[ 0-9]{10,}", pasted): found.append("phone number missing or not as text") if "@" not in pasted: found.append("email missing") first_education = pasted.find("EDUCATION") first_skills = pasted.find("SKILLS") if first_education < 0 or first_skills < 0 or first_education > first_skills: found.append("sections out of order or missing") for ch in pasted: if ch == "�" or "" <= ch <= "": found.append(f"strange symbol U+{ord(ch):04X} (icon font or bad character)") break return found
good = "ANANYA RAO\n+91 90000 00000 | ananya.rao.dev@gmail.com\nEDUCATION\nB.Tech CSE\nSKILLS\nPython"bad = "ANANYA RAO\n ananya.rao.dev\nSKILLS\nPython\nEDUCATION\nB.Tech CSE"for label, text in (("good", good), ("bad", bad)): result = problems(text) print(f"{label}:", "; ".join(result) if result else "no problems")good: no problems bad: phone number missing or not as text; email missing; sections out of order or missing; strange symbol U+E0B0 (icon font or bad character)
What this code does
- The bad paste is what an icon-heavy two-column template often gives: the phone was an icon plus a picture, the email lost its
@, and the private-use characterU+E0B0is an icon font glyph. - Paste your own PDF text into the
goodstring to try it. The checks are simple on purpose; reading the pasted text yourself is still the real test.
Check four things: the order of the sections is right, nothing is missing (contact details, icons, a skills table), bullets and dates look normal, and there are no strange symbols. If the text is jumbled, simplify the layout and test again.
What to look for in the pasted text:
- Order: name and contact first, then your sections in your order.
- Completeness: phone, email and links present as text.
- Characters: no boxes, question marks or merged words.
- Next step: try the portal's own "autofill from resume" and correct what it gets wrong.
Next step
Check your understanding
12 quick questions