DEV Community

Akbo Ichou
Akbo Ichou

Posted on

How an ATS Resume Checker Scores Your CV (and Why Developers Get Filtered Out)

Plenty of strong developers send dozens of applications and hear nothing back. Often the problem isn't skill — it's that the resume doesn't survive the applicant tracking system (ATS) or the recruiter's 10-second skim.

I built HireFlow, a free ATS resume checker with no signup, to make that invisible filtering visible. This post walks through how the scoring works, which is useful whether or not you ever use the tool.

An ATS score is really two questions

  1. Can the software read your resume? (parsing)
  2. Does what it reads match the job? (relevance)

A beautifully designed resume that fails question 1 never gets to question 2. So the checker scores them separately rather than blending everything into one opaque number.

The seven check groups

The checker groups its checks into categories, each producing specific, fixable findings:

  • ATS essentials — parseable text (not an image), standard fonts, no content trapped in headers/footers or tables, contact info present.
  • Resume sections — recognizable headings like Experience, Education, Skills.
  • Content quality — action verbs, quantified results, reasonable length.
  • Job tailoring — keyword overlap with a pasted job description.
  • Recruiter red flags — things that make a human skim past you.
  • Bias & gaps — employment gaps and details that invite bias.
  • Seniority & impact — whether the resume reads at the level you're applying for.

Keyword matching: exact phrases matter

A classic failure: the job says "Salesforce" and the resume says "CRM software". To a human that's close; to keyword matching it's a miss. The fix is to mirror the exact phrases from the posting where they're truthful.

A simplified version of the matching logic:

const normalize = (s: string) =>
  s.toLowerCase().replace(/[^a-z0-9+#.\s-]/g, " ").replace(/\s+/g, " ").trim();

export function keywordCoverage(resume: string, keywords: string[]) {
  const text = ` ${normalize(resume)} `;
  const hits = keywords.filter((k) => text.includes(` ${normalize(k)} `));
  return {
    score: keywords.length ? hits.length / keywords.length : 0,
    missing: keywords.filter((k) => !hits.includes(k)),
  };
}
Enter fullscreen mode Exit fullscreen mode

Note the character class keeps +, # and . — otherwise C++, C# and Node.js get mangled, which is a surprisingly common bug in resume tooling.

Parsing checks for developers specifically

Developer resumes break ATS parsing in predictable ways:

  • Two-column templates — text can be read across columns in the wrong order.
  • Skill bars and icons — "React ●●●●○" is meaningless to a parser.
  • Tech stacks as logos — images contain no text.
  • Contact details in the header — some parsers skip headers entirely.

Strong vs weak bullet points

Content quality checks look for impact over activity:

  • ❌ "Worked on the backend API."
  • ✅ "Cut p95 API latency from 800 ms to 180 ms by adding Redis caching to the pricing service."

The second one has an action verb, a metric and a technology keyword — everything both the ATS and the recruiter are looking for.

What a "good" score means

A score isn't a pass/fail gate, and different ATS products behave differently. It's most useful as a checklist: fix parsing problems first, then tailor keywords to each job, then sharpen impact statements.

Takeaways for your own resume

  • Use a single-column, text-based layout.
  • Mirror exact keywords from the job posting when they're true.
  • Quantify results.
  • Keep contact info in the body, not the header.

You can check your resume for free at hireflow.net — no signup. What's the most surprising resume feedback you've received?

Top comments (0)