Skip to content
Rehan.dev

AI Automation · Browser Extension · Job Automation

SeamlessApply

AI-Powered Bulk Job Application Platform

Built a full-stack AI-powered job application automation platform that scrapes jobs from Indeed, LinkedIn, Workday, and Remote — then uses GPT-4 to auto-fill application forms, generate personalized cover emails, and apply to hundreds of jobs on autopilot. Includes a Chrome extension, cron automation, and an admin dashboard.

Role
Solo Full-Stack Developer
Year
2025
Type
Full-Stack SaaS · AI Integration · Browser Extension · Job Automation
60+
API endpoints
12+
UI pages
12
Database models
6
External integrations

Quick summary

Job seekers create "Seam" campaigns — defining job title, location, experience level, and target boards — and the system automatically scrapes matching jobs from Indeed, LinkedIn, Workday, and Remote. GPT-4 fills application forms, generates personalized cover-letter emails, and the system applies to jobs automatically via a daily cron job or through a Chrome extension installed on the user's browser.

The problem

Job searching at scale is painful:

  • Manually searching 4+ job boards wastes hours daily
  • Every application form asks the same questions, typed from scratch each time
  • Writing a unique cover letter per company is time-consuming
  • Most people apply to too few jobs because the process is exhausting
  • No way to track which jobs you've already applied to

The goal: build a platform that finds jobs, fills forms, writes emails, and applies automatically — while the user is asleep.

My role

Solo full-stack developer, end-to-end ownership: product architecture and database design, UI/UX and frontend (12+ pages), backend API (60+ endpoints), a separate Chrome Extension build, third-party integrations (OpenAI, Apify, GCS, AWS S3, Google Maps, Nodemailer), the authentication system, cron automation, and production deployment.

Core concept: the "Seam"

The central entity is the Seam — a job search campaign. Each seam stores a job title, location and radius, job type, experience level, target boards (Indeed, LinkedIn, Workday, Remote, or all), an uploaded resume (parsed via GPT-4 from a GCS-stored PDF), settings (excluded companies/keywords, auto-apply toggle, AI answering toggle), and a personalized email template. Users can run multiple active seams simultaneously.

What was built

  1. Seam Management — create/update/delete seams; resume upload to GCS with GPT-4 text extraction.
  2. Job Scraping & Results — Apify-triggered multi-board scraping into a ScrapedJob table; filterable, paginated results (18/page); polling detects criteria changes and prompts a refresh.
  3. AI Form Filling — the Chrome extension detects form fields on a job site, sends them to /api/ai-fill-fields, and GPT-4 returns field-specific answers, with a regex fallback if parsing fails.
  4. Indeed Q&A Learning System — the extension detects Indeed application questions; unseen questions get an AI-generated answer the user confirms once, then every future occurrence of that field is pre-filled instantly with no AI call.
  5. Auto-Apply via Email — per-seam email templates with variable placeholders; company-email lookup (cached first, API fallback); strict deduplication so no company is ever emailed twice per seam.
  6. Cron Automation — a daily unattended run (max 5-minute execution) processes every seam with auto-send enabled, applying the same match logic as the UI, with per-seam error isolation.
  7. AI Email Template Generator — GPT generates a full template from job title, experience, and a formality preference (formal / semi-formal / casual).
  8. CV/Resume Extraction — PDF upload to GCS, then GPT-4 Vision parses it into structured data (name, skills, experience, education) used to personalize form answers.
  9. Authentication — NextAuth.js for the web app; a separate JWT path (stored in localStorage) for the Chrome extension, since extensions can't use httpOnly cookies across origins.
  10. Admin Panel — user stats, subscriber growth and jobs-matched charts, client management, role-gated routes.

Core features — technical deep dive

Shared job-matching logic. The isJobMatch() function lives in one shared module (utils/job-matching.ts) and is imported by both the frontend results page and the cron auto-apply job — so the same criteria (excluded companies/keywords, board, location) are applied identically everywhere, and a fix in one place fixes both paths at once.

Dual authentication for a cross-origin extension. The web app uses NextAuth sessions (httpOnly cookies), which don't work across the extension's different origin. The extension instead authenticates against /api/auth/login, receives a JWT, stores it in extension storage, and sends it as an Authorization: Bearer header — extension-facing endpoints extract and verify that token manually. Both paths hit the same database and the same endpoints.

Application deduplication across manual and automated paths. Every apply attempt — whether the user clicks Apply manually or the cron job fires — checks JobApplication for an existing record for that job/seam pair first. The table is the single source of truth, so a job never gets a duplicate application regardless of which path triggered it.

Indeed Q&A matching on field ID, not question text. Indeed sometimes renders the same question with slightly different wording, so matching is done on the DOM's fieldId (which is consistent for a given question type) instead of the label text, with a @@unique([userId, fieldId]) constraint enforcing one saved answer per field per user.

Cron job resilience at scale. maxDuration = 300, a 1-second delay between individual sends and between seams, and a try/catch wrapped around each seam individually — one seam's failure never stops the rest from processing.

// /api/cron-auto-apply — simplified
for (const seam of seamsWithAutoSend) {
  try {
    const jobs = await prisma.scrapedJob.findMany({
      where: { seamId: String(seam.id), createdAt: { gte: oneWeekAgo } },
    });
    const unapplied = jobs.filter((j) => !appliedIds.has(j.id));
    const matched = unapplied.filter((job) => isJobMatch(job, seamData));

    for (const job of matched) {
      const email = await findCompanyEmail(job.company, job.location);
      if (email) await sendApplicationEmail(job, seam.id, email, template, user);
      await sleep(1000);
    }
  } catch (error) {
    ErrorTracker.trackError(error, "CRON_AUTO_APPLY_API", { seamId: seam.id });
  }
}

Database schema (key models)

  • User — auth, role
  • JobSubmission (the "Seam") — search criteria, resume text, board targets
  • SeamSettings — auto-send/auto-fill/AI-answering toggles, match threshold, exclusion lists
  • ScrapedJob — one row per scraped listing, tagged by source board
  • JobApplication — application record with status (applied/interviewed/rejected/offered)
  • EmailTemplate — formal/semi-formal/casual templates per seam
  • IndeedQuestion — learned Q&A pairs, unique per user + field
  • CompanyEmail — cached/discovered company email addresses

Key numbers

MetricValue
Job boards integrated4 (Indeed, LinkedIn, Workday, Remote)
API endpoints60+
UI pages12+
Database models12
AI integrationsOpenAI GPT-4 + GPT-3.5
External integrations6 (OpenAI, Apify, GCS, AWS S3, Nodemailer, Google Maps)

What this demonstrates

  • API integration expertise — 6 third-party APIs integrated with proper auth, pagination, rate-limit, and error handling for each; a dual GCS/S3 storage strategy.
  • AI/LLM product building — three distinct AI use cases (form filling, Q&A answering, CV parsing) with caching and fallback pipelines for unpredictable GPT output.
  • Browser extension development — a Manifest V3 extension in React/TypeScript/Vite with cross-origin API communication and DOM-level form automation on third-party sites.
  • Production-level backend — shared business logic between frontend and backend, structured logging and error tracking, cron automation with isolation, rate limiting, and deduplication.

SeamlessApply — job application automation platform. Built end-to-end as a solo developer.