How ATS Verification Extracts and Validates PDF Text Layers with pdftotext: A 3-Step Implementation
The ATS verification utility in the MadsLorentzen/ai-job-search repository validates PDF text layers by invoking pdftotext with the -layout flag, normalizing whitespace, and enforcing checks for minimum character counts and required text substrings.
The ai-job-search repository provides a robust ATS (Applicant Tracking System) verification tool that ensures generated PDFs contain machine-readable text layers essential for automated resume parsing. Located in tools/verify_pdf.py, this utility leverages Poppler utilities—specifically pdftotext and pdfinfo—to validate that PDF documents meet specific content and structure requirements before submission to ATS platforms.
The Three-Step Verification Pipeline
The verification process implemented in tools/verify_pdf.py follows a strict three-step pipeline to guarantee PDF accessibility. Each step utilizes external Poppler command-line tools invoked through a unified helper function.
Step 1: Page Count Validation with pdfinfo
First, the script validates document length using the external pdfinfo command. The run_tool helper function executes this binary and captures its output. The parse_page_count function then extracts the integer value following the Pages: line. If the caller provides an expected_pages argument, the actual count is compared against this value, and a VerificationError is raised immediately upon mismatch.
Step 2: Text Layer Extraction Using pdftotext
For ATS readability, the core extraction relies on pdftotext executed with the -layout flag. This flag preserves the physical layout structure, which improves parsing accuracy for resume formats. The run_tool function invokes pdftotext -layout <pdf> -, outputting the raw text stream to stdout. This approach ensures that even complex multi-column PDFs yield coherent text extraction suitable for automated screening systems.
Step 3: Content Validation and Normalization
Once extracted, the raw text undergoes processing through normalize_text, which collapses consecutive whitespace characters into single spaces. This normalization makes string matching resilient against layout variations.
The validation then performs two critical checks:
- Minimum character verification: The normalized text length is compared against the
min_charsparameter (defaulting to 1). If the extracted content falls short, aVerificationErrorsignals that the PDF lacks a proper searchable text layer. - Required text verification: When provided via the
required_textparameter or--containsCLI flag, each specified string is normalized and verified as a substring of the extracted content. Missing entries trigger aVerificationError.
Error Handling and Reporting
All validation failures funnel through the custom VerificationError exception class. The main entry point catches these exceptions at lines 94-96, reporting failures to stderr with descriptive messages. Successful verification prints a concise confirmation message: Verified <pdf>.
Command-Line and Programmatic Usage
The tool supports both CLI invocation and direct Python integration.
Command-line usage allows quick verification with page counts, character minimums, and required text strings:
python -m tools.verify_pdf \
resume.pdf \
--pages 2 \
--min-chars 100 \
--contains "Professional Experience" \
--contains "your.email@example.com"
For integration into larger workflows, import the verify_pdf function directly:
from pathlib import Path
from tools.verify_pdf import verify_pdf, VerificationError
pdf_path = Path("resume.pdf")
try:
verify_pdf(
pdf_path,
expected_pages=2,
min_chars=100,
required_text=("Professional Experience", "your.email@example.com")
)
print("PDF passed ATS verification")
except VerificationError as exc:
print(f"Verification failed: {exc}")
Testing the Verification Logic
The test suite in [tests/test_verify_pdf.py](https://github.com/MadsLorentzen/ai-job-search/blob/master/tests/test_verify_pdf.py) mocks the external pdfinfo and pdftotext commands to validate each logic branch. These unit tests ensure the verification pipeline behaves correctly regardless of whether the underlying Poppler utilities are installed on the system, covering edge cases such as missing text layers and page count mismatches.
Summary
- The
tools/verify_pdf.pyscript validates PDFs for ATS compatibility using Poppler utilitiespdfinfoandpdftotext. - Page count validation uses
pdfinfooutput parsed byparse_page_countto verify document length againstexpected_pages. - Text extraction runs
pdftotext -layoutto preserve formatting while extracting searchable text layers. - Content validation enforces minimum character requirements via
min_charsand verifies the presence of required text substrings after whitespace normalization. - The custom
VerificationErrorexception provides unified error handling for all validation failures, caught and reported by the main entry point. - Comprehensive unit tests in
tests/test_verify_pdf.pymock external dependencies to ensure reliability without requiring actual PDF tool installations.
Frequently Asked Questions
What is pdftotext and why is it used for ATS verification?
pdftotext is a command-line utility from the Poppler suite that converts PDF documents to plain text. The ai-job-search repository uses it specifically because it reliably extracts hidden text layers from PDFs, which is essential for verifying that resumes remain machine-readable by Applicant Tracking Systems that cannot parse image-based or scanned documents.
How does the tool handle PDFs with missing text layers?
If a PDF contains no extractable text layer, pdftotext returns minimal or empty output. The normalize_text function processes this result, and the subsequent min_chars check (defaulting to 1 character) fails, raising a VerificationError. This ensures that image-only PDFs or improperly exported documents are flagged before submission to ATS platforms.
Can I verify multiple PDFs at once using the CLI?
The current implementation in tools/verify_pdf.py processes a single PDF path per invocation. To batch-process multiple files, you would need to wrap the CLI call in a shell loop or script that iterates through your PDF directory, invoking python -m tools.verify_pdf for each document individually.
What happens if pdfinfo or pdftotext is not installed?
The run_tool helper function executes these external commands via subprocess. If either pdfinfo or pdftotext is missing from the system PATH, the subprocess call will fail and raise an exception. The test suite mitigates this dependency by mocking these external tools, but production usage requires installing the Poppler utilities package (typically poppler-utils on Linux/Unix systems).
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →