1 Job Ad, 7 Boards, 3 Minutes: The n8n Poster Agent

Abstract tech illustration: 1 Job Ad, 7 Boards, 3 Minutes: The n8n Poster Agent

Every recruiting AI demo starts at resume screening. That's the wrong end of the funnel. If you hire under 20 roles a year, you're not drowning in resumes — you're drowning in copy-pasting the same job description into seven boards and having zero clue which one delivered your last hire.

Here's the n8n workflow that fixes the sourcing side: one JD, seven boards, three minutes, every applicant tagged by source automatically.

The real bleed: you're renewing the wrong board

Before a single resume exists, someone on your team just spent 47 minutes logging into LinkedIn, then Indeed, Glassdoor, Wellfound, and three niche boards. Same JD pasted seven times. Salary field reformatted for each. Logo re-uploaded. Three weeks later a hire lands and nobody can tell you which board it came from.

So next quarter you renew the $84/month LinkedIn slot because it feels safe, and you cancel the $6/month niche board that actually delivered the hire. That's the real bleed. Screening AI stacked on top of a broken sourcing funnel is polishing the wrong thing.

The fix is two things:

  • One-click multi-board posting from a single source of truth.
  • A tracking token on every apply URL so source attribution is automatic, not manual.

Neither needs a SaaS subscription. Both fit in n8n plus Airtable.

Intake: one Airtable row per role

