AI CV Screening with Evidence-Based Scoring
n8n, DeepSeek, Gmail, Google Drive/27 nodes
Not deployed with a client, no usage metrics.
01
The problem
A staffing desk receives applications for one role from three or four different places. LinkedIn sends a notification email. Indeed sends its own. Some candidates email the jobs address directly. A careers page form drops into somewhere else again.
Nobody has a single list. The recruiter works through whatever is in front of them, and at two to three minutes per CV, a role with 200 applicants is roughly eight to ten hours of reading. That is arithmetic, not a measured figure, but it explains the pattern every recruiter recognises: the first forty CVs get read properly and the rest get skimmed.
The second problem is defensibility. When a hiring manager asks why a candidate was passed over, or a rejected candidate asks the same question, there is usually nothing written down.
02
The solution
One pipeline that accepts applications from every channel, reads every CV against the same requirements, and produces a score with the evidence attached. The recruiter still makes every decision. They start from a ranked list with reasoning instead of a folder of PDFs.
Screenshot 1 of 3
03
Architecture
Three entry points converge on one processing path.
Email intake
The Gmail trigger polls for unread mail with PDF attachments. A code node splits one item per attachment, since a single email can carry several CVs, and reads the sender domain to tag the source.
LinkedIn and Indeed send from noreply addresses, so those branches pull the applicant name from the subject line. The direct branch takes it from the From header. Processed mail is marked read so nothing is screened twice.
Webhook intake
The webhook accepts either a JSON payload with a CV link or a multipart upload with the PDF attached, and returns immediately rather than making the caller wait for scoring.
The shared path
Everything converges on a normalize step that produces one shape regardless of origin. A conditional branch handles the difference between a CV that arrived as an attachment and one that arrived as a link.
Output
Three exits. Shortlisted candidates are written to Google Drive as a JSON scorecard named score-first, so the folder sorts highest to lowest.
04
The AI component
One step uses a model: reading the CV text and judging it against the requirements. DeepSeek, temperature 0.1, fixed seed, with a JSON schema enforced through a structured output parser.
| Field | What it holds |
|---|---|
| Match score | The model's own number for how well the CV meets the stated requirements. |
| Summary | A short read on the candidate in plain language. |
| Requirement breakdown | Every requirement marked yes, partial, no or unclear, each with the supporting evidence. |
| Strengths | What the CV actually demonstrates. |
| Gaps | Requirements with nothing behind them. |
| Tenure flag | Raised when the employment history is worth a second look. |
Everything else is ordinary code. Fetching, extraction, redaction, scoring arithmetic, thresholds and routing. The model contributes judgement, the surrounding logic decides what happens with it.
05
What I changed from the starting template
The build started from a public n8n template that downloaded one CV from a hardcoded URL, sent it to OpenAI, and stopped.
- Fixed a real bug. The original URL-encoded the CV text before sending it, so the model received a blob full of escape sequences.
- Replaced single-file input with multi-channel intake, source detection and deduplication.
- Added redaction before scoring. Email, phone, LinkedIn URL, date of birth, lines mentioning nationality or marital status, and the candidate's own name are stripped. The model sees experience only.
- Rewrote the prompt to demand evidence. Every judgement must cite a line from the CV. Anything not stated is marked unclear rather than inferred.
- Added a second, non-model score.
- Added routing and error handling. Failures land in a review queue with a reason instead of vanishing.
- Added output. The original's results ended in a Set node and went nowhere.
Design decision worth defending
The score is calculated twice
A language model will return 85% and be unable to point at anything in the CV that supports it. So the score is calculated twice.
The model gives its number. Separately, code counts how many requirements it could actually evidence: met scores full, partial scores half, unclear or missing scores zero. The final score is 60% the model's opinion and 40% that count.
When the two numbers disagree by 25 points or more, the candidate is flagged for human review rather than auto-rejected. That is the model being confident about something it cannot substantiate, and it is exactly the case where a person should look.
06
Expected impact
Unmeasured. No live pipeline.
- Every application read against the same criteria, rather than the first forty getting attention
- A written reason attached to every outcome, requirement by requirement
- Intake consolidated across LinkedIn, Indeed, direct email and a careers page
- Assessment runs on experience, since identifying details are removed before scoring
- Uncertainty surfaced rather than hidden
Screening time does not disappear, it changes shape. Reading 200 CVs becomes reviewing a ranked list and checking the flagged cases.
07
Technical notes
- Structured output enforced through a JSON schema on the output parser
- Temperature 0.1 with a fixed seed, so the same CV scores the same twice
- Retries with backoff on the download and the model call
- Failures routed rather than thrown; a dead link or scanned PDF produces a review-queue record with a stated reason
- Parser handles reasoning-model think blocks and markdown fences, so the model is swappable without touching the pipeline
- Provider is two config fields; the workflow does not care which model answers
08
What I would add next
- Write outcomes to a sheet or ATS rather than Drive alone
- Store the original CV alongside the scorecard
- A weekly calibration report comparing scores against who actually got hired
- Per-requirement weighting, built in the follow-up project
- Batch throttling for high-volume days
Have a process worth automating?
Book a free 30 minute call. Talk me through the steps your team repeats every week and I will tell you what is worth automating and what should stay manual.