How to Monitor Competitor Job Postings to Predict Their Strategy
Job postings are the most honest signal of a competitor's roadmap. Track their ATS boards automatically and turn hiring data into strategy.
The actor referenced in this article. Pay only for results delivered.
A competitor cannot hide their hiring. The moment they open a role on Greenhouse, Lever, Ashby or Workday, the posting is public. If you know where to look, and you automate the looking, you get a 6-to-12-month preview of their product roadmap, new market bets, and technology decisions, all before they announce anything.
TL;DR: Monitor competitor job postings using public ATS job boards (Greenhouse, Lever, Ashby and Workday, no authentication required) to predict strategy: new engineering roles reveal product direction, first sales hire in a region signals market entry, unfamiliar tech stacks mean platform shifts. Automate weekly collection with the ATS Jobs scraper, pipe results to Claude for interpretation, and get a Monday morning briefing on what every competitor is building.
This is not a new insight. CB Insights, investors, and growth teams have used job posting intelligence for years. What has changed is that you can now automate the entire pipeline: collection, interpretation, and alerting, in an afternoon.
Why Job Postings Are the Best Competitive Signal
Most competitive intelligence is lagged. Press releases describe decisions already made. Earnings calls describe results already booked. Blog posts describe features already shipped.
Job postings are leading. A company must hire before they can build. The average time from job posting to new hire to meaningful output is 6 to 12 months. When you see a pattern in their postings, you are looking at their roadmap, not their past.
Specific signals job postings reliably encode:
Product direction: A web-first company posting five iOS engineers is building a native app. A company posting “ML Platform Engineer” (not “ML Research Engineer”) is productionizing AI, not experimenting with it.
Market entry: The first sales hire in a new geography is the most reliable signal of geographic expansion. Companies do not hire salespeople in markets they are not serious about.
Technology decisions: The tech stack in a job description reflects actual infrastructure, not marketing copy. “Experience with ClickHouse and Flink” tells you more about their data architecture than their entire engineering blog.
Organizational structure: Whether they post individual contributor roles or manager roles in a function reveals whether they are scaling a team or building a new one from scratch.
Acquisition interest: A company that posts deep expertise requirements in a niche area they have never mentioned may be building toward an acquisition target, or building to compete with one.
The Data Source: Public ATS APIs
Greenhouse, Lever, and Ashby all expose public-facing job board APIs that require zero authentication. Every company using these ATSs is broadcasting their open roles to anyone who calls the right endpoint. Workday, which a lot of larger companies run, publishes a public board too, though each customer sits on its own tenant URL rather than a guessable slug.
Going to the ATS board directly also beats watching LinkedIn or Indeed. Those sites copy listings after the fact and can trail the company’s own board by a day or more. The ATS board changes the moment a recruiter hits publish, and it carries the full description rather than a trimmed copy.
# Direct API calls, no API key, no auth
# Greenhouse: https://boards-api.greenhouse.io/v1/boards/{slug}/jobs
# Lever: https://api.lever.co/v0/postings/{slug}
# Ashby: https://api.ashbyhq.com/posting-api/job-board/{slug}
# Workday: https://{tenant}.wd{N}.myworkdayjobs.com/{site} (no guessable slug)
The ATS Jobs scraper wraps all four platforms in a single normalized call, handles pagination, and returns clean structured JSON: same schema regardless of which ATS the target company uses.
Setting Up the Monitoring Pipeline
Step 1: Build Your Target Company List
Identify which ATS each competitor uses. The easiest way is to look at their careers page URL:
greenhouse.ioin the URL → Greenhouse slug is the subdomainlever.coin the URL → Lever slug is the path segmentashbyhq.comin the URL → Ashby slug is the path segmentmyworkdayjobs.comin the URL → Workday, and you need the whole careers URL, because the tenant and datacentre number (wd1,wd5and so on) cannot be derived from the company name
COMPETITORS = {
"greenhouse": [
"stripe", "linear", "notion", "figma", "vercel",
],
"lever": [
"planetscale", "turso", "neon",
],
"ashby": [
"loom", "coda", "retool",
],
"workday": [
"https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
],
}
Step 2: Collect and Store Postings
from apify_client import ApifyClient
import json
import hashlib
from pathlib import Path
from datetime import datetime
apify = ApifyClient("YOUR_APIFY_TOKEN")
SEEN_FILE = Path("seen_postings.json")
def load_seen() -> set:
if SEEN_FILE.exists():
return set(json.loads(SEEN_FILE.read_text()))
return set()
def save_seen(seen: set):
SEEN_FILE.write_text(json.dumps(list(seen)))
def job_id(job: dict) -> str:
key = f"{job.get('_company')}-{job.get('title')}-{job.get('location', '')}"
return hashlib.md5(key.encode()).hexdigest()
def collect_new_postings(competitors: dict) -> list[dict]:
seen = load_seen()
new_jobs = []
for platform, slugs in competitors.items():
for slug in slugs:
run = apify.actor("themineworks/ats-jobs").call(run_input={
"boards": [{"ats": platform, "slug": slug}],
"maxJobsPerCompany": 100,
"includeDescription": True,
})
for job in apify.dataset(run["defaultDatasetId"]).iterate_items():
job["_company"] = slug
job["_platform"] = platform
jid = job_id(job)
if jid not in seen:
job["_first_seen"] = datetime.utcnow().isoformat()
new_jobs.append(job)
seen.add(jid)
save_seen(seen)
return new_jobs
For Workday entries, _company will be the careers URL, so map it to a readable name before the brief goes out. Workday rows also come back without a department, because Workday’s public board does not publish one; for those companies the titles and descriptions carry the signal.
Step 3: Interpret With Claude
Raw job postings are useful. Interpreted job postings are intelligence. Claude can read a batch of new postings and surface what they signal, not just list them.
import anthropic
import os
claude = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
def interpret_new_postings(new_jobs: list[dict]) -> str:
if not new_jobs:
return "No new postings this week."
# Build company summaries
by_company = {}
for job in new_jobs:
company = job["_company"]
if company not in by_company:
by_company[company] = []
by_company[company].append({
"title": job.get("title"),
"department": job.get("department"),
"location": job.get("location"),
"description_excerpt": (job.get("description") or "")[:400],
})
response = claude.messages.create(
model="claude-sonnet-4-6",
max_tokens=2000,
messages=[{
"role": "user",
"content": f"""You are a competitive intelligence analyst. Analyze these new job postings from the past week.
NEW POSTINGS BY COMPANY:
{json.dumps(by_company, indent=2)}
Write a Monday morning competitive intelligence brief covering:
1. MOST SIGNIFICANT SIGNALS: What are the 3 most important things these postings tell us about competitor direction? Be specific: "Company X is building Y because they posted Z roles."
2. COMPANY-BY-COMPANY SUMMARY: For each company with new postings, one paragraph: what are they hiring for, what does it suggest about their roadmap?
3. PATTERNS ACROSS COMPANIES: Are multiple competitors hiring in the same area? That signals an industry-wide shift worth noting.
4. WHAT TO WATCH: Which companies or role types should we track most closely next week?
Be specific and analytical. "They're hiring engineers" is not useful. "They posted 4 ML Platform roles and 2 data infrastructure roles but zero ML Research roles, which suggests they are productionizing an existing capability rather than building a new one" is useful."""
}]
)
return response.content[0].text
Step 4: Schedule and Alert
import schedule
import time
def weekly_competitive_brief():
print("Collecting new job postings...")
new_jobs = collect_new_postings(COMPETITORS)
print(f"Found {len(new_jobs)} new postings")
brief = interpret_new_postings(new_jobs)
# Save locally
filename = f"competitive_brief_{datetime.now().strftime('%Y_%m_%d')}.md"
with open(filename, "w") as f:
f.write(f"# Competitive Intelligence Brief, {datetime.now().strftime('%B %d, %Y')}\n\n")
f.write(f"**New postings analyzed:** {len(new_jobs)}\n\n")
f.write(brief)
print(f"Brief saved to {filename}")
print("\n" + "="*60 + "\n")
print(brief)
# Run every Monday at 8am
schedule.every().monday.at("08:00").do(weekly_competitive_brief)
while True:
schedule.run_pending()
time.sleep(60)
The Signals That Matter Most
Not all job postings carry equal intelligence value. These are the patterns worth watching closely:
First hire in a function: The first data engineer, the first compliance officer, the first sales hire in a new city. First hires signal new bets. Tenth hires in a function signal scale, which is less interesting for strategy.
Role titles that don’t exist yet: If a competitor posts “Agentic Infrastructure Engineer” or “AI Reliability Engineer,” they are naming a discipline that does not have standard terminology. They are inventing their organizational model in real time.
Senior versus junior mix: A company posting all Staff and Principal engineers and no mid-level engineers is either burning out, scaling fast, or building a new team from scratch. Any of these is worth understanding.
Location and remote signals: A company that was fully remote suddenly posting office-required roles in a specific city may be making a strategic partnership or acquisition that requires physical presence.
Volume spikes: A company that normally posts 5 roles per month suddenly posting 20 is in an expansion phase. A company that drops from 20 to 0 has either hit a hiring freeze or a structural problem.
Who Else Reads Hiring Data
Competitive intelligence is the most common use of this feed, but other teams pull the same data for different reasons.
Investors watch open roles at portfolio companies and at private comparables, where there is no filing to read. A steady rise in engineering openings points to growth, and a sudden drop in open roles usually means a freeze, often months before anyone says so.
Talent teams pull descriptions for the same role from competitor boards before writing their own. It shows which skills and experience ranges the market asks for, and in places where pay transparency laws apply, the salary bands competitors disclose.
Staffing recruiters use it to build target lists. A recruiter who places mid-market sales roles can pull every open Account Executive and Sales Manager posting across a couple of hundred company boards in one run.
Researchers use the structured output to study which skills employers ask for and how requirements shift over time, and niche job boards (fintech engineering, climate tech, biotech research) are built by aggregating boards from a curated company list. The ATS aggregation guide covers that build.
What Job Postings Will Not Show You
ATS boards only list the roles a company chose to advertise. Internal transfers, retained executive searches and roles filled through referrals before they were ever posted do not appear, so a quiet board does not always mean a quiet hiring team. Some companies also keep their Workday board behind an employee login, and those cannot be read from outside. Treat it as a signal of intent. It will not give you a full headcount plan.
Real Example: What Competitor Job Postings Revealed
A growth team at a Series B developer tools company tracked their top three competitors weekly. Signals they caught before public announcements:
-
One competitor posted 6 “Enterprise Sales Engineer” roles across New York, London, and Singapore in a single month, despite being primarily self-serve. This preceded their enterprise tier launch by 8 months.
-
Another competitor’s engineering job descriptions shifted from mentioning PostgreSQL to mentioning ClickHouse and Apache Iceberg across multiple roles over a 6-week period. This signaled a data infrastructure rewrite before any engineering blog post.
-
A third competitor posted “Head of Partnerships: Systems Integrators” with a description explicitly mentioning “SAP, Salesforce, and ServiceNow ecosystem.” Their integration marketplace launched 9 months later.
None of these signals required inside information. They were in public job postings, visible to anyone who was reading.
Frequently Asked Questions
Is it legal to scrape public ATS job boards?
Yes. Greenhouse, Lever, and Ashby job boards are explicitly public-facing APIs with no authentication requirement. The data is intended to be publicly accessible for job seekers. The hiQ v. LinkedIn ruling (9th Circuit) confirmed that scraping publicly accessible data does not violate the Computer Fraud and Abuse Act. Avoid storing personal employee data, and use the data for research and analysis rather than automated mass outreach.
How often should I run the collection to catch new postings quickly?
Daily collection is sufficient for most competitive intelligence purposes. Most strategic signals emerge from patterns over weeks, not hours. If you are in a fast-moving competitive situation, twice-daily collection is reasonable. Avoid running more frequently than necessary: it creates noise and wastes compute.
How many companies can I effectively monitor at once?
The practical limit is determined by signal-to-noise ratio, not technical constraints. Monitoring 50 companies produces so many postings that patterns get lost. Most effective competitive intelligence programs track 10 to 20 carefully selected companies, the ones where hiring signals are most relevant to your own strategy.
What if a competitor uses Workday or another enterprise ATS?
The ATS Jobs scraper covers Greenhouse, Lever, Ashby and Workday. Workday needs the company’s full careers URL (for example https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite) passed in boards, because there is no slug to guess, and its rows carry no department field. Companies on iCIMS, SuccessFactors or a custom careers page are outside these four systems and need a different scraping approach. A practical fallback is to watch their LinkedIn company page job postings, which pull from every ATS.
How do I separate signal from routine backfill hiring?
Establish a baseline. After 4 to 6 weeks of collection, you will know each company’s typical posting volume by department and role type. Deviations from baseline, more than 2x volume in any category, new role types that haven’t appeared before, sudden geographic expansion, are the signals worth investigating. Claude’s pattern analysis does this automatically when you provide historical context alongside new postings.
Explore the scraper referenced in this article: inputs, outputs, and pricing, then run it on Apify.
Building a Job Market Intelligence Dashboard with Free ATS Data
How to build a real-time hiring dashboard that tracks roles, skills demand, and company hiring velocity using public Greenhouse, Lever, and Ashby APIs.
Recruitment Automation: Building a Job Intelligence Pipeline with Free ATS Data
How to use the public Greenhouse, Lever and Ashby APIs to build automated job monitoring and salary benchmarking for recruiting teams.
I Automated My AI Job Hunt: 8 Tools, One Claude Agent, Under $1
Most job hunting is spent on the wrong problem. Here is the exact end-to-end flow: find who is actually hiring, rank by real fit, research the company, find the human, and write an application grounded in facts, run entirely from Claude via MCP.
How to Aggregate Job Postings from 500+ Companies Using Public ATS APIs
Greenhouse, Lever and Ashby expose public job board APIs with no auth. Build one aggregator that pulls from all three, dedupes, and flags new roles.