如何毋須無頭瀏覽器,監察任何公司的職位空缺:Workday、Greenhouse、Lever 等 11 種 ATS
How to monitor any company's job openings (Workday, Greenhouse, Lever & 8 more) without a headless browser
作者示範如何毋須使用無頭瀏覽器,透過 11 種 ATS 的公開資料介面監察多間公司的職位空缺,並統一資料格式。文中列出各系統端點和資料差異,例如 Workday 以 POST 分頁回傳職位,完整端點參考見 github.com/Mersetti/ats-job-board-apis。追蹤新增及關閉職位時,方法以首次執行作靜默基準,並只在公司資料擷取成功後才標記職位關閉。
Want a feed of new openings at a list of companies — for a niche job board, a recruiting pipeline, a hiring-trends dashboard
or just your own job hunt? You don't need Puppeteer. Almost every company publishes jobs through an applicant tracking
system (ATS), and every major ATS exposes a public, unauthenticated JSON feed for its career pages.
This post shows the endpoints, the gotchas I hit, and the small amount of code that turns 11 different formats into one.
Step 1: find out which ATS a company uses
Open the careers page and look at the links / embedded scripts:
| You see in the HTML | ATS |
|---|---|
boards.greenhouse.io/stripe |
Greenhouse |
jobs.lever.co/palantir |
Lever |
jobs.ashbyhq.com/openai |
Ashby |
nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite |
Workday |
apply.workable.com/huggingface |
Workable |
jobs.smartrecruiters.com/BoschGroup |
SmartRecruiters |
…plus Recruitee, Personio, Breezy HR, Teamtailor and Rippling. A regex per pattern over the page HTML detects
most companies automatically.
Step 2: call the public feed
The easy ones return everything in one request:
# Greenhouse (content=true adds descriptions)
curl "https://boards-api.greenhouse.io/v1/boards/stripe/jobs?content=true"
# Lever
curl "https://api.lever.co/v0/postings/palantir?mode=json"
# Ashby (with structured salary!)
curl "https://api.ashbyhq.com/posting-api/job-board/openai?includeCompensation=true"
Workday is the odd one: a POST with a JSON body, 20 jobs per page:
curl -X POST -H "Content-Type: application/json" \
-d '{"limit":20,"offset":0,"searchText":"engineer","appliedFacets":{}}' \
"https://nvidia.wd5.myworkdayjobs.com/wday/cxs/nvidia/NVIDIAExternalCareerSite/jobs"
Tip: use searchText — paging through 2,000 NVIDIA jobs to find 30 matching ones is slow; Workday's own search isn't.
Step 3: the gotchas
-
Greenhouse descriptions are double-encoded HTML (
<p>) — decode entities first, then strip tags. -
Workday dates are text:
Posted Today,Posted 3 Days Ago,Posted 30+ Days Ago. The detail endpoint has the realstartDate.locationsTextmay literally be"2 Locations". -
Workday
totalis only correct on the first page. -
Recruitee dates look like
2026-10-13 10:58:56 UTC— not ISO. -
Personio returns XML, and some companies live on
.jobs.personio.cominstead of.de. - SmartRecruiters and Rippling need one detail call per job for descriptions (Rippling even for the date).
-
Teamtailor usually runs on a custom domain —
/jobs.rsson the careers domain gives you everything.
Step 4: normalize
Map every source into one shape:
{
company, ats, jobId, title, department, location, locations, country,
remote, workplaceType, employmentType, postedAt, salary, descriptionText, applyUrl
}
Salary deserves a note: only Ashby, Lever, Recruitee and Rippling have structured pay. For the rest, US postings
usually state a range in the text, and one regex catches most of them:
const m = /([$€£])\s?(\d{1,3}(?:,\d{3})*|\d+)\s?([kK])?\s?(?:-|–|to)\s?[$€£]?\s?(\d{1,3}(?:,\d{3})*|\d+)\s?([kK])?/.exec(text);
Reject yearly ranges under 10,000 so "$1,000–$2,000 signing bonus" doesn't become a salary. In my tests this finds
pay for roughly half of all jobs.
Step 5: only new jobs
Keep a map of ats:company:jobId → firstSeenAt. Each run:
- job not in the map → new
- job in the map but gone now → closed, but only if that company's fetch succeeded (otherwise one timeout looks like a mass closure)
- make the very first run a silent baseline, so your "new jobs" feed doesn't start with 3,000 items.
Run it daily on a schedule and you have a new-jobs feed for any list of companies.
Full endpoint reference
I documented all 11 endpoints, fields and quirks here:
👉 github.com/Mersetti/ats-job-board-apis
Don't want to maintain it?
I packaged all of the above — 11 ATS, auto-detection from careers URLs, salary extraction, filters and new/closed
monitoring — as an Apify Actor: Career Sites Jobs Feed. Pay per job,
schedule it, export to CSV/Sheets or call it from an AI agent.
Which ATS should I add next? Let me know in the comments.
來源:DEV Community · dev.to