Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ATS Jobs Scraper — Greenhouse, Lever, Ashby, SmartRecruiters & Workday

Run on Apify License: MIT Python 3.12+

Free. Scrape job postings straight from a company's own careers page, in seconds. No login, no proxies, no headless browser.

Most job scrapers go through job boards, which means stale listings, missing roles and rate limits. This one talks directly to the applicant tracking system (ATS) behind the careers page — the original source, updated the moment a recruiter posts a job.

Paste a career page URL or a company name. It works out which ATS the company uses and returns the jobs.

pip install -r requirements.txt
apify run

Supported platforms

ATS Coverage Example input
Greenhouse Full, incl. descriptions greenhouse:stripe or https://boards.greenhouse.io/stripe
Lever Full, incl. descriptions https://jobs.lever.co/spotify
Ashby Titles, locations, type https://jobs.ashbyhq.com/ramp
SmartRecruiters Full, incl. departments smartrecruiters:Visa
Workday Full (needs the complete URL) https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite

These are the companies' own public job board APIs. No proxies, no browser, no blocking — so a run costs almost nothing, and the Actor is free to use.

The endpoints, if you'd rather roll your own

Everything here is a plain HTTP request. No key, no login.

import requests

# Greenhouse — one GET, add ?content=true for full descriptions
requests.get("https://boards-api.greenhouse.io/v1/boards/stripe/jobs?content=true").json()["jobs"]

# Lever — descriptionPlain gives clean text, no HTML stripping
requests.get("https://api.lever.co/v0/postings/spotify?mode=json").json()

# SmartRecruiters — paginated, 100 per page
requests.get("https://api.smartrecruiters.com/v1/companies/Visa/postings?limit=100").json()["content"]

# Workday — POST, and limit CANNOT exceed 20 (higher returns an empty array, not an error)
requests.post(
    "https://nvidia.wd5.myworkdayjobs.com/wday/cxs/nvidia/NVIDIAExternalCareerSite/jobs",
    json={"appliedFacets": {}, "limit": 20, "offset": 0, "searchText": ""},
).json()["jobPostings"]

Ashby uses an unauthenticated GraphQL POST — see src/main.py for the query.

Three Workday traps

  1. limit above 20 returns an empty array, not an error. It looks exactly like "no more results."
  2. It throttles fast paging. If your loop treats a failed page as the end of the list, you'll silently collect a fraction of the jobs. This cost us 1,960 of NVIDIA's 2,000 jobs before we noticed. Pause between pages and retry a failed one.
  3. The URL parts aren't guessable. The tenant, datacenter (wd5) and site name all come from the company's real careers URL.

What you get for each job

  • Job title, company, location
  • Department and employment type, where the ATS provides them
  • Posted date, normalized across all five platforms
  • Seniority level and job function, inferred from the title
  • Direct apply link
  • Full description text (optional; Greenhouse and Lever)
{
  "company": "Careem",
  "ats": "greenhouse",
  "title": "Account Manager I",
  "location": "Dubai, United Arab Emirates",
  "department": "Commercial",
  "employmentType": null,
  "postedDate": "2026-06-24",
  "seniorityGuess": "Mid-Senior level",
  "functionGuess": "Sales",
  "url": "https://boards.greenhouse.io/careem/jobs/1234567"
}

Top Gulf employers, ready to run

The default input is a curated list of sought-after employers hiring in the UAE and Saudi Arabia. Every slug was checked against the live ATS, so you get real jobs on the first run.

Company Where Input
Aldar Properties Abu Dhabi lever:aldar
Careem Dubai greenhouse:careem
Tamara Dubai, Riyadh greenhouse:tamara
Masdar Abu Dhabi smartrecruiters:masdar
Deliveroo Dubai ashby:deliveroo
Fresha Riyadh, Dubai lever:fresha
Lean Technologies Riyadh ashby:leantech
Kitopi Dubai lever:kitopi

Add "locationFilter": "Dubai" (or Riyadh, Abu Dhabi, Remote) to narrow any run.

Most big employers aren't reachable. Of 42 top Gulf companies we checked, only 7 run a modern ATS. Emirates Group, ADNOC, Emaar, Majid Al Futtaim, Qatar Airways, DP World, Emirates NBD and Aramco all use Taleo, Oracle Cloud, Phenom or custom portals, none of which publish a public job API. For those, use the GCC Jobs Aggregator instead, which reaches them via Bayt, GulfTalent and NaukriGulf.

Input

Field Description
companies Career page URLs, company slugs, or ats:slug to force a platform
titleFilter Only keep jobs whose title contains this text
locationFilter Only keep jobs whose location contains this text
includeDescription Fetch the full description for each job
maxJobsPerCompany Cap results per company. 0 means no limit

Mix formats freely:

{
  "companies": [
    "greenhouse:stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/ramp",
    "smartrecruiters:Visa"
  ],
  "locationFilter": "Remote"
}

Use it with Claude or ChatGPT

Every Apify Actor is exposed over MCP, so you can wire this into Claude Desktop, Claude Code or any MCP client and ask: "what engineering roles are open at Stripe and Ramp right now?" It also has a REST API and works with LangChain, n8n, Make and Zapier.

Lessons from building it

Two bugs that shipped before we caught them, both from naive substring matching on job titles:

  • "coo" in title.lower() classified "Coordinator" as a chief operating officer.
  • "partner" in title.lower() promoted "Partner Onboarding Specialist" to firm partner.

Also: "Assistant Vice President" is not an executive — in Gulf banking and real estate it's an upper-mid individual contributor title. Use word boundaries, and print the raw titles behind every bucket before you trust an aggregate.

Some sites also fingerprint your TLS handshake, not just the User-Agent. When a site 403s a plain requests call but loads fine in Chrome, curl_cffi with impersonate="chrome" fixes it. (None of the five ATS platforms above need this — but the Gulf job boards do.)

Be a good citizen

These endpoints are public because companies want their jobs discovered. Cache aggressively, pause between requests, and don't hammer a small company's board. The reason this works without keys is that nobody has had to lock it down yet.

Related

License

MIT — see LICENSE.

About

Free scraper for Greenhouse, Lever, Ashby, SmartRecruiters and Workday job boards. Reads jobs straight from company career pages. No login, no proxies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages