DEV Community

Alex Chen
Alex Chen

Posted on

I Automated My Job Search and Here's What Happened

I Automated My Job Search and Here's What Happened

As a developer looking for freelance work, I got tired of manually checking 20+ job boards every day. So I built a system to do it for me.

The Problem

I'm a solo developer who does:

  • Freelance writing ($80-$150/article)
  • Web development ($500-$3000/project)
  • Automation consulting ($75/hour)

Finding clients means checking:

  • Reddit (r/slavelance, r/forhire, r/hireawriter)
  • Twitter (search queries)
  • Dev.to (job board)
  • LinkedIn (if I had premium)
  • Various Slack/Discord communities
  • Cold email outreach lists

Time spent daily: 2-3 hours just LOOKING for work.

That's not sustainable. I needed automation.

The System I Built

Architecture

┌─────────────────────────────────────┐
│         Job Aggregator Bot           │
│                                     │
│  ┌──────────┐   ┌────────────────┐ │
│  │ Sources  │   │  Parser &      │ │
│  │          │──▶│  Normalizer    │ │
│  │ • Reddit │   │                │ │
│  │ • Twitter│   │  → Title       │ │
│  │ • Dev.to │   │  → Company     │ │
│  │ • RSS    │   │  → Pay range   │ │
│  └──────────┘   │  → Tags        │ │
│                 └───────┬────────┘ │
│                         │          │
│                 ┌───────▼────────┐ │
│                 │  Scoring Engine│ │
│                 │  (relevance ×  │ │
│                 │   pay × recency)│ │
│                 └───────┬────────┘ │
│                         │          │
│              ┌──────────┼────────┐ │
│              ▼          ▼        ▼ │
│         [Top 10]   [Log File] [Alert]│
└─────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Step 1: Data Collection

Reddit (the hardest part):

// Reddit blocks server IPs, so I use RSS bridges
const REDDIT_RSS = [
  'https://rsslounge.com/r/slavelance/.rss',
  'https://rsslounge.com/r/forhire/.rss',
  'https://rsslounge.com/r/hireawriter/.rss',
];

async function fetchRedditJobs() {
  const jobs = [];
  for (const url of REDDIT_RSS) {
    const feed = await parseRSS(url);
    feed.items.forEach(item => {
      jobs.push({
        source: 'reddit',
        title: item.title,
        url: item.link,
        published: new Date(item.pubDate),
        // Extract pay from title if mentioned
        pay: extractPay(item.title),
      });
    });
  }
  return jobs;
}
Enter fullscreen mode Exit fullscreen mode

Pro tip: Reddit's official API requires OAuth. RSS bridges are a workaround but can be unreliable. The most reliable method? Check Reddit via browser automation during off-peak hours.

Dev.to (much easier):

// Dev.to has a public API, no auth needed for reading
const DEVTO_API = 'https://dev.to/api/articles?tag=hiring&per_page=20';

async function fetchDevToJobs() {
  const res = await fetch(DEVTO_API);
  const articles = await res.json();
  return articles.map(a => ({
    source: 'devto',
    title: a.title,
    url: a.url,
    published: a.published_at,
    tags: a.tag_list,
  }));
}
Enter fullscreen mode Exit fullscreen mode

RSS Feeds (the most reliable):

// Many job boards publish RSS feeds
const RSS_SOURCES = {
  'RemoteOK': 'https://remoteok.com/remote-jobs.rss',
  'HackerNews': 'https://hnrss.org/frontpage?points=100', // filter by points
  'StackOverflow': 'https://stackoverflow.com/jobs/feed',
};
Enter fullscreen mode Exit fullscreen mode

Step 2: Scoring & Ranking

Not all gigs are worth my time. I score each opportunity:

