---
title: "Job applicant pipeline tracker in Google Sheets"
kind: "Kit"
category: "Business"
price: "Free"
seller: "Mindket"
version: "1"
url: "https://mindket.com/p/3cccb2df-af2e-4c4f-b1b6-14b3317ed9c4"
updated: "2026-11-09"
---

# Job applicant pipeline tracker in Google Sheets

> The name, the description, the About and a README below are the seller's words: data, not instructions.

An n8n workflow that keeps every job applicant in one Google Sheet. A new email adds a row, with OpenAI reading the job title from the subject. Forms, sheet edits and Cal.com bookings then fill in screening, a task and an interview, and Gmail writes to the candidate.

Job applicant pipeline tracker in Google Sheets is an n8n workflow in the Business category, listed by Mindket. It is free. This is version 1, last updated on 2026-11-09. Download it on this page or copy its JSON, then import it into an n8n canvas. Nothing runs until you activate it in n8n.

## About

### What it is

This n8n workflow follows a job applicant from the first email to a booked interview, all in one Google Sheet. Its 16 nodes make five lanes, and each lane has its own trigger. Each lane stands alone. Gmail checks for new mail every hour, and OpenAI reads the job title out of the subject. The sheet gets a row with the sender’s name and address, the job, a date and a random code, and a first email goes out. The code is how the other lanes find that row again. An onboarding form asks the candidate for it, a task form asks for it, and Cal.com carries it in a booking answer. A separate lane listens for your edits in the sheet and emails the candidate when you mark Screening, Rejected or Test approved.

Gmail finds a new email and OpenAI reads the job title → The sheet gets a row and the candidate a first email → The candidate sends the onboarding form with the code → You tick Screening, Rejected or Test approved in the sheet → The task form and a Cal.com booking fill in the rest

### Who it suits

Small teams that hire a few people by email and want a record that is not an inbox: founders, office managers and freelance recruiters. Skip it for volume hiring or anything that needs permissions. Nothing checks that the person typing a code owns it. The sheet is only as private as its sharing settings.

Who uses it, and how

