Job Postings Scraper — Greenhouse, Lever, Ashby, Workable avatar

Job Postings Scraper — Greenhouse, Lever, Ashby, Workable

Pricing

Pay per usage

Go to Apify Store
Job Postings Scraper — Greenhouse, Lever, Ashby, Workable

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

Juan Carlos Gutiérrez Huérfano

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

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

ATSBoard URLBoard entry
Greenhouseboards.greenhouse.io/stripegreenhouse:stripe
Leverjobs.lever.co/leverdemolever:leverdemo
Ashbyjobs.ashbyhq.com/rampashby:ramp
Workableapply.workable.com/hospitableworkable:hospitable
SmartRecruitersjobs.smartrecruiters.com/Acmesmartrecruiters:Acme
Recruiteetether.recruitee.comrecruitee: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/annualizedMax so an hourly US rate and a monthly Colombian salary sort in the same column. Every band carries the exact rawText it came from, and a confidence of structured or parsed, 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 stays unknown rather than being guessed at.

  • LATAM eligibility flag. latamFriendly is 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 postedAfter with 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.
  • companyName is 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 install
npm run build
npm 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.