Job Postings Scraper — Greenhouse, Lever, Ashby, Workable
Pricing
Pay per usage
Job Postings Scraper — Greenhouse, Lever, Ashby, Workable
Scrape jobs from company career pages across 6 ATS platforms — Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee — into one schema. Salary ranges parsed and annualized, remote/hybrid/onsite detection, LATAM eligibility flag, delta feed. No personal data.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
Juan Carlos Gutiérrez Huérfano
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Job Postings Scraper — Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee
Pulls open roles straight from companies' own applicant tracking systems and returns one clean schema across all six, with salary bands parsed into comparable annual figures and an eligibility flag for Latin America.
No personal data is collected or emitted — job postings only.
Supported sources
| ATS | Board URL | Board entry |
|---|---|---|
| Greenhouse | boards.greenhouse.io/stripe | greenhouse:stripe |
| Lever | jobs.lever.co/leverdemo | lever:leverdemo |
| Ashby | jobs.ashbyhq.com/ramp | ashby:ramp |
| Workable | apply.workable.com/hospitable | workable:hospitable |
| SmartRecruiters | jobs.smartrecruiters.com/Acme | smartrecruiters:Acme |
| Recruitee | tether.recruitee.com | recruitee:tether |
Why this exists
Every ATS already publishes its job board as a public JSON endpoint. The hard part was never fetching it; it's that each one names things differently, buries compensation in free prose, and describes location in a dozen incompatible ways. Existing scrapers hand you the raw payload and leave the normalization to you.
This one does the normalization:
-
Salary parsed and annualized. Structured fields when the ATS provides them, otherwise parsed from the description — English, Spanish and Portuguese, multi-currency, with
annualizedMin/annualizedMaxso an hourly US rate and a monthly Colombian salary sort in the same column. Every band carries the exactrawTextit came from, and aconfidenceofstructuredorparsed, so you can audit or discard. -
Work mode classified as
remote/hybrid/onsite/unknown— reading the title and body, not just the location string. "Hybrid remote" resolves to hybrid, and a named city with no remote signal resolves to onsite; a bare country staysunknownrather than being guessed at. -
LATAM eligibility flag.
latamFriendlyis true when the role sits in a Latin American country or is remote with a scope that includes the region — "Remote - LATAM", "Americas", "must overlap GMT-5", "work from anywhere". US-built job scrapers treat those strings as noise; if you hire in the region, that flag is the product.It is deliberately conservative. A role anchored to a non-LATAM country and not marked remote is never flagged, no matter what the description says — a US-based role whose body mentions "our business in the Americas" is a business-scope mention, not a hiring signal, and treating it as one would make the flag worthless.
-
Language detection (
es/pt/en) on the posting body. -
Delta feed. Pass
postedAfterwith your previous run's timestamp and get only what's new, instead of re-pulling every board in full.
Input
{"boards": ["greenhouse:stripe","lever:leverdemo","ashby:ramp","workable:hospitable","smartrecruiters:smartrecruiters","recruitee:tether"],"postedAfter": "2026-07-01T00:00:00Z","latamOnly": true,"withSalaryOnly": false,"workMode": ["remote"],"titleIncludes": ["backend", "platform"],"maxItems": 0,"descriptionMaxChars": 5000}
The slug is whatever appears in the board's public URL — see the table above. Only
boards is required; every filter is optional.
Output
One record per posting:
{"id": "greenhouse:stripe:7967890","source": "greenhouse","companySlug": "stripe","companyName": "Stripe","title": "Consumer Operations Associate","url": "https://stripe.com/jobs/search?gh_jid=7967890","locationRaw": "Mexico City","countryCode": "MX","latamFriendly": true,"workMode": "onsite","department": "Operations","employmentType": "Full-time","postedAt": "2026-07-22T15:16:54-04:00","updatedAt": "2026-07-27T11:17:30-04:00","salary": {"min": 120000,"max": 160000,"currency": "USD","period": "year","annualizedMin": 120000,"annualizedMax": 160000,"rawText": "$120,000 - $160,000","confidence": "parsed"},"language": "en","description": "...","scrapedAt": "2026-07-31T18:00:00Z"}
id is stable across runs, so you can upsert on it.
A RUN_SUMMARY record is written to the key-value store with per-board failures,
postings scanned vs emitted, and the filters applied — so a run that returns fewer
rows than you expected tells you why.
Reliability
These are documented public JSON endpoints with no authentication and no anti-bot
layer, so there is nothing here that silently degrades when a site ships a redesign.
Requests retry three times with exponential backoff; a 404 is treated as a permanent
"no such board" rather than retried. Boards are fetched five at a time — enough to be
fast, not enough to be rude. One failing board does not sink the run; all boards failing
does, loudly.
A typical run across six boards reads well over a thousand postings in about ten seconds.
What this does not do
- No personal data. No recruiter or hiring-manager names, no contact details, no applicant information. This is a deliberate design constraint, not an oversight.
- No authenticated scraping and no credential sharing.
- No aggregator sites. It reads each company's own board directly, which is why the data is first-hand and the uptime is the ATS's rather than a middleman's.
companyNameis null on Lever. Lever's public postings API does not expose the company's display name, and inventing one from the slug would be a guess. The other five sources return it when the ATS publishes it.
Local development
npm installnpm run buildnpm run test:local # offline assertions + live endpoint probe
test:local checks the salary parser and the location, work-mode and LATAM classifiers
against fixtures without needing network — including a regression test for the
"business in the Americas" false positive — then probes the six live endpoints and
reports how many postings each returned.
Issues
Found a bad parse, or want a field in a different shape? Open an issue on the Actor. Include the board entry and the posting URL and it is usually a quick fix.