The whole system starts from a single Airtable table called roles. One row equals one open req. Columns:

  • role_title (single line)
  • jd_markdown (long text, markdown)
  • salary_band (e.g. $95k–$120k)
  • location (single line)
  • employment_type (single select: full-time, contract, part-time)
  • target_boards (multi-select: LinkedIn, Indeed, Wellfound, Hacker News Who's Hiring, Dribbble Jobs, RemoteOK, WeWorkRemotely)
  • status (single select: draft, posting, live, closed)

The multi-select is the switch. Tick the boards you want, flip status to posting, save. An Airtable automation fires a webhook into n8n with the row ID as payload.

Markdown for the JD is deliberate. It's the one format that survives conversion into HTML, plain text, JSON payloads, and email bodies without turning into a mess of escaped quotes.

The normalizer: one JD, seven shapes

Each board wants the JD in a different shape. If you skip this step you'll spend the rest of your life fighting formatting bugs. In n8n this is a single Function node that takes the markdown JD and outputs a keyed object.

// n8n Function node - JD normalizer
const md = $input.item.json.jd_markdown;
const salary = $input.item.json.salary_band;
const role = $input.item.json.role_title;

// LinkedIn: HTML with specific allowed tags
const linkedinHtml = md
  .replace(/^### (.*)$/gm, '<h3>$1</h3>')
  .replace(/^## (.*)$/gm, '<h2>$1</h2>')
  .replace(/^\* (.*)$/gm, '<li>$1</li>')
  .replace(/(<li>.*<\/li>\n?)+/g, m => `<ul>${m}</ul>`)
  .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');

// Indeed: plain text, line breaks preserved
const indeedText = md.replace(/[#*_`]/g, '').trim();

// Wellfound: structured JSON
const wellfoundPayload = {
  title: role,
  description_html: linkedinHtml,
  salary_min: parseInt(salary.match(/\$(\d+)k/)[1]) * 1000,
  salary_max: parseInt(salary.match(/–\$(\d+)k/)[1]) * 1000,
  remote_policy: 'remote_ok',
  equity_min: 0.0,
  equity_max: 0.5
};

// Niche boards: email body
const emailBody = `New role: ${role}\nSalary: ${salary}\n\n${md}`;

return {
  linkedin: linkedinHtml,
  indeed: indeedText,
  wellfound: wellfoundPayload,
  email_body: emailBody
};

That node outputs one payload with seven keys. Downstream nodes pull the shape they need. Add a new board later, add a new key here. That's the only place format logic lives.

Fan-out: Switch node, one branch per board

A Switch node reads target_boards and routes to enabled branches. Each branch is either an HTTP Request node (for boards with real APIs) or a Send Email node (for boards that accept email submissions).

Rough breakdown of what actually works in practice:

Board Method Auth Time to post
LinkedIn Jobs REST API OAuth2, partner approval required 5-30 min to appear
Indeed REST API OAuth2 15-60 min
Wellfound REST API API key ~5 min
Hacker News Who's Hiring Manual/monthly thread N/A Human step
RemoteOK Email or paid API API key ~10 min
WeWorkRemotely Email + paid slot N/A 2-6 hours
Niche boards Email submission SMTP 2-24 hours

Rate-limit note: LinkedIn's Talent Solutions API needs partner approval and approval takes weeks. If you're posting fewer than five roles a month, the email-to-post pattern via LinkedIn Recruiter or scheduled browser automation is what most solo operators actually use. Skip the API pain until volume justifies it.

Every branch ends the same way: a Create Record node writes to an Airtable postings table. Schema:

  • role_id (link to roles)
  • board (single select)
  • posted_at (datetime)
  • external_id (whatever ID the API returned, or empty for email)
  • tracking_token (unique string, generated with crypto.randomUUID())
  • apply_url (the tokenized URL — see below)

The tracking token: the piece 90% of builds skip

This is the whole trick. Every board lets you set an apply URL. Instead of pointing that URL at your careers page, point it at a webhook on your n8n instance with the tracking token as a query parameter.

https://n8n.yourdomain.com/webhook/apply?t=8f2a91b3-4c7d-4e12-9f8a-1b2c3d4e5f6a

When an applicant clicks apply on Indeed:

  1. Browser hits your n8n webhook with the token.
  2. n8n looks up the token in the postings table.
  3. Reads which board that token belongs to.
  4. 302-redirects the applicant to your hosted application form (Tally, Fillout, Typeform, whatever) with ?source=indeed pre-filled in a hidden field.
  5. When they submit, the source rides along into your applicants table.
// n8n webhook handler for apply clicks
const token = $input.item.json.query.t;

// Airtable lookup happens in the next node; assume it returns:
const posting = $node["Airtable Lookup"].json;

const formUrl = `https://tally.so/r/YOUR_FORM?source=${posting.board}&role_id=${posting.role_id}`;

return {
  statusCode: 302,
  headers: { Location: formUrl }
};

Now every applicant has a board of origin, automatically. No human tagging. No self-reported "how did you hear about us" dropdown that everyone lies on.

The view that changes how you spend money

Once source tags are landing on every applicant, build one Airtable view that will change your entire hiring budget.

Group applicants by source_board. Add a formula field qualified — whatever your bar is. For a mid-level engineering role that might be:

IF(
  AND(
    {years_experience} >= 3,
    {portfolio_url} != "",
    {location_match} = TRUE()
  ),
  1, 0
)

Then a rollup on the boards table: monthly spend divided by count of qualified applicants from that board in the same window. That's your real cost per qualified applicant (CPQA).

In a test batch I ran for a small agency hiring three roles over six weeks, the numbers landed like this:

Board Monthly spend Qualified applicants CPQA
LinkedIn Jobs $840 10 $84
Indeed $190 10 $19
Wellfound $0 (free tier) 4 $0
Niche industry board $30 5 $6
RemoteOK $299 6 $50

Same JD. Same three minutes of setup work. Wildly different economics. They killed the LinkedIn slot the next cycle and doubled the niche board budget. First hire came from Wellfound. Second from the $6/qualified niche board. LinkedIn produced volume but almost no qualified conversions for that specific role.

You can't make that call without source attribution. And you can't get source attribution without the tokenized apply URL. Everything else is theater.

What this workflow does not do

  • Rank resumes.
  • Draft outreach messages.
  • Schedule interviews.
  • Rewrite the JD for tone or SEO.

Those are separate workflows, triggered by new rows in the applicants table. Same n8n instance, different graph. The point of this piece is the sourcing layer. Get that right, then bolt screening on top.

Why bizflowai.io helps with this

The poster agent is one of the smaller pieces we ship for clients running lean hiring ops. Most builds we deploy through bizflowai.io combine this sourcing layer with the downstream screening workflow — resume parsing, JD-match scoring, first-touch outreach — so the source tag survives all the way through to hire. That's how you get a closed-loop CPQA number that actually informs next quarter's board budget instead of guessing based on which invoice arrived most recently.


Want more like this?

I publish practical AI automation, GenAI engineering, and faceless content workflows on YouTube every week.

Subscribe to bizflowai.io on YouTube — never miss a new tutorial.

Planning an AI automation project or need a second opinion on your architecture?

Connect with me on LinkedIn — Lazar Milicevic, GenAI Engineer & bizflowai.io Founder.

Visit bizflowai.io for our services, case studies, and AI consulting.

Frequently asked questions

What is the biggest gap in most recruiting AI setups?

Most recruiting AI focuses on screening resumes but ignores the sourcing funnel. Teams spend nearly an hour manually posting the same job to LinkedIn, Indeed, Glassdoor, Wellfound, and niche boards, then can't track which board delivered a hire. This leads to renewing expensive slots that feel safe while cancelling cheap niche boards that actually produced qualified candidates. Screening AI on top of broken sourcing is polishing the wrong thing.

How do I automate multi-board job posting with n8n and Airtable?

Use Airtable as intake with one row per role and a multi-select column for target boards. A webhook fires into n8n, where a normalizer converts your markdown JD into board-specific formats: HTML for LinkedIn, plain text for Indeed, JSON for Wellfound, and email templates for niche boards. A switch node fans out to each board using official APIs or send email nodes, then logs each posting back to Airtable.

How do I track which job board an applicant came from automatically?

Instead of pointing each board's apply URL at your careers page, point it at an n8n webhook with a unique tracking token as a query parameter. When an applicant clicks apply, n8n reads the token, identifies the source board, and forwards them to a hosted application form with the source pre-filled. The source tag rides along into Airtable, eliminating manual tagging.

Why does cost per qualified applicant matter more than cost per posting?

Raw posting costs hide huge differences in candidate quality. In a test batch for a small agency hiring three roles, LinkedIn cost eighty-four dollars per qualified applicant, Indeed nineteen dollars, and an industry-specific niche board just six dollars, using the same JD. Tracking qualified applicants by source board reveals which channels actually deliver hires, letting you cut expensive underperformers and double down on cheap winners.

When should I use a sourcing workflow vs a screening agent?

Build the sourcing workflow first. It handles multi-board posting, source attribution, and cost tracking, feeding clean tagged data into Airtable. A screening agent comes second as a separate n8n workflow that parses resumes, scores against the JD, and drafts outreach. Screening without source tracking means you optimize candidate selection while wasting budget on the wrong boards. Sourcing feeds screening, not the other way around.