cd /news/ai-tools/job-radar-md Β· home β€Ί topics β€Ί ai-tools β€Ί article
[ARTICLE Β· art-155224] src=gist.github.com β†— pub= topic=ai-tools verified=true sentiment=↑ positive

job_radar.md

A developer published a step-by-step guide for building a self-hosted "job radar" automation in n8n that checks the Arbeitsagentur job board each morning, uses Google's Gemini API to score new postings against a personal profile, and emails only the strong matches. The workflow runs locally via Docker, keeping user data on their own machine, and requires a Gemini API key plus a Gmail app password for delivery.

by read22 min views2 publishedOct 21, 2026

In this guide you build an automation that actually helps you: a job radar.

Every morning, it checks the Arbeitsagentur job board for new postings. AI reads each one and rates how well it fits you. You only get an email with the good matches.

[Manual trigger]──┐
                  β”œβ”€> Search settings -> Fetch jobs -> Split jobs -> Clean up jobs
[Every morning]β”€β”€β”€β”˜        -> Remember seen jobs -> Limit -> Score with AI (Gemini)
                           -> Job + score -> Good matches only -> Build email -> Send email

You build it with n8n, an automation tool like Make, with two big differences:

  • It runs on your own laptop, so your data stays with you.

  • It's free when you host it yourself. No credits, no monthly limit.

  • Goal: what you're building in this part.

  • Checkpoint: what you should see before you move on.

  • Stuck? Quick fixes for the usual problems.

[drag X] means: drag the field X from the left panel into this spot. Replace the whole [drag X], brackets included.

If you know Make, most of this will feel familiar. Only the words change:

Make n8n What it means
Scenario Workflow The whole automation
Module Node One step
Bundle Item One piece of data, like one job posting
Operation Execution One run of the workflow
Connection Credential Your saved login or API key for a service
Mapping Expression Pulling data from earlier steps, written as {{ }}

You won't write code yourself. At one point, AI writes a small piece of code for you, and this guide shows you how to ask for it.

Please have these ready:

  • Docker Desktop installed and running.
  • n8n downloaded. This saves the classroom Wi-Fi. In a terminal, run:
docker pull n8nio/n8n
  • A Gemini API key: go to**https://aistudio.google.com/apikey** and clickCreate API key . Copy it somewhere safe.
  • A Gmail app password: see the step-by-step section below.
  • Your profile in 3–4 sentences: your background, what kind of job you want, languages, preferences. There's an example in Part 2.

n8n sends the email through your Gmail account. Gmail won't accept your normal password from an app like n8n, so you create a special 16-character "app password" just for n8n.

Use a personal Gmail account. Work and school accounts usually don't allow app passwords.

App passwords only exist once 2-Step Verification is on. Skip to part B if yours already is.

  1. Go to https://myaccount.google.com/security .

  2. Check the profile picture at the top right: is it your personal Gmail? If not, click it and switch accounts.

  3. Scroll to How you sign in to Google and click2-Step Verification .

  4. Click Turn on 2-Step Verification and follow the steps. Usually you confirm your phone number and enter a code sent by SMS.

  5. Back on the Security page, 2-Step Verification should now sayOn .

  6. Open https://myaccount.google.com/apppasswords . Type the full address, includinghttps:// .

  • Google doesn't show a button for this on the Security page. If the link doesn't work, go to https://myaccount.google.com , click the search bar at the top, typeApp passwords , and click the result.
  1. Google doesn't show a button for this on the Security page. If the link doesn't work, go to
  2. Sign in again if Google asks.
  3. In App name , typen8n and clickCreate .
  4. A box shows your app password: 16 letters in four groups, like abcd efgh ijkl mnop .
  5. Copy it now and save it somewhere safe. Google shows it only once. If you lose it, delete it and create a new one.
  6. Click Done .

That's all for now. You'll paste the app password into n8n in Part 8: Send the email, which walks you through every click. Until then, keep it somewhere easy to copy from, like a note on your laptop.

Work through these in order:

  1. 2-Step Verification is off. Do part A, then reload the page.
  2. Wrong account. If you're signed in to several Google accounts, the link opens your default one. Check the profile picture at the top right and switch accounts, or open the link in a private/incognito window and sign in with your personal Gmail only.
  3. Work or school account. Your organization has blocked app passwords. Use a personal Gmail.
  4. 2-Step Verification uses only a security key, or Advanced Protection is on. Add your phone number as a second step in part A, or use a different Gmail account.

Good to know: if you ever change your Google password, all app passwords stop working. Then just create a new one and update it in n8n.

