DEV Community

DEUS Automations
DEUS Automations

Posted on

Why Most "AI Resume Builders" Produce PDFs That Fail ATS Parsers

If you've ever run your own resume through an ATS (Applicant Tracking System) parser and watched
your job title or bullet points come out garbled, you've hit a problem that has nothing to do with
your content and everything to do with how the PDF was built.

The root cause: PDF is a layout format, not a text format

A PDF doesn't store "a paragraph followed by another paragraph." It stores absolute-positioned
glyphs on a page. Most polished-looking resume templates get that layout from HTML+CSS rendered
through a headless browser (Puppeteer/Chromium), which is great for visual fidelity and terrible
for text order: multi-column layouts, sidebars, and floated elements often get flattened in
reading order that has nothing to do with visual order. An ATS parser reads the underlying text
stream top-to-bottom, left-to-right in insertion order — so a two-column template can silently
interleave your work history with your skills list, or drop your most recent job title into the
middle of a bullet point.

What actually fixes it

Two things matter more than template beauty:

  1. Build the PDF with a low-level drawing API, not a browser. Libraries like pdfkit let you place text in the exact order you write it in code — single-column templates render sidebar accents as decoration (colored rectangles, icons) that never enter the text stream, so the parser only ever sees the real content, in the real order.
  2. Always keep a resume-only fallback path. If you're generating resume content with an LLM (turning raw notes into structured bullet points, for example), the model call will eventually fail or time out. A parser that falls back to a deterministic, rule-based structuring of the same raw input — instead of failing the whole request — means the user still gets a correct, ATS-safe PDF even when the AI provider has a bad day.

A concrete example

I ended up building this into CV Forge, a small AI resume generator: raw notes
go in, an LLM (OpenAI-compatible, tested against Groq's Llama 3.3 70B) turns them into a structured
CV JSON, and pdfkit renders it with a single-column-first "Compact" template designed to stay
ATS-safe, alongside two more visual templates for when you're sending directly to a human. If the
AI call fails, a local parser produces the same structured JSON so the PDF still comes out
correctly formatted.

The lesson generalizes past resumes: any time you're generating a PDF that a machine will read
back
, decide before picking a rendering approach whether text-stream order matters as much as
visual layout. If it does, skip the headless browser and reach for a library that lets you control
the text stream directly.

Top comments (0)