This workflow corresponds to n8n.io template #13104 — we link there as the canonical source.
This workflow follows the Gmail → Gmail Trigger recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "0xugVH7Fxq8N9-RQiDPnw",
"name": "AI job application tracker and interview prep assistant",
"tags": [
{
"id": "dK4BDm3KhXP6KKmp",
"name": "AI",
"createdAt": "2026-01-29T01:52:31.750Z",
"updatedAt": "2026-01-29T01:52:31.750Z"
},
{
"id": "ZBrBt6NFsk8YYyHQ",
"name": "Productivity",
"createdAt": "2026-01-29T18:28:46.563Z",
"updatedAt": "2026-01-29T18:28:46.563Z"
},
{
"id": "nvYdDZDOvQ2pkTxp",
"name": "Job Search",
"createdAt": "2026-01-29T18:28:46.536Z",
"updatedAt": "2026-01-29T18:28:46.536Z"
}
],
"nodes": [
{
"id": "ebc3b9c8-f70c-42eb-b1a9-6f8ee2cdfb8c",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-672,
0
],
"parameters": {
"width": 420,
"height": 996,
"content": "## AI Job Application Tracker & Interview Prep Assistant\n\n### How it works\nThis workflow helps you stay organized during your job search by automatically tracking applications and preparing you for interviews with AI-powered research.\n\n1. **Submit application** via form or forward confirmation email\n2. **Auto-extract** job details (company, role, requirements)\n3. **Generate interview prep** including likely questions and talking points\n4. **Track in Notion** with visual pipeline and follow-up reminders\n\n### Setup steps\n1. Create a Notion database with required properties (see template below)\n2. Configure OpenAI API credentials\n3. Set up Gmail/Email trigger for forwarded applications\n4. Customize the interview prep prompt for your background\n5. Test with a sample job posting URL\n\n### Required Notion properties\n- Company (Title)\n- Role (Text)\n- Status (Select: Applied, Interviewing, Offer, Rejected)\n- Applied Date (Date)\n- Salary Range (Text)\n- Job URL (URL)\n- Company Research (Text)\n- Interview Prep (Text)\n- Follow Up Date (Date)\n- Notes (Text)"
},
"typeVersion": 1
},
{
"id": "23ea1e1f-afed-49e4-9227-e2bbd00563e7",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-208,
128
],
"parameters": {
"color": 7,
"width": 268,
"height": 604,
"content": "### \ud83d\udce5 Input Methods\nTwo ways to add applications:\n1. **Manual form** - paste job URL\n2. **Email forward** - forward confirmation emails"
},
"typeVersion": 1
},
{
"id": "bc82466f-648d-4bed-b7b5-03dac64d5051",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
848,
256
],
"parameters": {
"color": 7,
"width": 488,
"height": 388,
"content": "### \ud83d\udd0d Data Extraction\nExtracts job details from URL or email content using AI"
},
"typeVersion": 1
},
{
"id": "6afb9c45-ba8b-43b8-a396-0b20f31e30bb",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1456,
256
],
"parameters": {
"color": 7,
"width": 296,
"height": 452,
"content": "### \ud83c\udfaf Interview Prep\nAI generates customized questions and talking points"
},
"typeVersion": 1
},
{
"id": "73ea0e1b-9df1-4270-b65d-391e407f8660",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1792,
224
],
"parameters": {
"color": 7,
"width": 712,
"height": 484,
"content": "### \ud83d\udcca Tracking & Alerts\nSaves to Notion and schedules follow-up reminders"
},
"typeVersion": 1
},
{
"id": "4d3ed59b-c091-4fde-ba19-92ef58efd151",
"name": "Receive Job Application Form",
"type": "n8n-nodes-base.webhook",
"position": [
-144,
336
],
"parameters": {
"path": "job-application",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "7766a013-158c-43b3-bfd8-35934722ee97",
"name": "Check for Forwarded Applications",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
-144,
544
],
"parameters": {
"filters": {
"readStatus": "unread"
},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
}
},
"typeVersion": 1
},
{
"id": "09e40c45-7e27-43f0-9c82-d182f634892d",
"name": "Route by Input Source",
"type": "n8n-nodes-base.switch",
"position": [
128,
464
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "From Form",
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.body?.jobUrl }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"outputKey": "From Email",
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.textPlain }}",
"rightValue": ""
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3
},
{
"id": "428b76c6-2a09-4de5-9645-d5add52c3eb2",
"name": "Scrape Job Posting URL",
"type": "n8n-nodes-base.httpRequest",
"position": [
512,
224
],
"parameters": {
"url": "=https://r.jina.ai/{{ $json.body.jobUrl }}",
"method": "POST",
"options": {
"response": {
"response": {
"responseFormat": "text"
}
}
}
},
"typeVersion": 4.2
},
{
"id": "68013cd7-40cf-4d82-85c5-eb59cb46f269",
"name": "Extract Job Details with AI",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
896,
480
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini",
"cachedResultName": "GPT-5-MINI"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "=You are a job application data extractor. Extract structured information from job postings or application confirmation emails. This is your source {{ $('Scrape Job Posting URL').item.json.data }}\n\nAlways respond with valid JSON only, no markdown or explanation. "
},
{
"content": "Extract the following information from this content:\n\n{{ $json.data || $json.textPlain }}\n\n---\n\nRespond with this exact JSON structure:\n{\n \"company\": \"Company name\",\n \"role\": \"Job title\",\n \"location\": \"City, State or Remote\",\n \"salaryRange\": \"Salary range if mentioned, or 'Not specified'\",\n \"jobType\": \"Full-time/Part-time/Contract\",\n \"requirements\": [\"Key requirement 1\", \"Key requirement 2\", \"Key requirement 3\"],\n \"responsibilities\": [\"Main responsibility 1\", \"Main responsibility 2\"],\n \"benefits\": [\"Benefit 1\", \"Benefit 2\"],\n \"applicationDeadline\": \"Date if mentioned, or null\",\n \"companyDescription\": \"Brief company description from posting\"\n}"
}
]
}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.7
},
{
"id": "181e69fd-c26b-476f-8cd3-88aa9cbe35ea",
"name": "Parse and Structure Job Data",
"type": "n8n-nodes-base.code",
"position": [
1200,
480
],
"parameters": {
"jsCode": "/*\n * Parse AI Response to Structured Data\n * =====================================\n * Purpose: Takes the AI's response (which is text/JSON) and converts it\n * into clean, structured data that other nodes can use.\n * \n * Input: Raw AI response containing job details as JSON text\n * Output: Clean job object with company, role, dates, etc.\n * \n * \u2699\ufe0f CONFIGURATION\n * ----------------\n * DAYS_UNTIL_FOLLOWUP: Change this number to set when you want\n * to be reminded to follow up (default: 7 days)\n */\n\nconst DAYS_UNTIL_FOLLOWUP = 7; // \u2190 Change this to adjust follow-up timing\n\n// ==================== CODE START ====================\n\n/*\n * STEP 1: Get the data from the previous node\n * -------------------------------------------\n * $input.first() = gets the first item from the previous node\n * .json = accesses the JSON data inside that item\n */\nconst input = $input.first().json;\n\n/*\n * STEP 2: Parse the AI response\n * -----------------------------\n * The AI returns text that looks like JSON, but it's actually a string.\n * We need to convert it to a real JavaScript object we can work with.\n * \n * Sometimes the AI wraps its response in ```json``` markdown blocks,\n * so we need to clean those out first.\n */\nlet jobData;\n\ntry {\n // Check if the AI response is a string (most common case)\n if (typeof input.message?.content === 'string') {\n \n /*\n * Clean up the response:\n * - Remove ```json at the start\n * - Remove ``` at the end\n * - Remove extra whitespace\n */\n const cleanJson = input.message.content\n .replace(/```json\\n?/g, '') // Remove opening code block\n .replace(/```\\n?/g, '') // Remove closing code block\n .trim(); // Remove extra spaces\n \n // Convert the clean string to a JavaScript object\n jobData = JSON.parse(cleanJson);\n \n } else {\n /*\n * If it's already an object (rare), use it directly.\n * The || input part is a fallback if message.content doesn't exist.\n */\n jobData = input.message?.content || input;\n }\n \n} catch (error) {\n /*\n * ERROR HANDLING\n * --------------\n * If something goes wrong (bad JSON, unexpected format), \n * we return an error object instead of crashing the workflow.\n * \n * This lets you see what went wrong in the n8n execution log.\n */\n return [{\n json: {\n error: true,\n message: 'Failed to parse AI response',\n rawResponse: input.message?.content // Include raw response for debugging\n }\n }];\n}\n\n/*\n * STEP 3: Add metadata and dates\n * ------------------------------\n * Now we enrich the job data with tracking information:\n * - When we applied\n * - When to follow up\n * - Current status\n * - Link to the original job posting\n */\n\n// Get today's date\nconst today = new Date();\n\n// Calculate follow-up date (today + DAYS_UNTIL_FOLLOWUP)\nconst followUpDate = new Date(today);\nfollowUpDate.setDate(followUpDate.getDate() + DAYS_UNTIL_FOLLOWUP);\n\n/*\n * STEP 4: Return the final structured data\n * ----------------------------------------\n * We combine:\n * - ...jobData = all the fields extracted by AI (company, role, etc.)\n * - appliedDate = today's date in YYYY-MM-DD format\n * - followUpDate = when to send follow-up email\n * - status = initial status is always \"Applied\"\n * - jobUrl = the original URL (from form) or note that it came from email\n * \n * The $('Node Name') syntax lets us reference data from other nodes.\n */\nreturn [{\n json: {\n ...jobData, // Spread operator: includes all AI-extracted fields\n \n // Format dates as YYYY-MM-DD (e.g., \"2025-01-29\")\n appliedDate: today.toISOString().split('T')[0],\n followUpDate: followUpDate.toISOString().split('T')[0],\n \n // Default status for new applications\n status: 'Applied',\n \n // Get the job URL from the form input, or note it came from email\n jobUrl: $('Receive Job Application Form').first().json.body?.jobUrl || 'From email'\n }\n}];\n\n// ==================== CODE END ====================\n\n/*\n * EXAMPLE OUTPUT\n * --------------\n * This node will output something like:\n * \n * {\n * \"company\": \"Acme Corp\",\n * \"role\": \"Software Engineer\",\n * \"location\": \"Remote\",\n * \"salaryRange\": \"$120k - $150k\",\n * \"requirements\": [\"JavaScript\", \"React\", \"Node.js\"],\n * \"appliedDate\": \"2025-01-29\",\n * \"followUpDate\": \"2025-02-05\",\n * \"status\": \"Applied\",\n * \"jobUrl\": \"https://acme.com/careers/123\"\n * }\n * \n * TROUBLESHOOTING\n * ---------------\n * - If you see \"Failed to parse AI response\": Check the AI node's output\n * in the execution log. The AI might have returned an unexpected format.\n * \n * - If dates look wrong: Make sure your n8n instance timezone is correct.\n * \n * - To change follow-up timing: Edit DAYS_UNTIL_FOLLOWUP at the top.\n */"
},
"typeVersion": 2
},
{
"id": "217da761-bf2a-49c0-8878-e26cda22f3ba",
"name": "Generate Interview Prep Materials",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1488,
480
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini",
"cachedResultName": "GPT-5-MINI"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "You are a career coach helping job seekers prepare for interviews. Provide actionable, specific insights."
},
{
"content": "Based on this job posting and company research, prepare interview materials.\n\n## Job Details\n- Company: {{ $json.company }}\n- Role: {{ $json.role }}\n- Requirements: {{ $json.requirements?.join(', ') || 'Not specified' }}\n- Responsibilities: {{ $json.responsibilities?.join(', ') || 'Not specified' }}\n\n## Company Research\n{{ $('Research Company Online').first().json.data?.substring(0, 3000) || 'No additional research available' }}\n\n---\n\nProvide:\n\n### 1. LIKELY INTERVIEW QUESTIONS (5-7 questions)\nBased on the role requirements, what questions will they probably ask?\n\n### 2. SUGGESTED TALKING POINTS\nWhat specific experiences or skills should the candidate emphasize?\n\n### 3. QUESTIONS TO ASK THEM\n3-5 thoughtful questions that show genuine interest and research.\n\n### 4. COMPANY CULTURE INSIGHTS\nBased on the research, what's the company culture like? Any red flags or positives?\n\n### 5. SALARY NEGOTIATION NOTES\nAny insights on compensation, benefits, or negotiation leverage?\n\nBe specific and actionable. Avoid generic advice."
}
]
}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.7
},
{
"id": "d3379d59-2726-4bf6-94e3-b28f62a58491",
"name": "Save Application to Notion",
"type": "n8n-nodes-base.notion",
"position": [
1840,
480
],
"parameters": {
"options": {},
"resource": "databasePage",
"databaseId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 2.2
},
{
"id": "93f28549-ddf1-4098-a66a-bb3b6f2033be",
"name": "Prepare Success Response",
"type": "n8n-nodes-base.set",
"position": [
2064,
480
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "summary",
"name": "summary",
"type": "string",
"value": "=\u2705 Application tracked!\n\n**{{ $('Parse and Structure Job Data').first().json.company }}** - {{ $('Parse and Structure Job Data').first().json.role }}\n\n\ud83d\udccd {{ $('Parse and Structure Job Data').first().json.location }}\n\ud83d\udcb0 {{ $('Parse and Structure Job Data').first().json.salaryRange }}\n\ud83d\udcc5 Follow up: {{ $('Parse and Structure Job Data').first().json.followUpDate }}\n\nInterview prep materials have been saved to Notion."
}
]
}
},
"typeVersion": 3.4
},
{
"id": "1d980032-5214-4949-9bc8-206c74927bdb",
"name": "Send Confirmation Response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2288,
384
],
"parameters": {
"options": {},
"respondWith": "text",
"responseBody": "={{ $json.summary }}"
},
"typeVersion": 1.1
},
{
"id": "d0609dfe-2952-46e2-ab3a-7c4522738518",
"name": "Send Email Confirmation",
"type": "n8n-nodes-base.gmail",
"position": [
2288,
576
],
"parameters": {
"sendTo": "={{ $('Check for Forwarded Applications').first().json.from?.value?.[0]?.address }}",
"message": "=Your application has been added to the tracker!\n\n**Company:** {{ $('Parse and Structure Job Data').first().json.company }}\n**Role:** {{ $('Parse and Structure Job Data').first().json.role }}\n**Location:** {{ $('Parse and Structure Job Data').first().json.location }}\n**Salary:** {{ $('Parse and Structure Job Data').first().json.salaryRange }}\n\n\ud83d\udcc5 **Follow up reminder set for:** {{ $('Parse and Structure Job Data').first().json.followUpDate }}\n\n---\n\n## Interview Prep Generated:\n\n{{ $('Generate Interview Prep Materials').first().json.message?.content?.substring(0, 1500) }}...\n\n*(Full prep materials saved in Notion)*",
"options": {},
"subject": "\u2705 Job Application Tracked: {{ $('Parse and Structure Job Data').first().json.company }}"
},
"typeVersion": 2.1
},
{
"id": "022a632d-992d-41f9-8af2-6f49987f51ed",
"name": "Daily Follow-up Check",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
80,
-192
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
}
]
}
},
"typeVersion": 1.2
},
{
"id": "3fd3087c-4657-473e-b79f-4234a093c0bf",
"name": "Get Applications Due for Follow-up",
"type": "n8n-nodes-base.notion",
"position": [
288,
-192
],
"parameters": {
"options": {},
"resource": "databasePage",
"operation": "getAll",
"databaseId": {
"__rl": true,
"mode": "list",
"value": ""
},
"filterType": "manual"
},
"typeVersion": 2.2
},
{
"id": "67bbeef3-546d-43bb-beb2-1fe3fc958e63",
"name": "Has Pending Follow-ups?",
"type": "n8n-nodes-base.if",
"position": [
512,
-192
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $input.all().length }}",
"rightValue": 0
}
]
}
},
"typeVersion": 2
},
{
"id": "ea80332d-244a-482e-89f6-779cdae1a39f",
"name": "Send Slack Reminder",
"type": "n8n-nodes-base.slack",
"position": [
736,
-192
],
"parameters": {
"text": "=\ud83d\udccb **Job Application Follow-up Reminder**\n\nYou have {{ $input.all().length }} application(s) due for follow-up today:\n\n{{ $input.all().map(item => `\u2022 **${item.json.properties?.Company?.title?.[0]?.plain_text || 'Unknown'}** - ${item.json.properties?.Role?.rich_text?.[0]?.plain_text || 'Role'}`).join('\\n') }}\n\n_Time to send those follow-up emails!_ \ud83d\udcaa",
"otherOptions": {}
},
"typeVersion": 2.2
},
{
"id": "13c1a2e7-fb87-4f17-82e7-51aef327156d",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
32,
-288
],
"parameters": {
"color": 4,
"width": 924,
"height": 324,
"content": "### \u23f0 Daily Follow-up Reminders\nChecks Notion daily at 9 AM for applications that need follow-up"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "e644c523-981d-4bf0-b9f3-e464f989ba26",
"connections": {
"Daily Follow-up Check": {
"main": [
[
{
"node": "Get Applications Due for Follow-up",
"type": "main",
"index": 0
}
]
]
},
"Route by Input Source": {
"main": [
[
{
"node": "Scrape Job Posting URL",
"type": "main",
"index": 0
}
],
[
{
"node": "Extract Job Details with AI",
"type": "main",
"index": 0
}
]
]
},
"Scrape Job Posting URL": {
"main": [
[
{
"node": "Extract Job Details with AI",
"type": "main",
"index": 0
}
]
]
},
"Has Pending Follow-ups?": {
"main": [
[
{
"node": "Send Slack Reminder",
"type": "main",
"index": 0
}
]
]
},
"Prepare Success Response": {
"main": [
[
{
"node": "Send Confirmation Response",
"type": "main",
"index": 0
},
{
"node": "Send Email Confirmation",
"type": "main",
"index": 0
}
]
]
},
"Save Application to Notion": {
"main": [
[
{
"node": "Prepare Success Response",
"type": "main",
"index": 0
}
]
]
},
"Extract Job Details with AI": {
"main": [
[
{
"node": "Parse and Structure Job Data",
"type": "main",
"index": 0
}
]
]
},
"Parse and Structure Job Data": {
"main": [
[
{
"node": "Generate Interview Prep Materials",
"type": "main",
"index": 0
}
]
]
},
"Receive Job Application Form": {
"main": [
[
{
"node": "Route by Input Source",
"type": "main",
"index": 0
}
]
]
},
"Check for Forwarded Applications": {
"main": [
[
{
"node": "Route by Input Source",
"type": "main",
"index": 0
}
]
]
},
"Generate Interview Prep Materials": {
"main": [
[
{
"node": "Save Application to Notion",
"type": "main",
"index": 0
}
]
]
},
"Get Applications Due for Follow-up": {
"main": [
[
{
"node": "Has Pending Follow-ups?",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Categories: AI, Productivity, Career
Source: https://n8n.io/workflows/13104/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Email Automation AI-Powered Operations Internal Productivity Tools
🧾 An intelligent automation system that turns Google Meet recordings into structured meeting notes — integrating Fireflies.ai, OpenAI GPT-4.1-mini, Notion, Slack, Google Drive, and Gmail via n8n.
This n8n workflow acts as an AI-powered Inbox Assistant that automatically summarizes and classifies Gmail emails, prioritizes important messages, and sends a daily digest to Slack. It’s ideal for sta
This n8n workflow orchestrates a powerful suite of AI Agents and automations to manage and optimize various aspects of an e-commerce operation, particularly for platforms like Shopify. It leverages La
The Ultimate Scraper for n8n uses Selenium and AI to retrieve any information displayed on a webpage. You can also use session cookies to log in to the targeted webpage for more advanced scraping need