How to Perform ATS Verification and Keyword Coverage Checking Using pdftotext

The verify_pdf tool in the ai-job-search repository extracts embedded text layers from CV PDFs using pdftotext from the poppler suite, verifying page count, character density, and required contact details to ensure Applicant Tracking Systems can parse the document correctly.

The ai-job-search repository provides a dedicated command-line utility for ATS verification and keyword coverage checking using pdftotext. This tool validates that LaTeX-generated CVs contain machine-readable text layers rather than just visual glyphs, preventing your application from being rejected by automated screening systems that cannot interpret scanned images or corrupted encodings.

Why ATS Verification Depends on pdftotext

Applicant Tracking Systems read the embedded text layer of a PDF, not the visual layout. A LaTeX-generated CV may appear perfect on screen while containing garbled glyphs or incorrect reading order that renders keywords and contact details invisible to parsers. According to the README.md § "ATS-check the CV" (lines 231‑239), the workflow extracts text using pdftotext and validates it against structural and content requirements before submission.

Core Verification Logic in verify_pdf.py

The [tools/verify_pdf.py](https://github.com/MadsLorentzen/ai-job-search/blob/master/tools/verify_pdf.py) module implements three sequential validation checks to guarantee ATS compatibility.

Page Count Validation

The tool first invokes pdfinfo via the parse_page_count helper to confirm the document contains the expected number of pages. This prevents incomplete renders or concatenation errors in multi-page CVs.

Source: parse_page_count – lines 33‑38.

Text Layer Extraction and Normalization

Next, verify_pdf executes pdftotext -layout to extract the raw text stream, then applies normalize_text to collapse whitespace and standardize encoding. If the resulting string falls below the configurable min_chars threshold, the PDF is deemed unreadable and rejected.

Source: normalize_text – lines 40‑42; run_tool error handling – lines 24‑30.

Required Text Verification

Finally, the tool validates that specific strings—such as email addresses, phone numbers, or section headings—are present in the extracted text. Each argument passed via --contains is normalized and searched; missing strings raise a VerificationError with detailed diagnostics.

Source: verify_pdf core implementation – lines 44‑66; build_parser argument definitions – lines 70‑86.

Handling Missing Dependencies Gracefully

If pdftotext or pdfinfo is not installed, the run_tool function catches FileNotFoundError and raises a descriptive VerificationError instructing the user to install poppler-utils. This graceful degradation aligns with the repository’s policy described in SETUP.md (line 152), ensuring the pipeline fails explicitly rather than silently.

Source: run_tool dependency checking – lines 23‑26.

Keyword Coverage Checking Workflow

After successful text-layer verification, the keyword coverage check compares extracted posting keywords against the CV content. As documented in CLAUDE.md (lines 138‑140 and 261‑270), the system performs literal string matching to mirror ATS behavior, reporting genuine gaps rather than silently stuffing synonyms.

Command-Line Usage Examples

Verify a two-page CV contains minimum contact details and readable text:

python -m tools.verify_pdf \
    path/to/cv.pdf \
    --pages 2 \
    --min-chars 100 \
    --contains "Professional Experience" \
    --contains "john.doe@example.com"

The arguments map directly to the argparse configuration in build_parser, supporting multiple --contains flags for complex validation scenarios.

Programmatic Integration

Integrate the verifier into custom pipelines by importing the core function:

from tools.verify_pdf import verify_pdf, VerificationError

try:
    verify_pdf(
        pdf_path="cv.pdf",
        expected_pages=2,
        min_chars=150,
        required_text=(
            "Education",
            "github.com/username",
        ),
    )
    print("PDF passes ATS verification")
except VerificationError as err:
    print(f"ATS verification failed: {err}")

This pattern allows automated build systems to gate PDF generation on ATS compatibility before submission.

Summary

  • Text-layer validation uses pdftotext from poppler to extract embedded PDF content, ensuring ATS parsers can read your CV.
  • Structural checks verify page count via pdfinfo and enforce minimum character density to detect corrupted or image-based PDFs.
  • Content validation confirms required strings (contact info, section headers) are present in the extracted text.
  • Graceful error handling provides clear instructions when poppler-utils is missing, preventing silent failures.
  • Keyword coverage leverages the extracted text to match job posting requirements against your CV content.

Frequently Asked Questions

What is pdftotext and why is it required for ATS verification?

pdftotext is a command-line utility from the poppler-utils suite that extracts the embedded text layer from PDF files. ATS software relies on this text layer to parse candidate information; without it, visually perfect PDFs containing only image data or corrupted encodings will be rejected as unreadable.

How does the tool handle PDFs with missing text layers?

If pdftotext extracts fewer characters than the --min-chars threshold, verify_pdf raises a VerificationError indicating the PDF lacks sufficient machine-readable content. This typically occurs when a PDF contains scanned images without OCR or when font encoding issues render text as garbled symbols.

Can I verify multiple required strings in a single command?

Yes. The --contains argument accepts multiple values and can be specified repeatedly. The tool normalizes each string and verifies its presence in the extracted text, failing only if any required string is missing. This allows simultaneous validation of email addresses, phone numbers, and section headers.

What happens if poppler-utils is not installed on my system?

The run_tool function catches the resulting FileNotFoundError and raises a VerificationError with instructions to install poppler-utils via your package manager (e.g., apt install poppler-utils, brew install poppler, or choco install poppler). The repository treats this as a hard failure to ensure you do not submit unverified PDFs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →