[Workflow Included] CV Slack Assistant in n8n – drop a CV into Slack, get an instant structured summary

:waving_hand: Hey n8n Community,

A few weeks ago I built a Slack-based CV assistant for a friend’s recruiter, who was drowning in CVs of every imaginable format. Since it landed well, I cleaned it up and pushed it to the n8n template library: Summarize candidate CVs in Slack with easybits Extractor.

What it does:

Recruiter drops a CV (PDF, PNG, or JPG) into a dedicated Slack channel → bot downloads it → runs it through the easybits Extractor with 8 fields → posts a clean structured summary as a threaded reply in the same channel. No leaving Slack, no manual reading, no format guessing.

How it’s set up:

The trigger listens for new messages in the channel, ignores its own posts and anything without a file, checks the file type (PDF/PNG/JPG), downloads the private file with a bearer token, and sends the binary to the Extractor. The Extractor returns 8 structured fields, all with a “return null if not present” rule so the summary stays clean:

  • full_name
  • location
  • total_years_experience
  • top_skills (top 3 as short noun phrases)
  • last_three_roles (title, company, start, end)
  • education (degree, institution, year)
  • salary_expectations (verbatim string, not normalised)
  • linkedin_url

I also made a short video showing the workflow in action so you can see the recruiter flow end to end.

Want the Save-to-Sheet buttons too?

The template above also posts an interactive action card with Save to Sheet and Dismiss buttons under each summary. The workflow that handles those button clicks (appending the candidate to a Google Sheet, updating the card to “:white_check_mark: Saved by user”) is a separate n8n workflow, Slack interactivity needs its own webhook endpoint, so you can’t have the trigger and the button listener in the same workflow.

That second part is on my GitHub:

Together with 20 other workflows ranging from invoice classification and PO extraction through to more recruiting-side ones like this.

If any of these are useful, I’d hugely appreciate a :star: on the repo.

What other recruiter-side workflows are people building in n8n? Curious how far others have taken the ATS integration side of things.

Best,
Felix

1 Like

Nice workflow! I like that you kept everything inside Slack instead of forcing recruiters to switch between multiple tools.

One enhancement we’ve found valuable is adding a candidate deduplication step before processing. We generate a hash from the candidate’s email, phone number, or LinkedIn URL (when available) and check whether they’ve already been processed. That prevents duplicate summaries when recruiters accidentally upload the same CV multiple times.

Another useful addition is a fit score against the job description. Instead of just extracting fields, compare the candidate’s skills and years of experience with the role requirements and return something like:

  • Match Score: 86%
  • Missing Skills: Kubernetes, Terraform
  • Strong Matches: Python, AWS, Docker

We’ve also found it helpful to automatically tag candidates (e.g., Backend, Frontend, DevOps, Data, Product) and route them to different Slack channels or ATS queues based on those tags.

Finally, I’d add confidence scores for each extracted field. If confidence is low or key fields like name or experience are missing, flag the CV for manual review instead of automatically saving it.

Overall, this is a clean example of using n8n for recruitment automation without making the workflow overly complex. I can see this saving recruiters a lot of time.

2 Likes

Solid pattern, especially the null-if-not-present rule keeping the summary clean. On the ATS side: the piece that tends to bite people going further is duplicate-candidate detection before the Save to Sheet step - same person applying twice (different file name, updated CV) creates duplicate rows otherwise. A cheap fix is normalizing the extracted email/phone and doing a lookup in the Sheet before inserting; if found, update in place and note “resubmission” instead of appending. Also worth webhook-verifying the Slack interactivity payload signature if this is public-facing, since button click endpoints are an easy spot to overlook auth on.

1 Like

Hey @shedrach, first of all, thank you so much for the kind words and the thoughtful feedback!

I completely agree that adding a deduplication step earlier in the workflow makes sense. Right now, I only have it in the second part of the workflow (which you’ll find on my GitHub), where the recruiter decides whether to save the candidate to a spreadsheet or push them directly into the ATS.

The friend I built this for chose the direct ATS integration. In practice, the recruiter simply clicks a “Send to ATS” button in Slack. That triggers a short deduplication check to see whether the candidate already exists. If not, the candidate is created in the ATS, and many of the features you mentioned are handled there automatically. Since I’m also uploading the original CV, the ATS immediately labels the candidate based on the most suitable department. From there, the recruiter can compare the profile against current openings and see a fit score directly within the ATS.

That said, I think your suggestions would be a great addition for users who don’t have an ATS. They’re definitely worth considering for a v2 of the workflow.

Regarding confidence scoring, I handle that a little differently. I usually integrate this workflow:

It sends a Slack alert whenever an extraction fails, which is how I typically roll out workflows during the onboarding phase. That way, both the user and I get notified immediately if something needs attention.

I actually have a question for you as well. I’m currently talking to a client who wants to review an existing candidate database manually through Slack. My initial idea was to create separate Slack channels for each job description, since they currently have fewer than 10 open positions. Do you think that’s granular enough, or would you structure it differently? I’d love to hear your thoughts.

Hey @nguyenthieutoan, thank you so much for the feedback!

You’re absolutely right. Deduplication is something I’ve already implemented further down the workflow, but after reading your and @shedrach’s comment, I think it makes much more sense to move it closer to the beginning. That way, duplicate candidates can be identified and flagged right away before they go through the rest of the process.

1 Like

For under 10 open roles, a channel per JD works but gets noisy fast once positions close and reopen. I would use one #candidate-review channel with a message per candidate, and a thread per JD instead of full channels. Add a short prefix to each message like [Backend Dev] or [Sales] so people can scan without opening every thread. Slack’s built in search plus the prefix tag gives you filtering without the overhead of creating and archiving channels every time a role opens or closes.

1 Like

Hey @nguyenthieutoan, thank you so much for the feedback! That sounds like a great approach. I’ll definitely give it a try. I also feel that having a separate Slack channel for every single position would add unnecessary complexity, so your suggestion seems like a much cleaner and more scalable solution.