How I built a job-application tracker that chases follow-ups
Never losing a lead in the pipeline — Northwind's hiring funnel finally has memory.
By Awadesh Madhogaria · Published Jul 12, 2025
Hiring at Northwind was never our problem. Following up was. We would reply to a genuinely strong applicant, get pulled into client work, and quietly let the thread go cold.
A week later that person had accepted an offer somewhere else. Nobody decided to lose them — we just forgot. Our hiring pipeline lived in a sheet, but it was a passive record: it told us who had applied; it never told us who we were neglecting. The failure pattern was always the same — a promising applicant replied with availability, we meant to schedule a call “this week”, the thread sank below the fold of the inbox, and they drifted or took another offer before we noticed. Each lost candidate meant restarting a search: more sourcing, more screening, more weeks with a seat empty.
I did not need a smarter pipeline. I needed one that would poke me. So I built the funnel a memory.
How it works
The fix started with a single column added to the Applicants sheet:
lastContacted. Every time we replied to a candidate, that date got updated,
and that one column turned a static list into something with a pulse. Then a
weekly script reads the sheet and emails me anyone who has gone silent for more
than seven days. The whole thing is one short function on a weekly trigger:
function chaseApplicants() {
const cutoff = Date.now() - 7 * 86400000;
const stale = readSheet('1abcApplicantsId')
.filter((a) => a.status === 'in-progress' && a.lastContacted < cutoff);
if (!stale.length) return;
GmailApp.sendEmail('[email protected]', stale.length + ' applicants need a nudge',
stale.map((a) => '• ' + a.name + ' (' + a.role + ')').join('\n'));
}
Read top to bottom, it does this:
- A weekly trigger fires the function — for us, Monday morning.
- It works out a cutoff date: seven days ago.
- It reads the
Applicantssheet and keeps only rows stillin-progressthat have not been contacted since the cutoff. - If nobody is stale, it sends nothing — no noise on a clear week.
- Otherwise it emails me a tidy bullet list of names and roles to chase.
That is the entire system. No dashboard, no app — just a list arriving in my inbox at the exact moment it is useful.
What I kept manual, and the side benefit
The script never emails a candidate directly. A follow-up to a person you want to hire should not read like an autoresponder, so the script flags and I write. It tells me who needs a nudge, and I decide what to say. The judgement stays with a human; only the remembering is automated.
The same lastContacted column turned out to measure something else worth
knowing — our average response time to applicants. Before the tracker, we were
closer to four days to first reply; now we are consistently under 36 hours.
Candidates notice that. A fast, attentive process is itself a hiring pitch — it
signals what working here is actually like.
A list that only records the past will let things rot. The fix was not a better tool — it was one date column and a script that asks, every week, “who have we forgotten?”