{"id":290,"date":"2025-08-21T13:48:40","date_gmt":"2025-08-21T20:48:40","guid":{"rendered":"https:\/\/simpkins.social\/cliff\/?p=290"},"modified":"2025-10-30T12:43:56","modified_gmt":"2025-10-30T19:43:56","slug":"building-an-ai-job-search-agent-with-n8n","status":"publish","type":"post","link":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/","title":{"rendered":"Designing an AI Job Search Agent with n8n"},"content":{"rendered":"\n<p><em>30 Oct: This post is shifting to &#8216;why and how I designed\/built&#8217; the n8n job search agent; see <a href=\"https:\/\/simpkins.social\/cliff\/blog\/2025\/10\/28\/how-to-use-n8n-to-search-job-boards\/\">How to use n8n to search job boards<\/a> for how to install it.<\/em><\/p>\n\n\n\n<p>I built an AI agent that automatically finds relevant job openings, evaluates them against my criteria, and emails me daily updates. This agent detailed below has replaced my morning job board searches.<\/p>\n\n\n\n<p>Over the past couple of months, the AI job search agent processes 40+ new postings each week and flags 2-3 genuinely relevant opportunities. After trying several approaches this summer, I\u2019ve continue to find n8n&#8217;s visual workflow builder striking the perfect balance of abstraction and control for this automation.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why n8n for AI Agents<\/h2>\n\n\n\n<p>n8n&#8217;s flowgramming approach lets you see the entire agent workflow at a glance while maintaining granular control over each step. Unlike code-heavy frameworks, you can iterate quickly on logic and easily debug issues when they arise. And unlike no-code frameworks (e.g., Zapier), you get greater control over resource usage and greater predictability for how the agent operates.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5 Steps To Find Relevant Job Postings<\/h2>\n\n\n\n<p>The agent workflow has five functional steps to it:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Search the web for recent job openings using a keyword string I created<\/li>\n\n\n\n<li>Iterate through the found job openings and skip ones we\u2019ve seen before<\/li>\n\n\n\n<li>Ask Claude to analyze the role and evaluate if it is what I\u2019m looking for<\/li>\n\n\n\n<li>Save the discovered job openings, marking them as relevant or not<\/li>\n\n\n\n<li>Email me an update of what was processed<\/li>\n<\/ol>\n\n\n\n<p>Below is a screenshot of the current workflow, calling out where these steps occur.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1910\" height=\"878\" src=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-17.png?resize=1910%2C878&#038;ssl=1\" alt=\"Screenshot of n8n workflows that make up the AI job search agent\" class=\"wp-image-526\" srcset=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-17.png?w=1910&amp;ssl=1 1910w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-17.png?resize=300%2C138&amp;ssl=1 300w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-17.png?resize=1024%2C471&amp;ssl=1 1024w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-17.png?resize=768%2C353&amp;ssl=1 768w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-17.png?resize=1536%2C706&amp;ssl=1 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n<\/div>\n\n\n<p>The rest of this blog post examines each step and explains the implementation.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What You&#8217;ll Need<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You\u2019ll need an <strong><a href=\"https:\/\/n8n.io\/\">n8n<\/a> account<\/strong> (obviously). You can use either the cloud service or self-host. <br><em>For me, I started with the cloud service to build the initial workflow, then moved it to a local Docker container to run on my local machine.<\/em><\/li>\n\n\n\n<li>To search the web, a <a href=\"https:\/\/brave.com\/search\/api\/guides\/use-with-n8n\/\"><strong>Brave Search API<\/strong> account<\/a> and a <a href=\"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/26\/adding-google-search-to-my-n8n-driven-job-search-agent\/\"><strong>Google Search API <\/strong>account<\/a>. Both of their free tier accounts provide sufficient quota for daily job searches<\/li>\n\n\n\n<li>You can use <strong><a href=\"https:\/\/www.airtable.com\/\">Airtable<\/a>,<\/strong> <strong>PostgreSQL<\/strong>, or whatever else you prefer to store your data. My solution has used both Airtable and Postgres, which are detailed below.<\/li>\n\n\n\n<li><strong>Gmail account<\/strong> to send daily summary emails<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/console.anthropic.com\/\">Anthropic API key<\/a><\/strong> is needed to power the job evaluation. Note that you need an API account to call your AI service, which is separate from your Pro subscriptions.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Configured Data Storage<\/h3>\n\n\n\n<p>To store the data, I set up my data store with the following fields:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Company<\/code> (single line text) \u2013 Company name<\/li>\n\n\n\n<li><code>Position<\/code> (single line text) \u2013 Job title<\/li>\n\n\n\n<li><code>Date Identified<\/code> (date) \u2013 Date that the role was first discovered<\/li>\n\n\n\n<li><code>Date Applied<\/code> (date) \u2013 Date applied for role (if applicable)<\/li>\n\n\n\n<li><code>Decision Date<\/code> (date) \u2013 Date that this opportunity closed &#8211; positive or negative (if applicable)<\/li>\n\n\n\n<li><code>Status<\/code> (single select) \u2013 For the purposes of this example, \u2018Found by Agent\u2019, \u2018Ignore\u2019, \u2018Ignore \u2013 Duplicate\u2019, \u2018Applied\u2019, and \u2018Position Closed\u2019<\/li>\n\n\n\n<li><code>Job Description Link<\/code> (single line text) \u2013 URL<\/li>\n\n\n\n<li><code>Interview Rounds<\/code> &#8211; Links to records in the Interviews data table<\/li>\n\n\n\n<li><code>Notes<\/code> (single line text) \u2013 Claude applies their reasoning here<\/li>\n\n\n\n<li><code>Job Description<\/code> (long text) \u2013 Full job description<\/li>\n\n\n\n<li><code>Source<\/code> (single select) \u2013 Where this job was found &#8211; for this example, &#8216;AI Agent&#8217;, &#8216;LinkedIn&#8217;<\/li>\n\n\n\n<li><code>Green flags<\/code> (single line text) \u2013 String array of green flags that the AI spotted from the job description<\/li>\n\n\n\n<li><code>Red flags<\/code> (single line text) \u2013 String array of green flags that the AI spotted from the job description<\/li>\n\n\n\n<li><code>Normalized URL<\/code> (single line text) &#8211; URL that has been cleaned up to remove URL variables and language-specific URL features, helping reduce duplicate job entries.<\/li>\n\n\n\n<li><code>Platform<\/code> (single line text) \u2013 Which job board the job listing came from<\/li>\n<\/ul>\n\n\n\n<p>I use a number of additional fields in the Airtable database to track and drive my application\/interview process, but the above are required for this workflow setup.<\/p>\n\n\n\n<p>With the dependencies setup, let\u2019s start creating the agent.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1 \u2013 Search the Job Boards for Jobs<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Using Brave Search<\/h3>\n\n\n\n<p>The agent uses <a href=\"https:\/\/safe.search.brave.com\/help\/operators\">Brave Search&#8217;s operators<\/a> to find targeted results across multiple job boards. Here&#8217;s the search syntax:<\/p>\n\n\n\n<p><code>site:ashbyhq.com AND (intitle:\"developer marketing\" <code>OR intitle:\"developer relations\"<\/code><\/code> <code>OR intitle:\"product marketing\") AND (intitle:\"director\" OR intitle:\"vp\" OR intitle:\"head\") AND inpage:\"developer\" NOT intitle:\"Product Management\"<\/code><\/p>\n\n\n\n<p>Brave Search key operators:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>site:<\/code> &#8211; Limits results to the URL of a specific job board<\/li>\n\n\n\n<li><code>intitle:<\/code> &#8211; Targets keywords within the job title<\/li>\n\n\n\n<li><code>inpage:<\/code> &#8211; Requires specific terms in the description<\/li>\n\n\n\n<li><code>NOT<\/code> \u2013 Used to exclude unwanted roles<\/li>\n<\/ul>\n\n\n\n<p>I use two workflows to search Brave:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The first workflow (1) sets the search string (above), (2) runs separate searches for each target job board by calling the second workflow, and then uses n8n&#8217;s &#8216;Split Out&#8217; activity to convert API results into individual job entries that can be processed. A brief pause between searches prevents API rate limiting.<\/li>\n\n\n\n<li>The second workflow makes the Brave Search API call &#8211; it (3a) initializes a loop to (4) retrieve a page of search results and then (3b) concatenate the pages together and determine whether it needs to run again. <\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"829\" height=\"550\" src=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-19.png?resize=829%2C550&#038;ssl=1\" alt=\"Workflow model for calling Brave Search API.\" class=\"wp-image-528\" srcset=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-19.png?w=829&amp;ssl=1 829w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-19.png?resize=300%2C199&amp;ssl=1 300w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-19.png?resize=768%2C510&amp;ssl=1 768w\" sizes=\"auto, (max-width: 829px) 100vw, 829px\" \/><\/figure>\n<\/div>\n\n\n<p>The end result is a collection of search results that are merged back together using the n8n Merge activity to bring all of the individual search results together into one collection that can be passed back to the primary workflow.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Using Google Search<\/h3>\n\n\n\n<p>I also use this for Google, which I wrote <a href=\"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/26\/adding-google-search-to-my-n8n-driven-job-search-agent\/\">a separate blog post on<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2 \u2013 Filter Out Duplicates<\/h2>\n\n\n\n<p>With search results merged into a single collection, we want to filter out the URLs that we have previously seen. This saves us a lot of processing and LLM tokens. The below section describes how to do this with PostgreSQL, but I have also <a href=\"https:\/\/simpkins.social\/cliff\/blog\/2025\/10\/20\/how-to-bulk-validate-airtable-data-to-save-api-checks\/\">done this using Airtable<\/a>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"653\" height=\"370\" src=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-20.png?resize=653%2C370&#038;ssl=1\" alt=\"Workflow nodes for filtering out duplicates - retrieving prior results and using the n8n Combine node to filter out results\" class=\"wp-image-529\" srcset=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-20.png?w=653&amp;ssl=1 653w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-20.png?resize=300%2C170&amp;ssl=1 300w\" sizes=\"auto, (max-width: 653px) 100vw, 653px\" \/><\/figure>\n<\/div>\n\n\n<p>When I query the data store, I use the cached credentials and retrieve all rows, but only retrieve the <code>job description link<\/code> and <code>normalized url<\/code> columns to limit space. When configuring this, I found it very helpful to have the \u2018Always Output Data\u2019 option enabled &#8211; otherwise the workflow may stop if no results are returned.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"904\" height=\"689\" src=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-22.png?resize=904%2C689&#038;ssl=1\" alt=\"\" class=\"wp-image-531\" srcset=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-22.png?w=904&amp;ssl=1 904w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-22.png?resize=300%2C229&amp;ssl=1 300w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-22.png?resize=768%2C585&amp;ssl=1 768w\" sizes=\"auto, (max-width: 904px) 100vw, 904px\" \/><\/figure>\n\n\n\n<p>To use the data, I use an n8n Combine node to match the search results against the previously processed URLs and use set the <code>Output Type<\/code> to <code>Keep Non-Matches<\/code> &#8211; this is the magic that filters out all of the previously processed URLs.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1110\" height=\"537\" src=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-23.png?resize=1110%2C537&#038;ssl=1\" alt=\"\" class=\"wp-image-532\" srcset=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-23.png?w=1110&amp;ssl=1 1110w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-23.png?resize=300%2C145&amp;ssl=1 300w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-23.png?resize=1024%2C495&amp;ssl=1 1024w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-23.png?resize=768%2C372&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n<\/div>\n\n\n<p>And I actually do this filtering-out step twice &#8211; once against the <code>Job Description Link<\/code> and once against the <code>Normalized URL<\/code>.<\/p>\n\n\n\n<p>In my first implementation of this, I had the agent loop through each job posting and queries Airtable using the job URL and evaluate if it existed in the database. HOWEVER, I found this ate up a LOT of Airtable API calls and caused my agent to get blocked &#8211; leading to this solution. For additional details, check out my <a href=\"https:\/\/simpkins.social\/cliff\/blog\/2025\/10\/20\/how-to-bulk-validate-airtable-data-to-save-api-checks\/\">blog post on the topic<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3 \u2013 Claude Evaluation<\/h2>\n\n\n\n<p>Now that we have a new job entry, let\u2019s ask use an <a href=\"https:\/\/docs.n8n.io\/integrations\/builtin\/app-nodes\/n8n-nodes-langchain.anthropic\/\">Anthropic AI node<\/a> to evaluate if it is a role that marches what I\u2019m looking for. This is where Claude analyzes each new job posting using a prompt that includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Your specific role requirements and preferences<\/li>\n\n\n\n<li>The job title and URL from search results<\/li>\n\n\n\n<li>Explicit instructions to return only valid JSON (no markdown formatting)<\/li>\n\n\n\n<li>Output examples showing the expected structure<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"440\" height=\"647\" src=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-6.png?resize=440%2C647&#038;ssl=1\" alt=\"n8n properties for AI Messaging node to find prior applications - parameters tab\" class=\"wp-image-298\" srcset=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-6.png?w=440&amp;ssl=1 440w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-6.png?resize=204%2C300&amp;ssl=1 204w\" sizes=\"auto, (max-width: 440px) 100vw, 440px\" \/><\/figure>\n<\/div>\n\n\n<p>Within this activity, you\u2019ll want to be as descriptive as possible of what you are looking for and how the AI should evaluate the job description. As you code this, consider the prompt as a starting point that will be evaluated and tweaked over time &#8211; I have continued to evolve and tweak this prompt on a weekly basis based on how it is processing job postings, and I expect I will continue to revisit this prompt weekly.<\/p>\n\n\n\n<p>A few key elements to keep in mind:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>You must pass it the job title and the URL from the search results into the prompt \u2013 I got mine from the \u2018Loop Over Posts\u2019 activity<\/li>\n\n\n\n<li>A critical element for me was to give it output examples and explicitly tell it to pass only valid JSON and not to include any markdown formatting.<\/li>\n\n\n\n<li>Consider increasing the maximum token limit to handle longer job descriptions<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"685\" height=\"1024\" src=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-13.png?resize=685%2C1024&#038;ssl=1\" alt=\"screenshot of the full AI prompt\" class=\"wp-image-395\" style=\"width:477px;height:auto\" srcset=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-13.png?resize=685%2C1024&amp;ssl=1 685w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-13.png?resize=201%2C300&amp;ssl=1 201w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-13.png?resize=768%2C1147&amp;ssl=1 768w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-13.png?w=1008&amp;ssl=1 1008w\" sizes=\"auto, (max-width: 685px) 100vw, 685px\" \/><\/figure>\n<\/div>\n\n\n<p>After Claude has analyzed the posting, you should add a &#8216;SET&#8217; activity in JSON mode cleans up the response format before proceeding.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"475\" height=\"206\" src=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-5.png?resize=475%2C206&#038;ssl=1\" alt=\"n8n properties for Set node that cleaned up the JSON\" class=\"wp-image-297\" srcset=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-5.png?w=475&amp;ssl=1 475w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-5.png?resize=300%2C130&amp;ssl=1 300w\" sizes=\"auto, (max-width: 475px) 100vw, 475px\" \/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Step 4 \u2013 Save the Results<\/h2>\n\n\n\n<p>With the job opening evaluated, we need to post the entry up into Airtable for human evaluation using an Airtable activity with these mapped fields:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Company: <code>{{ $json.company }}<\/code><\/li>\n\n\n\n<li>Position: <code>{{ $('Loop Over Posts').item.json.title }}<\/code><\/li>\n\n\n\n<li>Date Identified: <code>{{ $now.format('MM\/dd\/yyyy') }}<\/code><\/li>\n\n\n\n<li>Status: <code>{{ $if($json.relevant, \"Found by Agent\", \"Ignore\" ) }}<\/code><\/li>\n\n\n\n<li>Notes: <code>{{ $json.reasoning }}<\/code><\/li>\n\n\n\n<li>Job Description Link: <code>{{ $('Loop Over Posts').item.json.profile.url }}<\/code><\/li>\n\n\n\n<li>Job Description Text: <code>{{ $json['job description'] }}<\/code><\/li>\n\n\n\n<li>Green flags: <code>{{ $json.green_flags.join(\"; \") }}<\/code><\/li>\n\n\n\n<li>Red flags: <code>{{ $json.red_flags.join(\"; \") }}<\/code><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5 \u2013 Daily Email Summary<\/h2>\n\n\n\n<p>Lastly, the workflow sends me a summary email using the <a href=\"https:\/\/docs.n8n.io\/integrations\/builtin\/app-nodes\/n8n-nodes-base.gmail\/\">Gmail node<\/a> to let me know what it has processed: job counts, token usage, and a list of newly discovered relevant roles. This has been extremely useful for letting me know what has been found by the agent.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"480\" src=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-15.png?resize=1024%2C480&#038;ssl=1\" alt=\"screenshots of node configuration, relevant expression boxes, and a sample email sent by the node.\" class=\"wp-image-397\" srcset=\"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-15.png?resize=1024%2C480&amp;ssl=1 1024w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-15.png?resize=300%2C141&amp;ssl=1 300w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-15.png?resize=768%2C360&amp;ssl=1 768w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-15.png?resize=1536%2C720&amp;ssl=1 1536w, https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-15.png?w=1694&amp;ssl=1 1694w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>I love how this email summary captures the summary of all of the work, which took some work to reverse-engineer\/hack my way into workflow variables, which I don&#8217;t think exist in the free tier of n8n. The process of creating these &#8216;variables&#8217; helped me learn a lot about the way that n8n works, but that is the topic for a future blog post. <\/p>\n\n\n\n<p>And while I like this email, I still really prefer the summary emails sent by my Zapier agent that is doing similar work each morning, but I&#8217;ll share more on the Zapier AI agent in another blog post.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Results &amp; Performance<\/h2>\n\n\n\n<p>So far, the agent picks up about 60-70 postings from the search results, with 10 jobs being new each week and &nbsp;1-2 of those being genuine opportunities. It filters out about 80%+ of irrelevant results and saves me roughly 3 hours of manual searching and evaluations per week.<\/p>\n\n\n\n<p>False positives are rare when the AI prompt includes specific examples of roles to avoid. The main challenge for me is refining the job board search syntax and tweaking my AI prompt to provide better assessment.<\/p>\n\n\n\n<p>The biggest thing holding me back is that I can\u2019t specify the freshness from the Search queries. For Brave, the Search API is limited to 20 results, the API call typically processes most of the same 10-12 results top the returned results. If I were able to specify job postings new in the last week, I predict that the workflow would find more new postings and wouldn\u2019t need to process the same ones.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Next Steps<\/h2>\n\n\n\n<p>I love how this workflow performs, but I\u2019m not done yet!<\/p>\n\n\n\n<p>Below is my current backlog of workflow enhancements:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Brave Search API enhancement \u2013 I REALLY want to only search the fresh job results. I am debating to either (a) move to an activity that calls the URL\/API directly, or (b) updating the n8n Brave Search activity to add the freshness flag.<\/li>\n\n\n\n<li>Querying my top-10 company list \u2013 I would like to enhance the workflow to query targeted company Career pages, not just job board web searches.<\/li>\n\n\n\n<li>Give more agency to the AI &#8211; In my Zapier agent, the AI has given itself permission to dig around the internet if the URL isn&#8217;t found &#8211; querying the company&#8217;s job board and finding it. This one doesn&#8217;t, but I would love to figure out how to get it to do more on its own.<\/li>\n\n\n\n<li><s>Multi-criteria scoring instead of binary relevant\/irrelevant classification \u2013 I\u2019m in the process of moving to a multi-shot prompt to get more useful notes. Eventually, I\u2019d like to make this question itself and flag potential false positives and false negatives.<\/s><\/li>\n\n\n\n<li><s>Automated career coaching resume updates for the most obvious fits \u2013 I have a rather extensive Career Coach \u2018agent\u2019 that helps me tailor my resume to specific jobs. I\u2019m debating whether to incorporate that analysis into this workflow, moving it out of my Claude Pro account. This would likely be creating an AI Agent in n8n and calling into it.<\/s><\/li>\n<\/ul>\n\n\n\n<p>I hope that this post helps you get use out of n8n, and that it helps other job seekers out there on the market today. If you have other suggestions for improvements or see where I could be using n8n better, drop me a note.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>30 Oct: This post is shifting to &#8216;why and how I designed\/built&#8217; the n8n job search agent; see How to use n8n to search job boards for how to install&hellip;<\/p>\n","protected":false},"author":1,"featured_media":394,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[12,29],"tags":[16,25],"class_list":["post-290","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-funemployment","category-n8n","tag-learning","tag-tips-tricks"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Designing an AI Job Search Agent with n8n - Cliff Simpkins<\/title>\n<meta name=\"description\" content=\"Building a basic AI Agent as an n8n workflow to search and qualify relevant jobs using Brave Search APIs, Claude AI, and Airtable.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Designing an AI Job Search Agent with n8n - Cliff Simpkins\" \/>\n<meta property=\"og:description\" content=\"Building a basic AI Agent as an n8n workflow to search and qualify relevant jobs using Brave Search APIs, Claude AI, and Airtable.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/\" \/>\n<meta property=\"og:site_name\" content=\"Cliff Simpkins\" \/>\n<meta property=\"article:published_time\" content=\"2025-08-21T20:48:40+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-30T19:43:56+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-12.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1487\" \/>\n\t<meta property=\"og:image:height\" content=\"884\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"cliff.simpkins\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"cliff.simpkins\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/\"},\"author\":{\"name\":\"cliff.simpkins\",\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/#\\\/schema\\\/person\\\/bba546ac4d77da1fb51bc4030238e864\"},\"headline\":\"Designing an AI Job Search Agent with n8n\",\"datePublished\":\"2025-08-21T20:48:40+00:00\",\"dateModified\":\"2025-10-30T19:43:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/\"},\"wordCount\":1998,\"commentCount\":1,\"image\":{\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/simpkins.social\\\/cliff\\\/wp-content\\\/uploads\\\/2025\\\/08\\\/image-12.png?fit=1487%2C884&ssl=1\",\"keywords\":[\"Learning\",\"Tips &amp; Tricks\"],\"articleSection\":[\"Funemployment\",\"N8n\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/\",\"url\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/\",\"name\":\"Designing an AI Job Search Agent with n8n - Cliff Simpkins\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/simpkins.social\\\/cliff\\\/wp-content\\\/uploads\\\/2025\\\/08\\\/image-12.png?fit=1487%2C884&ssl=1\",\"datePublished\":\"2025-08-21T20:48:40+00:00\",\"dateModified\":\"2025-10-30T19:43:56+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/#\\\/schema\\\/person\\\/bba546ac4d77da1fb51bc4030238e864\"},\"description\":\"Building a basic AI Agent as an n8n workflow to search and qualify relevant jobs using Brave Search APIs, Claude AI, and Airtable.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/#primaryimage\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/simpkins.social\\\/cliff\\\/wp-content\\\/uploads\\\/2025\\\/08\\\/image-12.png?fit=1487%2C884&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/simpkins.social\\\/cliff\\\/wp-content\\\/uploads\\\/2025\\\/08\\\/image-12.png?fit=1487%2C884&ssl=1\",\"width\":1487,\"height\":884},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/2025\\\/08\\\/21\\\/building-an-ai-job-search-agent-with-n8n\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Designing an AI Job Search Agent with n8n\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/#website\",\"url\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/\",\"name\":\"Cliff Simpkins\",\"description\":\"Personal site + blog\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/#\\\/schema\\\/person\\\/bba546ac4d77da1fb51bc4030238e864\",\"name\":\"cliff.simpkins\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/07b113647e819a448cfc8545b476db50a641b9d43808a2c399af84e724d078d2?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/07b113647e819a448cfc8545b476db50a641b9d43808a2c399af84e724d078d2?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/07b113647e819a448cfc8545b476db50a641b9d43808a2c399af84e724d078d2?s=96&d=mm&r=g\",\"caption\":\"cliff.simpkins\"},\"url\":\"https:\\\/\\\/simpkins.social\\\/cliff\\\/blog\\\/author\\\/cliff-simpkins\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Designing an AI Job Search Agent with n8n - Cliff Simpkins","description":"Building a basic AI Agent as an n8n workflow to search and qualify relevant jobs using Brave Search APIs, Claude AI, and Airtable.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/","og_locale":"en_US","og_type":"article","og_title":"Designing an AI Job Search Agent with n8n - Cliff Simpkins","og_description":"Building a basic AI Agent as an n8n workflow to search and qualify relevant jobs using Brave Search APIs, Claude AI, and Airtable.","og_url":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/","og_site_name":"Cliff Simpkins","article_published_time":"2025-08-21T20:48:40+00:00","article_modified_time":"2025-10-30T19:43:56+00:00","og_image":[{"width":1487,"height":884,"url":"https:\/\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-12.png","type":"image\/png"}],"author":"cliff.simpkins","twitter_card":"summary_large_image","twitter_misc":{"Written by":"cliff.simpkins","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/#article","isPartOf":{"@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/"},"author":{"name":"cliff.simpkins","@id":"https:\/\/simpkins.social\/cliff\/#\/schema\/person\/bba546ac4d77da1fb51bc4030238e864"},"headline":"Designing an AI Job Search Agent with n8n","datePublished":"2025-08-21T20:48:40+00:00","dateModified":"2025-10-30T19:43:56+00:00","mainEntityOfPage":{"@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/"},"wordCount":1998,"commentCount":1,"image":{"@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-12.png?fit=1487%2C884&ssl=1","keywords":["Learning","Tips &amp; Tricks"],"articleSection":["Funemployment","N8n"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/","url":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/","name":"Designing an AI Job Search Agent with n8n - Cliff Simpkins","isPartOf":{"@id":"https:\/\/simpkins.social\/cliff\/#website"},"primaryImageOfPage":{"@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/#primaryimage"},"image":{"@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-12.png?fit=1487%2C884&ssl=1","datePublished":"2025-08-21T20:48:40+00:00","dateModified":"2025-10-30T19:43:56+00:00","author":{"@id":"https:\/\/simpkins.social\/cliff\/#\/schema\/person\/bba546ac4d77da1fb51bc4030238e864"},"description":"Building a basic AI Agent as an n8n workflow to search and qualify relevant jobs using Brave Search APIs, Claude AI, and Airtable.","breadcrumb":{"@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/#primaryimage","url":"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-12.png?fit=1487%2C884&ssl=1","contentUrl":"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-12.png?fit=1487%2C884&ssl=1","width":1487,"height":884},{"@type":"BreadcrumbList","@id":"https:\/\/simpkins.social\/cliff\/blog\/2025\/08\/21\/building-an-ai-job-search-agent-with-n8n\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/simpkins.social\/cliff\/"},{"@type":"ListItem","position":2,"name":"Designing an AI Job Search Agent with n8n"}]},{"@type":"WebSite","@id":"https:\/\/simpkins.social\/cliff\/#website","url":"https:\/\/simpkins.social\/cliff\/","name":"Cliff Simpkins","description":"Personal site + blog","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/simpkins.social\/cliff\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/simpkins.social\/cliff\/#\/schema\/person\/bba546ac4d77da1fb51bc4030238e864","name":"cliff.simpkins","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/07b113647e819a448cfc8545b476db50a641b9d43808a2c399af84e724d078d2?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/07b113647e819a448cfc8545b476db50a641b9d43808a2c399af84e724d078d2?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/07b113647e819a448cfc8545b476db50a641b9d43808a2c399af84e724d078d2?s=96&d=mm&r=g","caption":"cliff.simpkins"},"url":"https:\/\/simpkins.social\/cliff\/blog\/author\/cliff-simpkins\/"}]}},"jetpack_featured_media_url":"https:\/\/i0.wp.com\/simpkins.social\/cliff\/wp-content\/uploads\/2025\/08\/image-12.png?fit=1487%2C884&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/posts\/290","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/comments?post=290"}],"version-history":[{"count":6,"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/posts\/290\/revisions"}],"predecessor-version":[{"id":533,"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/posts\/290\/revisions\/533"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/media\/394"}],"wp:attachment":[{"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/media?parent=290"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/categories?post=290"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/simpkins.social\/cliff\/wp-json\/wp\/v2\/tags?post=290"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}