# ATS Verification Steps to Ensure Clean CV Text-Layer Extraction

> Learn essential ATS verification steps for clean CV text layer extraction. Ensure your resume passes with pdftotext, correct formatting, and accurate keyword placement. Maximize job applications now.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: how-to-guide
- Published: 2026-07-12

---

**To guarantee your CV passes Applicant Tracking Systems, extract the PDF text layer using `pdftotext -layout`, inspect for `(cid:*)` markers or replacement characters, confirm contact details appear as literal text, validate the reading order matches the visual layout, and verify keyword coverage without stuffing.**

When you compile a LaTeX CV to PDF, Applicant Tracking Systems (ATS) ignore the visual formatting and read only the embedded text layer. According to the `MadsLorentzen/ai-job-search` repository, a single corrupted glyph or misplaced text block can trigger automatic rejection. The repository defines a rigorous verification protocol in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) that ensures the extracted text is clean, searchable, and structurally sound.

## Extract the PDF Text Layer

The foundation of ATS verification begins with extracting the raw text content from your compiled PDF. In [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) lines 30-33, the repository specifies using `pdftotext -layout` to preserve the document's column alignment during extraction:

```bash
pdftotext -layout path/to/cv.pdf > cv_extracted.txt

```

The `-layout` flag maintains the spatial structure of the text, making it easier to detect reading-order problems that standard extraction might obscure. This output file serves as the ground truth for all subsequent verification steps.

## Detect Stray Glyph Codes

Font embedding errors manifest as cryptic glyph codes that break ATS parsing. According to [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) lines 31-34, you must verify the extraction contains **no `(cid:*)` markers** or `` replacement characters. These artifacts indicate that the PDF font subsetting failed, leaving the ATS unable to map character codes to readable text.

Run this diagnostic to catch these errors:

```bash
grep -nE '(cid:|)' cv_extracted.txt || echo "No stray glyphs found"

```

If the grep returns any matches, rebuild your PDF using different font embedding options or LaTeX packages before submitting to an ATS.

## Verify Literal Contact Information

Contact details must appear as **literal text** in the extraction, not as vector icons or hyperlink metadata. As documented in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) lines 33-35, email addresses and phone numbers hidden behind graphical elements or interactive PDF features are invisible to ATS parsers.

Validate contact visibility with:

```bash
grep -iE 'mailto:|@|[0-9]{3}[-. ][0-9]{3}[-. ][0-9]{4}' cv_extracted.txt \
  && echo "Contact info visible" || echo "Missing contact info"

```

Avoid using `\icon{phone}` or similar LaTeX constructs that render as untextifiable graphics.

## Validate Document Reading Order

The sequence of text in the extracted file must match the visual reading order. [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) lines 34-36 warn that multi-column layouts or floating text boxes can scramble the extraction, causing the ATS to read your sidebar before your job history.

Perform a quick sanity check on the extraction boundaries:

```bash
head -n 20 cv_extracted.txt   # Verify header content

tail -n 20 cv_extracted.txt   # Verify footer content

```

The repository recommends using single-column templates (such as the default `moderncv` style) to eliminate ordering ambiguities.

## Check Keyword Coverage Honestly

Keyword validation ensures your content aligns with the job posting without resorting to "stuffing." As noted in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) lines 35-36, you should verify that required terms are either present or honestly marked as absent, **never artificially stuffed** into the document.

Automate coverage validation against your target keywords:

```bash
while read -r kw; do
  if grep -iq "$kw" cv_extracted.txt; then
    echo "✔ $kw"
  else
    echo "✘ $kw (absent or needs honest note)"
  fi
done < keywords.txt

```

This loop provides reproducible evidence that your CV contains relevant terms naturally rather than through hidden text or excessive repetition.

## Document Verification Results

The final step requires marking each checklist item as passed or failed in your verification report. This documentation creates an audit trail proving the CV was validated against the [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) protocol before submission. Store the [`cv_extracted.txt`](https://github.com/MadsLorentzen/ai-job-search/blob/main/cv_extracted.txt) file and grep results alongside your source files for reference.

## Source Files and Pipeline

The verification process operates on outputs from specific source templates in the repository:

- **[`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md)**: Contains the complete Verification Checklist and ATS guidelines referenced above.
- **`cv/main_example.tex`**: Example LaTeX CV template compiled to PDF for verification.
- **`cover_letters/cover_example.tex`**: Companion cover letter template using the same PDF generation pipeline.

These files form the complete chain: LaTeX source → PDF compilation → `pdftotext` extraction → ATS verification.

## Summary

- **Extract with layout preservation**: Use `pdftotext -layout` to create a text representation that maintains structural alignment.
- **Hunt for glyph corruption**: Search for `(cid:*)` markers and `` characters that indicate font embedding failures.
- **Demand literal text**: Ensure emails and phone numbers appear as plain text, not icons or hyperlink metadata.
- **Verify sequential logic**: Confirm the text extraction order matches visual reading order using head/tail checks.
- **Validate honestly**: Check keyword presence against job requirements without stuffing artificial terms.
- **Create audit trail**: Document each verification step in a final report before submission.

## Frequently Asked Questions

### What is a `(cid:*)` marker and why does it break ATS parsing?

A `(cid:*)` marker appears when the PDF contains a Character ID that cannot be mapped to a Unicode character due to incomplete font subsetting. According to the [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) verification protocol, these markers render as unreadable codes in the text extraction, causing the ATS to see gibberish instead of your content. You must rebuild the PDF with proper font embedding to eliminate these artifacts.

### Why can't I use icons or hyperlinks for contact information?

ATS parsers extract only the raw text layer and do not execute PDF interactive features or render vector graphics. If your email or phone number is embedded behind a `\href` command or rendered as an icon font, the extraction will show nothing. The [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) checklist explicitly requires contact details to appear as **literal text** in the `pdftotext` output to ensure visibility.

### How does `pdftotext -layout` differ from standard PDF extraction?

The `-layout` flag instructs the tool to maintain the physical layout of the document, preserving whitespace and column alignment. Standard extraction might concatenate multi-column text into a single stream, destroying the logical reading order. For ATS verification, the layout option is essential to detect whether the text flow matches the visual structure, as specified in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) lines 30-36.

### Should I stuff keywords to pass ATS verification?

No. The verification protocol in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) lines 35-36 explicitly forbids keyword stuffing. Instead, run a grep-based check to confirm that terms from the job posting are either naturally present in your experience or honestly noted as absent. Artificially inserting keywords creates a poor candidate experience and may trigger anti-spam filters in modern ATS platforms.