function scoreJob(job) {
  let score = 0;

  // Relevance to my skills (0-40)
  const mySkills = ['nodejs', 'python', 'react', 'writing', 'automation'];
  const jobText = (job.title + ' ' + (job.tags || '')).toLowerCase();
  mySkills.forEach(skill => {
    if (jobText.includes(skill)) score += 8;
  });

  // Pay estimate (0-30)
  if (job.pay >= 100) score += 30;      // Good pay
  else if (job.pay >= 50) score += 20;  // Decent
  else if (job.pay > 0) score += 10;    // Low but exists

  // Recency (0-20)
  const hoursOld = (Date.now() - new Date(job.published).getTime()) / 3600000;
  if (hoursOld < 2) score += 20;
  else if (hoursOld < 6) score += 15;
  else if (hoursOld < 24) score += 10;
  else if (hoursOld < 48) score += 5;

  // Quality signals (0-10)
  if (job.title.includes('senior')) score += 3;
  if (!job.title.includes('entry') && !job.title.includes('junior')) score += 2;
  if (job.source === 'devto') score += 3; // Usually higher quality

  return Math.min(score, 100); // Cap at 100
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Delivery

Daily digest email:

async function sendDigest(topJobs) {
  const body = topJobs.map((job, i) => 
    `${i+1}. **${job.title}** (${job.score}/100)\n` +
    `   ${job.url}\n` +
    `   Posted ${getRelativeTime(job.published)}\n` +
    `   Source: ${job.source}${job.pay ? ' | ~$' + job.pay : ''}`
  ).join('\n\n');

  await resend.emails.send({
    from: 'Job Bot <noreply@agentvote.cc>',
    to: 'contact@agentvote.cc',
    subject: `${topJobs.length} relevant gigs found — ${new Date().toLocaleDateString()}`,
    html: markdownToHtml(body),
  });
}
Enter fullscreen mode Exit fullscreen mode

Instant alerts for high-value opportunities:

// If something scores >80, alert immediately
if (job.score > 80) {
  await sendUrgentAlert(`🔥 HOT GIG: ${job.title}\n${job.url}`);
}
Enter fullscreen mode Exit fullscreen mode

The Results After 30 Days

Numbers:

Metric Before After
Time spent searching/day 2-3 hours 15 minutes
Applications sent/week 3-5 12-15
Response rate 8% 22%
Jobs found total ~20/week ~80/week (after filtering: ~10 good ones)
Clients landed 0-1/month 2/month

What Changed:

1. Volume → Selectivity
Before automation: I applied to everything because finding gigs was hard.
After automation: I only apply to scored >60 gigs because I know more will come tomorrow.

2. Speed = Advantage
The #1 predictor of getting hired is HOW FAST you apply.

  • Manual: See gig → think about it → draft response → apply (2-4 hours later)
  • Automated: See gig → alert → apply immediately (within minutes)

I've gotten responses saying "Wow, fast response!" multiple times. Speed signals enthusiasm.

3. Consistency
Some days I don't feel like job hunting. The bot doesn't care. It runs every morning at 7 AM regardless.

What It Can't Do (Yet)

  1. Write custom cover letters — I still do this myself
  2. Assess if a client is legit — Some postings are scams
  3. Negotiate rates — Still a human skill
  4. Follow up — Working on automated follow-up sequences

The Code

The full system is about 400 lines of Node.js:

  • 150 lines: Data collection (RSS, APIs, scraping)
  • 100 lines: Scoring engine
  • 80 lines: Email delivery
  • 70 lines: Scheduling and logging

Runs as a cron job every 6 hours. Costs $0 to operate (uses free tiers of everything).

Setup Your Own

If you want to build something similar:

  1. Start with ONE source (RSS is easiest)
  2. Add simple keyword filtering (regex match against your skills)
  3. Email yourself the results (Resend free tier = 3000 emails/month)
  4. Iterate: Add sources, improve scoring, add alerts

Don't build the perfect system first. Build a janky one that works, then improve it.


Are you still manually scrolling through job boards? Stop. Automate the boring stuff so you can focus on what actually gets you paid: doing great work.

Follow @armorbreak for more developer productivity content.

Top comments (0)