You spend hours crafting the perfect resume. You tailor it to the job description. You hit submit with hope.
And then... silence.
Sound familiar? You're not alone. Studies show that 75% of resumes are rejected by ATS (Applicant Tracking Systems) before a human ever sees them. That's not a typo. Three out of four applications disappear into a digital void.
The worst part? Job seekers have no idea why. Was it the format? The keywords? The length? No feedback. Just another "application received" email that goes nowhere.
So I Built Smart Resume
Smart Resume is a free tool that analyzes your resume against any job description and tells you exactly what's wrong—and how to fix it.
Here's what it does:
Keyword Match Analysis — Extracts keywords from the job description and shows you which ones you're missing
Frequency Tracking — Tells you if a keyword appears too few or too many times
Action Verb Detection — Flags passive language that weakens your resume
Quantified Achievement Check — Reminds you to add numbers (increased sales by 20%, reduced load time by 50%)
Prioritized Suggestions — Not all fixes are equal. Get high/medium/low impact recommendations
ATS-Friendly Templates — 9 templates tested for ATS compatibility
How It Works Under the Hood
Tech Stack
Cloudflare Workers — Edge computing for fast, serverless API
Vue 3 — Lightweight, reactive frontend
No database required — All processing happens in real-time
The Keyword Extraction Pipeline
The core feature is extracting keywords from job descriptions and matching them against resumes. Here's how:
// Extract keywords from job description
function extractKeywords(text) {
// Remove common words
const stopWords = new Set(['the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for']);
// Tokenize and clean
const words = text.toLowerCase()
.replace(/[^\w\s]/g, '')
.split(/\s+/)
.filter(word => word.length > 2 && !stopWords.has(word));
// Count frequency
const frequency = {};
words.forEach(word => {
frequency[word] = (frequency[word] || 0) + 1;
});
// Return top keywords
return Object.entries(frequency)
.sort((a, b) => b[1] - a[1])
.slice(0, 30)
.map(([word, count]) => ({ word, count }));
}
Match Score Calculation
The match score isn't just about presence—it's about relevance and frequency:
function calculateMatchScore(resume, jobKeywords) {
const resumeLower = resume.toLowerCase();
let score = 0;
let maxScore = 0;
for (const { word, count } of jobKeywords) {
maxScore += count;
// Count occurrences in resume
const regex = new RegExp(word, 'gi');
const matches = resumeLower.match(regex);
const resumeCount = matches ? matches.length : 0;
// Reward presence, penalize absence
if (resumeCount > 0) {
// Bonus for matching or exceeding expected frequency
score += Math.min(resumeCount, count);
}
}
return Math.round((score / maxScore) * 100);
}
Why Cloudflare Workers?
I chose Cloudflare Workers for a few reasons:
No cold starts — Unlike Lambda, Workers are always warm
Global edge deployment — 300ms latency from anywhere
Generous free tier — 100,000 requests/day
No database needed — All processing is stateless
The entire app fits in a single Worker, which keeps costs at literally $0 for normal usage.
// worker.js - simplified routing
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname === '/api/scan') {
return handleScan(request, env);
}
if (url.pathname === '/api/templates') {
return handleTemplates(request);
}
return new Response(getHTML(), {
headers: { 'content-type': 'text/html' }
});
}
};
Lessons Learned
- ATS Systems Are Dumber Than You Think They're not looking for "magic keywords" in some secret algorithm. They're doing basic text matching with some synonym support. The "secret" is:
Use exact phrases from the job description
Don't overdo it (keyword stuffing triggers flags)
Standard section headings (Experience, Education, Skills)
Simple formatting (tables and columns confuse parsers)
Quantified Achievements Matter Most
The scanner now specifically looks for numbers in achievements. "Increased sales" is weak. "Increased sales by 35% in Q4" is strong. ATS systems weight these higher.Action Verbs Beat Passive Voice
Weak: "Was responsible for managing a team" Strong: "Led a team of 8 engineers"
The difference isn't just readability—it's how ATS systems score leadership potential.
What's Next
I'm working on:
AI-powered rewriting — Let GPT suggest better phrasings for bullet points
Cover letter generator — Match tone and keywords from job description
Bulk analysis — Scan your resume against 10 jobs at once
Browser extension — One-click scan from any job board
Try It Yourself
Head over to smart-resume-now.top and paste your resume + a job description. No signup required.
I'd love feedback from the dev community. What features would actually help you in your job search? What did I miss?
Built with ❤️ after watching too many talented friends get ghosted by ATS systems.
P.S. If this helped you land an interview, I'd love to hear about it!

Top comments (0)