Goal: n8n running on your laptop.

n8n runs inside Docker. Think of Docker as a box that has everything n8n needs, so you don't have to install anything else.

  1. Make sure Docker Desktop is running.
  2. Open a terminal (Mac: Terminal, Windows: PowerShell) and run this command. It creates a storage space, so your workflows survive when n8n stops:
docker volume create n8n_data
  1. Then run this command to start n8n. The timezone part makes sure "8 a.m." means 8 a.m. in Germany:
docker run -it --rm --name n8n -p 5678:5678 -e GENERIC_TIMEZONE="Europe/Berlin" -e TZ="Europe/Berlin" -e N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true -v n8n_data:/home/node/.n8n n8nio/n8n
  1. Wait until the terminal shows the editor URL (http://localhost:5678 ). The first start can take a minute.
  2. Open http://localhost:5678 in your browser.
  3. Create your owner account (email, name, password). It's only stored on your laptop.
  4. Skip the survey and the license offer.

Checkpoint: you see the n8n start screen.

Keep this terminal open. If you close it, n8n stops. To start n8n again later, run the command from step 3 again.

Stuck?

  • "Cannot connect to the Docker daemon": Docker Desktop isn't running. Start it and wait until it says it's running.
  • "Port is already allocated": n8n is already running somewhere. Check Docker Desktop >Containers .
  • "Container name already in use": rundocker rm n8n , then the command from step 3 again.

Goal: all your settings in one place: job title, city, and your profile. That way, you can change the search later without touching the rest of the workflow.

A habit for this whole guide: name every node. It makes the workflow readable, and it helps later when you reference earlier steps.

  1. Click Create workflow . Name itJob radar (top left).
  2. Click Add first step >Trigger manually .
  3. Click the + on the right of the trigger, searchEdit Fields (Set) , and add it.
  4. Rename it Search settings : click the title at the top of the panel.
  5. Click Add Field five times. For each one, type the name, choose the type, and enter the value:
Name Type Value
jobTitle String e.g. Marketing
city String e.g. Hannover
radiusKm Number 25
daysBack Number 7
profile String Your 3–4 sentence profile (example below)

Example profile:

Former retail team lead with 5 years of experience in customer service and managing small teams. Currently finishing a course in AI tools and automation. Looking for junior roles in marketing, customer success or operations. Fluent in German and English, prefers hybrid or remote work.
  1. Click Execute step .

daysBack is 7 for now, so you have enough jobs to test with. In Part 10, you switch it to 1, because the workflow will run daily.

Checkpoint: the output on the right shows one item with your five fields.

Goal: a list of real job postings from the Arbeitsagentur.

The Arbeitsagentur has a free API: a door for programs instead of humans. The HTTP Request node is how n8n talks to any API, even ones that don't have their own node.

  1. Add an HTTP Request node afterSearch settings . Rename itFetch jobs .
  2. Method: GET
  3. URL:
https://rest.arbeitsagentur.de/jobboerse/jobsuche-service/pc/v6/jobs
  1. Turn on Send Query Parameters and clickAdd Parameter six times:
Name Value
was drag jobTitle from the left panel
wo drag city
umkreis drag radiusKm
veroeffentlichtseit drag daysBack
angebotsart 1
size 25
  1. Turn on Send Headers and add one header:
  • Name:X-API-Key
  • Value:jobboerse-jobsuche
  1. Click Execute step .

What's going on here:

  • The parameter names are German because it's a German API. was is "what",wo is "where",umkreis is the radius.
  • angebotsart 1 means regular jobs, not apprenticeships.
  • When you drag a field in, it turns into an expression, the part with curly braces. That's n8n saying: take this value from an earlier step.
  • The header works like a visitor badge. This one is public, it's the same for everyone.

Checkpoint: one item that contains ergebnisliste, a list of job postings.

Stuck?

  • No ergebnisliste in the output: no jobs were found. Try a bigger radius, more days, or a broader job title.
  • Error 401 or 403: check the URL, and the header name and value for typos.

Goal: one item per job, with only the fields you need.

Right now, all 25 jobs are packed into one item. But the AI should look at each job separately. So you split the list: one job becomes one item, and every node after this runs once per job.

  1. Add a Split Out node. Rename itSplit jobs .
  2. Fields To Split Out:ergebnisliste (type it or drag it in)
  3. Click Execute step .

Checkpoint: the output now shows many items, one per job.

Each job has a lot of fields you don't need. Now keep only the useful ones and give them simple names.

  1. Add an Edit Fields (Set) node. Rename itClean up jobs .
  2. For each row: click Add Field , type the name, choose the type from the table, then drag the value from the left panel.
Name Type Value
title String drag stellenangebotsTitel
occupation String drag hauptberuf
employer String drag firma
city String open stellenlokationen >adresse , dragort
jobId String drag referenznummer
link String paste the link expression (see below)
careerChangerFriendly Boolean drag quereinstiegGeeignet
remotePossible Boolean drag homeofficemoeglich

Link expression to paste into the link value:

{{ $json.externeURL || 'https://www.arbeitsagentur.de/jobsuche/jobdetail/' + $json.referenznummer }}
  1. Click Execute step .

What's going on here:

  • referenznummer is each job's unique ID. You call itjobId . You'll need it later, so the workflow remembers which jobs it already sent.
  • Many jobs on the Arbeitsagentur come from partner job boards. Those only exist on the partner's site, so the API gives you an externeURL for them. The link expression says: if there's an external link, use it. If not, use the Arbeitsagentur page.
  • A job can have several locations. For the city, you simply take the first one.
  • Two fields are especially useful for you: quereinstiegGeeignet means the job is suitable for career changers, andhomeofficemoeglich means remote work is possible. The AI will use both for the score.

Checkpoint: every item has exactly these eight fields. Open one link in the browser: it should show the job posting.

Stuck?

  • No stellenangebotsTitel field: usehauptberuf for the title instead.
  • Link shows "Dieses Stellenangebot gibt es nicht oder nicht mehr": check that thelink value is exactly the expression above. If it is, the posting was taken down in the meantime. Try another one.

Goal: AI reads each job, compares it to your profile, and gives a score from 1 to 10 with a short reason.

The AI makes a judgment call here, which a normal rule couldn't do. That's what makes this an AI automation.

First, a limit, so testing doesn't use up your free Gemini quota:

  1. Add a Limit node. Rename itLimit .
  2. Max Items:5
  3. Click Execute step .

Now the AI node:

  1. Add an Information Extractor node. Rename itScore with AI .
  2. Click into Text . If there's already something in it, delete it.
  3. Type the labels below and drag in the matching fields. For profile , scroll down in the left panel toSearch settings , where every earlier node is listed.
Candidate profile:
[drag profile from Search settings]

Job posting:
Title: [drag title]
Occupation: [drag occupation]
Employer: [drag employer]
Location: [drag city]
Suitable for career changers: [drag careerChangerFriendly]
Remote work possible: [drag remotePossible]
  1. Schema Type: From Attribute Descriptions
  2. Add two attributes:
Name Type Required Description
score Number Yes see below
reason String Yes One short sentence explaining the score.

Description for score:

How well this job fits the candidate profile, from 1 (no fit) to 10 (perfect fit). Be strict: give 7 or more only if the job clearly matches the candidate's goals and background. If the candidate is changing careers, rate jobs suitable for career changers higher. If the candidate prefers remote or hybrid work, take into account whether remote work is possible.
  1. Close the node panel. On the canvas, below Score with AI , click the**+** labeledModel (orChat Model ) and chooseGoogle Gemini Chat Model .
  2. Credential:**Create new credential . Paste your Gemini API key and leaveHost** as it is. Save.
  3. Model: pick a Flash model.
  4. Close the panel, open Score with AI again, and clickExecute step .

What's going on here:

  • The Information Extractor lets you describe what you want back, and gives you clean fields instead of a wall of text.
  • The descriptions are your prompt. The clearer they are, the better the scores.
  • The API only gives you the title, occupation, employer and the two flags, not the full job ad. So the AI is pre-screening. You still decide.
  • Your profile goes to Google here, so don't put anything private in it.

Checkpoint: five items, each with an output containing score and reason. Read a few: do they make sense?

Stuck?

  • Error about Search settings that mentions "paired item": in the Text field, change.item to.first() in the profile expression. That's safe here, because there's only oneSearch settings item.
  • Error 429 / quota: wait a minute and run again.
  • Scores feel random: sharpen the score description or your profile.

Goal: each job together with its score, and only the good matches.

The AI node only outputs the score and the reason. The job title and link are gone. That's no problem: n8n remembers which item came from where, so you can reach back to earlier steps and put everything together.

  1. Add an Edit Fields (Set) node. Rename itJob + score .
  2. Add six fields with Add Field , each with the same name as the field you drag in:
  • From Clean up jobs (scroll down in the left panel):title ,employer ,city ,link , all type String.
  • From Score with AI (insideoutput ):score with typeNumber , andreason with type String.
  1. From
  2. Click Execute step .

Checkpoint: five items with all six fields, and each job has its own title and score.

Stuck?

  • "Paired item" error here: run the whole workflow once withExecute workflow (bottom of the canvas), then try again. Don't use.first() here, or every job would get the first job's title.

Now the filter. This one is a plain rule, no AI: only jobs with a score of 7 or higher get through.

  1. Add a Filter node. Rename itGood matches only .
  2. Condition: dragscore > chooseNumber >is greater than or equal to >7
  3. Click Execute step .

Checkpoint: the output only has jobs with a score of 7 or more.

If nothing gets through, the workflow is working, there just wasn't a good match. For testing, lower the number to 5 so you have something to email.

Goal: one nicely formatted email with all matches, not one email per job.

n8n doesn't have a ready-made node for exactly this layout, so you use a Code node. You don't need to know how to code. You need to know how to ask.

A good code prompt has four parts: where the code runs, what goes in, what should come out, and how it should look.

Open ChatGPT, Claude or Gemini and paste this prompt:

I'm using n8n, the automation tool. Write JavaScript for a Code node
set to "Run Once for All Items".

Input: several items. Each item has these fields: title, employer,
city, link, score (a number from 1 to 10), reason.

Output: exactly ONE item with two fields:
- html: an HTML email listing all jobs, highest score first. For each
  job show the score, the title as a clickable link, the employer and
  city, and the reason in italics.
- count: how many jobs there are.

Keep the code short and simple, with comments explaining each part.

Notice that the prompt names the exact fields. The AI can't see your workflow, so you have to describe it.

  1. Add a Code node afterGood matches only . Rename itBuild email .
  2. Mode: Run Once for All Items.Language: JavaScript.
  3. Delete the example code and paste in the AI's code.
  4. Click Execute step .

Checkpoint: one single item with html and count.

If no job passes the filter, n8n simply stops before this node, so you never get an empty email.

Stuck?

  • The code throws an error: copy the error message back into the AI chat and ask it to fix the code. That's normal, even for developers.
  • It still doesn't work: use this reference version:
// Get all jobs that passed the filter
const jobs = $input.all().map(item => item.json);

// Best matches first
jobs.sort((a, b) => b.score - a.score);

// One list entry per job
const listItems = jobs.map(job => `
  <li style="margin-bottom:16px">
    <strong>${job.score}/10: <a href="${job.link}">${job.title}</a></strong><br>
    ${job.employer}, ${job.city}<br>
    <em>${job.reason}</em>
  </li>`).join('');

// Put the whole email together
const html = `
  <h2>Job radar: ${jobs.length} new ${jobs.length === 1 ? 'match' : 'matches'}</h2>
  <ul style="padding-left:18px">${listItems}</ul>
  <p style="color:#888">Sent by your n8n job radar</p>`;

// Return ONE item for the email node
return [{ json: { html, count: jobs.length } }];

Goal: the job radar email in your inbox.

Have your Gmail app password ready (see "Gmail app password, step by step").

Add the node

  1. On the canvas, click the + on the right side ofBuild email .
  2. In the search box, type Send Email and clickSend Email .
  3. If n8n asks which action you want, choose Send email . The node's settings panel opens.
  4. Click the node title at the top of the panel and rename it Send email .

Connect your Gmail (this is where the app password goes)

  1. At the top of the panel, find Credential to connect with . Click the dropdown and choose**+ Create new credential** .
  2. A new window opens, titled something like SMTP account . Fill it in:
Field What to enter
User your full Gmail address, e.g. alex.example@gmail.com
Password paste the app password here , exactly as Google shows it, including the spaces
Host smtp.gmail.com
Port 465
SSL/TLS switch on

Leave everything else (Disable STARTTLS, Client Host Name) as it is. 7. Click Save at the top right of the window. n8n tests the connection right away. 8. Look for a green Connection tested successfully. Red error? Check the "Stuck?" tips below. 9. Close the credential window with the X. Back in the node, the dropdown now shows your new credential.

Fill in the email

  1. From Email: your Gmail address
  2. To Email: your Gmail address (or any inbox you check)
  3. Subject: typeJob radar: , then dragcount from the left panel after it, then type new matches
  4. Email Format: HTML
  5. HTML: draghtml from the left panel
  6. Click Add option >Append n8n Attribution , and switch it off.
  7. Click Execute step .

Checkpoint: the email arrives within a minute. Check your spam folder if it doesn't.

Stuck?

  • "Invalid login" / "Username and Password not accepted": it has to be the app password, not your normal Gmail password. Paste it exactly as Google shows it, including the spaces, and check thatUser is the same Gmail account you created the app password in.
  • Can't create an app password: see "If it says 'The setting you are looking for is not available for your account'" in the Gmail section.

Goal: the workflow only lets through jobs it hasn't seen before.

Right now, if this runs every day, you'd get the same jobs again and again. So you give the workflow a memory: it notes every job ID it has seen and only lets new ones through.

  1. Hover over the line between Clean up jobs andLimit , click**+** , and searchRemove Duplicates . n8n shows three options. ChooseRemove items processed in previous executions . Rename the nodeRemember seen jobs .
  2. Check that Operation showsRemove Items Processed in Previous Executions .
  3. Keep Items Where: Value Is New
  4. Value to Dedupe On: dragjobId
  5. Click Execute workflow (bottom of the canvas) twice. Wait for the first run to finish before you start the second.

Checkpoint: on the second run, Remember seen jobs outputs 0 items, nothing after it runs, and no email is sent. That's exactly what you want: from now on, only new jobs get through.

Good to know: Remember seen jobs comes before Limit, so jobs cut off by the limit are also marked as seen and never scored. If you regularly get more new jobs per day than your limit, make your search more specific or raise the limit.

Stuck?

  • You want to test again with the same jobs: selectRemember seen jobs and pressD to deactivate it. PressD again before publishing.

Goal: the workflow runs by itself every morning.

You add a second trigger, a schedule. The manual trigger stays, so you can still test by hand.

  1. Click the + at the top right of the canvas, searchSchedule Trigger , and add it. Rename itEvery morning .
  2. Trigger Interval: Days.Days Between Triggers:1 .** Trigger at Hour:** 8am.Trigger at Minute:0 .
  3. Drag a line from the output dot of Every morning to the input ofSearch settings .
  4. Switch to daily mode:
  • In Search settings , changedaysBack to1 .
  • In Limit , changeMax Items to10 .
  • In Good matches only , set the number back to7 if you lowered it.
  • Pressed D onRemember seen jobs earlier? Press it again to switch it back on.
  1. In
  2. Click Publish (top right).

Checkpoint: the workflow shows as published.

Good to know:

  • Published means the workflow now runs on its own.
  • If you change anything later, click Publish again. Otherwise the schedule keeps using the old version.
  • Running locally has one catch: your laptop, Docker and the n8n terminal have to be on at 8 a.m. That's the price of free and private.
  • To check if it ran, open the Executions tab of your workflow.
  • To it, open the three-dot menu at the top right and unpublish.
Problem Fix
localhost:5678 doesn't load Is the terminal with n8n still open? Is Docker Desktop running?
Workflow gone after restart The start command needs the -v n8n_data:... part. Run exactly the command from Part 1.
HTTP Request: no ergebnisliste No results. Broaden the search: bigger radiusKm , moredaysBack , simplerjobTitle
Field missing (e.g. stellenangebotsTitel ) Check the actual field names in the Fetch jobs output and drag those instead
Can't find a field from an earlier node Scroll down in the left panel. Earlier nodes are listed further down. Run them first if they show no data.
"Paired item" error with Search settings Change .item to.first() in that expression
"Paired item" error in Job + score Run the whole workflow with Execute workflow. Don't use .first() there.
Gemini error 429 Free quota reached. Wait a minute, and keep Limit at 5–10
Nothing after the Filter No job scored 7 or more. Lower the number to test, or broaden the search
Email not arriving Check spam. A login error means the app password is wrong
Second test run sends nothing That's Remember seen jobs working. Press D on it to test again
Schedule ignores recent changes Changes only count after you publish again
Schedule didn't run Laptop asleep, Docker closed, or the n8n terminal was closed at 8 a.m. Check the Executions tab.
  1. Where does AI make a decision in this workflow, and where does it just follow rules?
  2. What would happen without the Remember seen jobs node?
  3. What are the limits of the AI pre-screening?
  4. Why run n8n locally instead of in the cloud? What are the pros and cons?
  • Several searches: duplicate the workflow with a different job title or city.
  • Better scoring: fetch each job's full description from the Arbeitsagentur details endpoint and give it to the AI. Hint: ask AI how to base64-encodejobId in an n8n expression. Test the details endpoint first, since the API changes without notice.
  • Weekly summary: add a second schedule that sends a Friday overview instead of daily emails.
── more in #ai-tools 4 stories Β· sorted by recency
── more on @n8n 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/job-radar-md] indexed:0 read:22min 2026-10-21 Β· β€”