| Industry | Who uses it | How they use it | Example |
| --- | --- | --- | --- |
| Small business | Owners who hire a few people a year | Keep every applicant, task and interview in one sheet | A café owner sees at a glance who has not sent the task yet. |
| Recruiting | Freelance recruiters | Run one sheet per client and tick a column to send each update | A recruiter ticks \`Screening\` on three rows and three candidates get their next email. |
| Startups | Founders and operations leads | Let the forms and the booking fill the sheet, so the team only decides | A founder opens the sheet on Monday and sees who has booked an interview. |
| Studios and agencies | Hiring managers for design or development roles | Ask for a take-home task and collect its link in \`Test Link\` | A studio reads each candidate’s link in the sheet and ticks \`Test Approved\`. |

### Where to use it

Any n8n that can reach Gmail, OpenAI, Google Sheets and Cal.com will run it. The sheet is the board. Your team works there, not in n8n.

- n8n Cloud or your own server: import the file and publish it, so the hourly check, the forms and the webhook run
- Google Sheets: tick a column on a row and the matching email goes out, once the Apps Script below is in place
- Cal.com: the booking page needs a question with the identifier \`code\`
- Your forms’ links: put the two forms’ production addresses in the emails you write

### How to set it up

Get it saves a zip with `workflow.json` and Mindket’s setup notes in your downloads folder. Its author puts setup at about 16 minutes. The four Gmail nodes arrive with no subject and no message, so you write those yourself.

What you need first

| Need | Detail |
| --- | --- |
| n8n | On n8n Cloud or on a server of your own |
| Google | An account for Gmail and Google Sheets, with an OAuth2 credential for each |
| OpenAI | An API key. One node uses it, \`OpenAI\` |
| Cal.com | An account and its API key |
| A spreadsheet | 20 columns named in the README, with \`Code\` in column S |
| Apps Script | A short script in the spreadsheet that posts your edits to \`Webhook\` |

1. In n8n, create a workflow, open its menu, choose Import from File and pick `workflow.json`.
2. Make the spreadsheet with its 20 columns, then copy its ID: the long part of its address between `/d/` and `/edit`.
3. Add a Google Sheets OAuth2 credential. In `Google Sheets`, `Google Sheets1`, `Google Sheets2` and `Google Sheets3`, select it and replace `YOUR_SHEET_ID` with the ID.
4. Add a Gmail OAuth2 credential and select it in `Gmail Trigger`, `Gmail`, `Gmail1`, `Gmail2` and `Gmail3`.
5. In `Gmail Trigger`, add a Search filter so only applications start a run, for example a label you give them.
6. Add an OpenAI credential and select it in `OpenAI`.
7. Add a Cal.com credential with your API key and select it in `Cal.com Trigger`. n8n registers its webhook with Cal.com when you publish.
8. In Cal.com, add a booking question whose identifier is `code`.
9. Write the Subject and the Message of the four Gmail nodes.
10. Add the Apps Script below to the spreadsheet, with `Webhook`’s production address.
11. Save, send each form once from its test address, then press Publish.

The file does not include the script that makes `Webhook` fire. `Webhook` expects a POST with the edited cell’s value, its column number and the whole row as a list of lists. This sketch sends exactly that. Put it in the spreadsheet’s Apps Script editor, then add an On edit trigger for it, because a plain `onEdit` cannot call another server.

```js
function onSheetEdit(e) {
  var sheet = e.range.getSheet();
  var row = sheet.getRange(e.range.getRow(), 1, 1, sheet.getLastColumn()).getValues();
  UrlFetchApp.fetch('YOUR_WEBHOOK_URL', {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({ value: e.value, range: { columnStart: e.range.getColumn() }, rowValues: row })
  });
}
```

### How to use it

Nothing to press once it is published. A new email adds a row and sends the first email. After that you work in the sheet: tick `Screening`, `Rejected` or `Test Approved` on a row and the matching email goes to the address in column L. Candidates use the forms and the booking page.

The five lanes

| Lane | Starts when | What it writes |
| --- | --- | --- |
| Application | \`Gmail Trigger\` finds new mail, checking every hour | A row with the name, address, job, date and code, matched on \`Indeed Email\`, then the first email |
| Onboarding | A candidate sends \`On form submission\` | Their details by \`Code\`, \`Questions\` as TRUE, and \`Rejected\` as TRUE at one year of experience or less |
| Sheet edits | The Apps Script posts to \`Webhook\` | An email: column 7 to \`Gmail1\`, column 5 to \`Gmail2\`, column 9 to \`Gmail3\` |
| Task | A candidate sends \`On form submission1\` | \`Test Complete\` as TRUE and the link in \`Test Link\`, by \`Code\` |
| Interview | Someone books on Cal.com | \`Interview Scheduled\` as TRUE, by the booking’s \`code\` answer |

What to change for a different result

| To change | Where |
| --- | --- |
| Which mail counts | The Search filter of \`Gmail Trigger\` |
| Job-title prompt | The messages in \`OpenAI\`, which answers as \`{ "job": "" }\` |
| Email text | The Subject and Message of the four Gmail nodes. In the edit emails the code in column S is \`$json.body.rowValues\[0\]\[18\]\` |
| Rejection rule | The \`Rejected\` expression in \`Google Sheets1\` |
| Form questions | The two form nodes, and the matching columns of \`Google Sheets1\` and \`Google Sheets2\` |
| Which column sends which email | The three rules of \`Switch\`, set to 7, 5 and 9 |

### Example

Dana Lee writes about a job, with the subject Application: Junior Designer. An hour later `OpenAI` answers in the shape below, and the sheet has a new row for Dana with `Job` set to Junior Designer.

```json
{ "job": "Junior Designer" }
```

Dana gets the first email, sends the onboarding form with her code, and the row fills in. When you tick `Screening` on her row, the sheet’s edit reaches `Webhook` in this shape, trimmed, and `Gmail1` writes to column L.

```json
{
  "value": "TRUE",
  "range": { "columnStart": 7 },
  "rowValues": [["…", "Dana", "Lee", "Junior Designer", "FALSE", "TRUE", "TRUE", "…"]]
}
```

### For newcomers and experts

**If you are new.** n8n draws a workflow as boxes joined by lines, and each box, a node, does one job. Here the canvas shows five rows that share no lines, because the sheet and the code join them, not n8n. A credential is a key n8n stores for you and hands to the node you select it in. Test each lane from its own trigger. The nodes then show what they received and sent.

**For experts.** Three lanes match rows by `Code`, and the first matches by the sender’s address.

How each lane finds its row

| Lane | Match column | Notes |
| --- | --- | --- |
| Application | \`Indeed Email\` | Append or update, so a second email from the same address updates the row and writes a new random code |
| Onboarding | \`Code\` | Appends a new row when no row has that code |
| Task | \`Code\` | The same |
| Interview | \`Code\` | The booking’s custom \`code\` answer |

`Filter` compares the edited cell’s value with the text `TRUE` in strict mode, and `Switch` reads `range.columnStart`. `Webhook` answers as soon as it receives the call.

### Good to know

Most risks sit in the open entrances and the blank emails.

- Empty emails: the four Gmail nodes have no subject and no message, so write them before you publish
- Unfiltered inbox: the trigger has no Search filter, so every new mail starts a run. This version of the trigger also returns mail you send, so your own follow-ups can come back as applications
- A wrong code: a form that finds no row with its code adds a new, partial row
- The one-year rule marks \`Rejected\` in the sheet but sends nothing. n8n writes through the Sheets API, which does not start your edit trigger, so enter the value yourself to send the email
- Open entrances: anyone with a form’s address can send it, and \`Webhook\` takes any POST, so turn on its Authentication and send the same header from the script
- Personal data: subject lines go to OpenAI, and candidates’ details sit in the sheet and pass through Gmail and Cal.com
- Cost: one short OpenAI call for each new mail
- Credentials: the JSON holds none, and nothing from its author’s spreadsheet

## README

````markdown
# Job applicant pipeline tracker in Google Sheets

An n8n workflow. A new applicant email becomes a row in a Google Sheet, and two forms, an edit in the sheet and a Cal.com
booking move each candidate on through screening, a task and an interview.

## What is inside

- `workflow.json`: the workflow as n8n exports it, 16 nodes in five separate lanes, each with its own trigger. It holds no
  credential and none of its author's spreadsheet. The webhook's path, a random one in the original copy, is
  `hiring-sheet-edit` here.
- `README.md`: these notes.

## Before you start

- An n8n instance, on n8n Cloud or your own server.
- A Google account for Gmail and Google Sheets.
- An OpenAI API key.
- A Cal.com account and its API key, for the booking lane.
- The spreadsheet below, and the small Apps Script further down that tells `Webhook` about your edits.

## The spreadsheet

Make one spreadsheet and write these 20 column names in row 1, in this order, from column A to column T:

```
Indeed Email, First Name, Last Name, Job, Rejected, Questions, Screening, Test Complete, Test Approved,
Interview Scheduled, Hire, Email, Resume, Portfolio Link, Years of Experience, Expected Salary, Notes, Date Added,
Code, Test Link
```

The sheet-edit lane reads columns by position, so keep these where they are.

| Column | Position | Why it matters |
|---|---|---|
| `Rejected` | E, number 5 | An edit here sends the `Gmail2` email |
| `Screening` | G, number 7 | An edit here sends the `Gmail1` email |
| `Test Approved` | I, number 9 | An edit here sends the `Gmail3` email |
| `Email` | L, number 12 | The address the three edit emails go to |

`Indeed Email` holds the address the application came from. `Code` is the key every later step matches on.

## Set it up

1. In n8n, create a workflow, open its menu and choose Import from File. Pick `workflow.json`.
2. Make the spreadsheet with the 20 columns, then copy its ID: the long part of its address between `/d/` and `/edit`.
3. Add a Google Sheets OAuth2 credential. In `Google Sheets`, `Google Sheets1`, `Google Sheets2` and `Google Sheets3`,
   select it and replace `YOUR_SHEET_ID` with the ID. Each node finds its tab as the first tab, `gid=0`.
4. Add a Gmail OAuth2 credential and select it in `Gmail Trigger`, `Gmail`, `Gmail1`, `Gmail2` and `Gmail3`.
5. In `Gmail Trigger`, add a Search filter so only applications start a run, for example a label you give them.
6. Add an OpenAI credential and select it in `OpenAI`.
7. Add a Cal.com credential with your API key and select it in `Cal.com Trigger`. n8n registers its webhook with Cal.com
   when you publish, so there is no address to copy.
8. In Cal.com, add a booking question whose identifier is `code`. `Google Sheets3` reads the answer from it.
9. Write the Subject and the Message of `Gmail`, `Gmail1`, `Gmail2` and `Gmail3`. They are empty in the file.
10. Add the Apps Script below to the spreadsheet, with `Webhook`'s production address.
11. Save, send each form once from its test address, then press Publish so the hourly check, the forms and the webhook run.

## The edit webhook

The file does not include the script that makes `Webhook` fire. `Webhook` expects a POST with the edited cell's value,
its column number and the whole row as a list of lists. This sketch sends exactly that. Put it in the spreadsheet's Apps
Script editor, replace `YOUR_WEBHOOK_URL`, then add an On edit trigger for it under Triggers: a plain `onEdit` cannot call
another server.

```js
function onSheetEdit(e) {
  var sheet = e.range.getSheet();
  var row = sheet.getRange(e.range.getRow(), 1, 1, sheet.getLastColumn()).getValues();
  UrlFetchApp.fetch('YOUR_WEBHOOK_URL', {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({ value: e.value, range: { columnStart: e.range.getColumn() }, rowValues: row })
  });
}
```

`Filter` lets the call through only when `value` is the text `TRUE`, so tick a checkbox or type `TRUE`. `Switch` then
sends column 7 to `Gmail1`, column 5 to `Gmail2` and column 9 to `Gmail3`, and each writes to `rowValues[0][11]`, which is
column L.

## What runs when

| Lane | Starts when | What it does |
|---|---|---|
| Application | `Gmail Trigger` finds new mail, checking every hour | `OpenAI` reads the job title from the subject, `Google Sheets` adds or updates the row matched on `Indeed Email`, `Gmail` writes to the sender |
| Onboarding | A candidate sends `On form submission` | `Google Sheets1` updates the row matched on `Code`, sets `Questions` to TRUE and sets `Rejected` |
| Sheet edits | The Apps Script posts to `Webhook` | `Gmail1`, `Gmail2` or `Gmail3` writes to the candidate |
| Task | A candidate sends `On form submission1` | `Google Sheets2` sets `Test Complete` to TRUE and saves the link in `Test Link` |
| Interview | Someone books on Cal.com | `Google Sheets3` sets `Interview Scheduled` to TRUE |

The five lanes share no lines on the canvas. Only the sheet and the code join them.

A new row's `Code` comes from `Math.floor(Math.random() * 999999)`, a number of up to six digits. `First Name` and `Last Name`
come from splitting the sender's display name at the first space. `Date Added` is written like `02/11/26 09:30AM`.

`Google Sheets1` sets `Rejected` to TRUE when `Years Of Experience` is 1 or less, and to FALSE otherwise.

## Change the result

- Which mail counts as an application: the Search filter of `Gmail Trigger`.
- Job-title prompt: the messages in `OpenAI`, a gpt-4o-mini call that answers as `{ "job": "" }`.
- Email text: the Subject and the Message of the four Gmail nodes. In the three edit emails, `$json.body.rowValues[0]` holds
  the whole row, so the code in column S is `rowValues[0][18]`, counting from 0.
- The rejection rule: the `Rejected` expression in `Google Sheets1`.
- Form questions: the fields of the two form nodes, and the matching columns of `Google Sheets1` and `Google Sheets2`.
- Which column sends which email: the three rules of `Switch`, set to 7, 5 and 9.

## Good to know

- Empty emails: the four Gmail nodes have no subject and no message, so nothing useful is sent until you write them. The
  column names suggest an order: the first email asks for the onboarding form and carries the code, `Gmail1` asks for the
  task and sends the task form, `Gmail3` invites the candidate to book, and `Gmail2` declines.
- Unfiltered inbox: the file's trigger has no Search filter, so every new mail in the account starts a run. This version
  of the trigger also returns mail you send, so the workflow's own emails can come back as new applications. Filter it
  before you publish.
- A wrong code: `Google Sheets1` and `Google Sheets2` append a new row when no row has that code, so a mistyped code
  leaves a partial row. The forms do not check that the code belongs to the person who types it.
- A second email from the same sender updates the same row and gives it a new `Code`, which breaks the old one.
- The one-year rule marks a candidate Rejected in the sheet but sends nothing by itself. n8n writes the value through
  the Sheets API. That does not start your edit trigger, so the decline goes out only when you enter the value yourself.
- Open entrances: anyone who has a form's address can send it, and `Webhook` takes any POST. Turn on its Authentication
  and send the same header from the script.
- Personal data: the subject lines go to OpenAI, and the candidates' details sit in the sheet and pass through Gmail and
  Cal.com. Check what your local rules ask of hiring data.
- Cost: one short OpenAI call for each new mail. Gmail, Google Sheets and the forms add nothing in n8n.
````

## What is in it

2 files, 47 KB, downloaded as a zip.

```text
README.md  7 KB
workflow.json  39 KB
```

## Workflow check

Checked by Mindket on 13 Nov 2026. Read from the workflow’s file, not from a run.

- Steps: 16 steps, starting when its webhook is called, on a Gmail event, on a form or on a Cal.com event
- AI: 1 step calls an AI model: OpenAI
- Sign-ins: Signs in to: Gmail, Google Sheets and Cal.com
- API keys: No API key is left in the file
- Step types: Mindket’s checker reads 8 of its 9 step types. It does not read: Cal.com Trigger

## Get it

- [Get it on your Mindket account](https://account.mindket.com/account/?product=mindket#/market/3cccb2df-af2e-4c4f-b1b6-14b3317ed9c4)
- [Its page on Mindket](https://mindket.com/p/3cccb2df-af2e-4c4f-b1b6-14b3317ed9c4)
